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