1*2d9fd380Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606 * Copyright 2019 Mellanox Technologies, Ltd
3*2d9fd380Sjfb8856606 */
4*2d9fd380Sjfb8856606
5*2d9fd380Sjfb8856606 #ifndef _GNU_SOURCE
6*2d9fd380Sjfb8856606 #define _GNU_SOURCE
7*2d9fd380Sjfb8856606 #endif
8*2d9fd380Sjfb8856606
9*2d9fd380Sjfb8856606 #include <sys/types.h>
10*2d9fd380Sjfb8856606 #include <sys/socket.h>
11*2d9fd380Sjfb8856606 #include <sys/un.h>
12*2d9fd380Sjfb8856606 #include <fcntl.h>
13*2d9fd380Sjfb8856606 #include <stdio.h>
14*2d9fd380Sjfb8856606 #include <unistd.h>
15*2d9fd380Sjfb8856606 #include <sys/stat.h>
16*2d9fd380Sjfb8856606
17*2d9fd380Sjfb8856606 #include "rte_eal.h"
18*2d9fd380Sjfb8856606 #include "mlx5_utils.h"
19*2d9fd380Sjfb8856606 #include "mlx5.h"
20*2d9fd380Sjfb8856606
21*2d9fd380Sjfb8856606 /* PMD socket service for tools. */
22*2d9fd380Sjfb8856606
23*2d9fd380Sjfb8856606 #define MLX5_SOCKET_PATH "/var/tmp/dpdk_net_mlx5_%d"
24*2d9fd380Sjfb8856606
25*2d9fd380Sjfb8856606 int server_socket; /* Unix socket for primary process. */
26*2d9fd380Sjfb8856606 struct rte_intr_handle server_intr_handle; /* Interrupt handler. */
27*2d9fd380Sjfb8856606
28*2d9fd380Sjfb8856606 /**
29*2d9fd380Sjfb8856606 * Handle server pmd socket interrupts.
30*2d9fd380Sjfb8856606 */
31*2d9fd380Sjfb8856606 static void
mlx5_pmd_socket_handle(void * cb __rte_unused)32*2d9fd380Sjfb8856606 mlx5_pmd_socket_handle(void *cb __rte_unused)
33*2d9fd380Sjfb8856606 {
34*2d9fd380Sjfb8856606 int conn_sock;
35*2d9fd380Sjfb8856606 int ret;
36*2d9fd380Sjfb8856606 struct cmsghdr *cmsg = NULL;
37*2d9fd380Sjfb8856606 int data;
38*2d9fd380Sjfb8856606 char buf[CMSG_SPACE(sizeof(int))] = { 0 };
39*2d9fd380Sjfb8856606 struct iovec io = {
40*2d9fd380Sjfb8856606 .iov_base = &data,
41*2d9fd380Sjfb8856606 .iov_len = sizeof(data),
42*2d9fd380Sjfb8856606 };
43*2d9fd380Sjfb8856606 struct msghdr msg = {
44*2d9fd380Sjfb8856606 .msg_iov = &io,
45*2d9fd380Sjfb8856606 .msg_iovlen = 1,
46*2d9fd380Sjfb8856606 .msg_control = buf,
47*2d9fd380Sjfb8856606 .msg_controllen = sizeof(buf),
48*2d9fd380Sjfb8856606 };
49*2d9fd380Sjfb8856606 uint16_t port_id;
50*2d9fd380Sjfb8856606 int fd;
51*2d9fd380Sjfb8856606 FILE *file = NULL;
52*2d9fd380Sjfb8856606 struct rte_eth_dev *dev;
53*2d9fd380Sjfb8856606
54*2d9fd380Sjfb8856606 /* Accept the connection from the client. */
55*2d9fd380Sjfb8856606 conn_sock = accept(server_socket, NULL, NULL);
56*2d9fd380Sjfb8856606 if (conn_sock < 0) {
57*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "connection failed: %s", strerror(errno));
58*2d9fd380Sjfb8856606 return;
59*2d9fd380Sjfb8856606 }
60*2d9fd380Sjfb8856606 ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
61*2d9fd380Sjfb8856606 if (ret < 0) {
62*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "wrong message received: %s",
63*2d9fd380Sjfb8856606 strerror(errno));
64*2d9fd380Sjfb8856606 goto error;
65*2d9fd380Sjfb8856606 }
66*2d9fd380Sjfb8856606 /* Receive file descriptor. */
67*2d9fd380Sjfb8856606 cmsg = CMSG_FIRSTHDR(&msg);
68*2d9fd380Sjfb8856606 if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS ||
69*2d9fd380Sjfb8856606 cmsg->cmsg_len < sizeof(int)) {
70*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "invalid file descriptor message");
71*2d9fd380Sjfb8856606 goto error;
72*2d9fd380Sjfb8856606 }
73*2d9fd380Sjfb8856606 memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
74*2d9fd380Sjfb8856606 file = fdopen(fd, "w");
75*2d9fd380Sjfb8856606 if (!file) {
76*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "Failed to open file");
77*2d9fd380Sjfb8856606 goto error;
78*2d9fd380Sjfb8856606 }
79*2d9fd380Sjfb8856606 /* Receive port number. */
80*2d9fd380Sjfb8856606 if (msg.msg_iovlen != 1 || msg.msg_iov->iov_len < sizeof(uint16_t)) {
81*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "wrong port number message");
82*2d9fd380Sjfb8856606 goto error;
83*2d9fd380Sjfb8856606 }
84*2d9fd380Sjfb8856606 memcpy(&port_id, msg.msg_iov->iov_base, sizeof(port_id));
85*2d9fd380Sjfb8856606 if (!rte_eth_dev_is_valid_port(port_id)) {
86*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "Invalid port %u", port_id);
87*2d9fd380Sjfb8856606 goto error;
88*2d9fd380Sjfb8856606 }
89*2d9fd380Sjfb8856606 /* Dump flow. */
90*2d9fd380Sjfb8856606 dev = &rte_eth_devices[port_id];
91*2d9fd380Sjfb8856606 ret = mlx5_flow_dev_dump(dev, file, NULL);
92*2d9fd380Sjfb8856606 /* Set-up the ancillary data and reply. */
93*2d9fd380Sjfb8856606 msg.msg_controllen = 0;
94*2d9fd380Sjfb8856606 msg.msg_control = NULL;
95*2d9fd380Sjfb8856606 msg.msg_iovlen = 1;
96*2d9fd380Sjfb8856606 msg.msg_iov = &io;
97*2d9fd380Sjfb8856606 data = -ret;
98*2d9fd380Sjfb8856606 io.iov_len = sizeof(data);
99*2d9fd380Sjfb8856606 io.iov_base = &data;
100*2d9fd380Sjfb8856606 do {
101*2d9fd380Sjfb8856606 ret = sendmsg(conn_sock, &msg, 0);
102*2d9fd380Sjfb8856606 } while (ret < 0 && errno == EINTR);
103*2d9fd380Sjfb8856606 if (ret < 0)
104*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "failed to send response %s",
105*2d9fd380Sjfb8856606 strerror(errno));
106*2d9fd380Sjfb8856606 error:
107*2d9fd380Sjfb8856606 if (conn_sock >= 0)
108*2d9fd380Sjfb8856606 close(conn_sock);
109*2d9fd380Sjfb8856606 if (file)
110*2d9fd380Sjfb8856606 fclose(file);
111*2d9fd380Sjfb8856606 }
112*2d9fd380Sjfb8856606
113*2d9fd380Sjfb8856606 /**
114*2d9fd380Sjfb8856606 * Install interrupt handler.
115*2d9fd380Sjfb8856606 *
116*2d9fd380Sjfb8856606 * @param dev
117*2d9fd380Sjfb8856606 * Pointer to Ethernet device.
118*2d9fd380Sjfb8856606 * @return
119*2d9fd380Sjfb8856606 * 0 on success, a negative errno value otherwise.
120*2d9fd380Sjfb8856606 */
121*2d9fd380Sjfb8856606 static int
mlx5_pmd_interrupt_handler_install(void)122*2d9fd380Sjfb8856606 mlx5_pmd_interrupt_handler_install(void)
123*2d9fd380Sjfb8856606 {
124*2d9fd380Sjfb8856606 MLX5_ASSERT(server_socket);
125*2d9fd380Sjfb8856606 server_intr_handle.fd = server_socket;
126*2d9fd380Sjfb8856606 server_intr_handle.type = RTE_INTR_HANDLE_EXT;
127*2d9fd380Sjfb8856606 return rte_intr_callback_register(&server_intr_handle,
128*2d9fd380Sjfb8856606 mlx5_pmd_socket_handle, NULL);
129*2d9fd380Sjfb8856606 }
130*2d9fd380Sjfb8856606
131*2d9fd380Sjfb8856606 /**
132*2d9fd380Sjfb8856606 * Uninstall interrupt handler.
133*2d9fd380Sjfb8856606 */
134*2d9fd380Sjfb8856606 static void
mlx5_pmd_interrupt_handler_uninstall(void)135*2d9fd380Sjfb8856606 mlx5_pmd_interrupt_handler_uninstall(void)
136*2d9fd380Sjfb8856606 {
137*2d9fd380Sjfb8856606 if (server_socket) {
138*2d9fd380Sjfb8856606 mlx5_intr_callback_unregister(&server_intr_handle,
139*2d9fd380Sjfb8856606 mlx5_pmd_socket_handle,
140*2d9fd380Sjfb8856606 NULL);
141*2d9fd380Sjfb8856606 }
142*2d9fd380Sjfb8856606 server_intr_handle.fd = 0;
143*2d9fd380Sjfb8856606 server_intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
144*2d9fd380Sjfb8856606 }
145*2d9fd380Sjfb8856606
146*2d9fd380Sjfb8856606 /**
147*2d9fd380Sjfb8856606 * Initialise the socket to communicate with the secondary process
148*2d9fd380Sjfb8856606 *
149*2d9fd380Sjfb8856606 * @param[in] dev
150*2d9fd380Sjfb8856606 * Pointer to Ethernet device.
151*2d9fd380Sjfb8856606 *
152*2d9fd380Sjfb8856606 * @return
153*2d9fd380Sjfb8856606 * 0 on success, a negative value otherwise.
154*2d9fd380Sjfb8856606 */
155*2d9fd380Sjfb8856606 int
mlx5_pmd_socket_init(void)156*2d9fd380Sjfb8856606 mlx5_pmd_socket_init(void)
157*2d9fd380Sjfb8856606 {
158*2d9fd380Sjfb8856606 struct sockaddr_un sun = {
159*2d9fd380Sjfb8856606 .sun_family = AF_UNIX,
160*2d9fd380Sjfb8856606 };
161*2d9fd380Sjfb8856606 int ret;
162*2d9fd380Sjfb8856606 int flags;
163*2d9fd380Sjfb8856606
164*2d9fd380Sjfb8856606 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
165*2d9fd380Sjfb8856606 if (server_socket)
166*2d9fd380Sjfb8856606 return 0;
167*2d9fd380Sjfb8856606 /*
168*2d9fd380Sjfb8856606 * Initialize the socket to communicate with the secondary
169*2d9fd380Sjfb8856606 * process.
170*2d9fd380Sjfb8856606 */
171*2d9fd380Sjfb8856606 ret = socket(AF_UNIX, SOCK_STREAM, 0);
172*2d9fd380Sjfb8856606 if (ret < 0) {
173*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "Failed to open mlx5 socket: %s",
174*2d9fd380Sjfb8856606 strerror(errno));
175*2d9fd380Sjfb8856606 goto error;
176*2d9fd380Sjfb8856606 }
177*2d9fd380Sjfb8856606 server_socket = ret;
178*2d9fd380Sjfb8856606 flags = fcntl(server_socket, F_GETFL, 0);
179*2d9fd380Sjfb8856606 if (flags == -1)
180*2d9fd380Sjfb8856606 goto error;
181*2d9fd380Sjfb8856606 ret = fcntl(server_socket, F_SETFL, flags | O_NONBLOCK);
182*2d9fd380Sjfb8856606 if (ret < 0)
183*2d9fd380Sjfb8856606 goto error;
184*2d9fd380Sjfb8856606 snprintf(sun.sun_path, sizeof(sun.sun_path), MLX5_SOCKET_PATH,
185*2d9fd380Sjfb8856606 getpid());
186*2d9fd380Sjfb8856606 remove(sun.sun_path);
187*2d9fd380Sjfb8856606 ret = bind(server_socket, (const struct sockaddr *)&sun, sizeof(sun));
188*2d9fd380Sjfb8856606 if (ret < 0) {
189*2d9fd380Sjfb8856606 DRV_LOG(WARNING,
190*2d9fd380Sjfb8856606 "cannot bind mlx5 socket: %s", strerror(errno));
191*2d9fd380Sjfb8856606 goto close;
192*2d9fd380Sjfb8856606 }
193*2d9fd380Sjfb8856606 ret = listen(server_socket, 0);
194*2d9fd380Sjfb8856606 if (ret < 0) {
195*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "cannot listen on mlx5 socket: %s",
196*2d9fd380Sjfb8856606 strerror(errno));
197*2d9fd380Sjfb8856606 goto close;
198*2d9fd380Sjfb8856606 }
199*2d9fd380Sjfb8856606 if (mlx5_pmd_interrupt_handler_install()) {
200*2d9fd380Sjfb8856606 DRV_LOG(WARNING, "cannot register interrupt handler for mlx5 socket: %s",
201*2d9fd380Sjfb8856606 strerror(errno));
202*2d9fd380Sjfb8856606 goto close;
203*2d9fd380Sjfb8856606 }
204*2d9fd380Sjfb8856606 return 0;
205*2d9fd380Sjfb8856606 close:
206*2d9fd380Sjfb8856606 remove(sun.sun_path);
207*2d9fd380Sjfb8856606 error:
208*2d9fd380Sjfb8856606 claim_zero(close(server_socket));
209*2d9fd380Sjfb8856606 server_socket = 0;
210*2d9fd380Sjfb8856606 DRV_LOG(ERR, "Cannot initialize socket: %s", strerror(errno));
211*2d9fd380Sjfb8856606 return -errno;
212*2d9fd380Sjfb8856606 }
213*2d9fd380Sjfb8856606
214*2d9fd380Sjfb8856606 /**
215*2d9fd380Sjfb8856606 * Un-Initialize the pmd socket
216*2d9fd380Sjfb8856606 */
RTE_FINI(mlx5_pmd_socket_uninit)217*2d9fd380Sjfb8856606 RTE_FINI(mlx5_pmd_socket_uninit)
218*2d9fd380Sjfb8856606 {
219*2d9fd380Sjfb8856606 if (!server_socket)
220*2d9fd380Sjfb8856606 return;
221*2d9fd380Sjfb8856606 mlx5_pmd_interrupt_handler_uninstall();
222*2d9fd380Sjfb8856606 claim_zero(close(server_socket));
223*2d9fd380Sjfb8856606 server_socket = 0;
224*2d9fd380Sjfb8856606 MKSTR(path, MLX5_SOCKET_PATH, getpid());
225*2d9fd380Sjfb8856606 claim_zero(remove(path));
226*2d9fd380Sjfb8856606 }
227