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