net/mlx5: use dynamic logging
[dpdk.git] / drivers / net / mlx5 / mlx5_socket.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016 6WIND S.A.
3  */
4
5 #define _GNU_SOURCE
6
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <sys/stat.h>
14
15 #include "mlx5.h"
16 #include "mlx5_utils.h"
17
18 /**
19  * Initialise the socket to communicate with the secondary process
20  *
21  * @param[in] dev
22  *   Pointer to Ethernet device.
23  *
24  * @return
25  *   0 on success, a negative errno value otherwise and rte_errno is set.
26  */
27 int
28 mlx5_socket_init(struct rte_eth_dev *dev)
29 {
30         struct priv *priv = dev->data->dev_private;
31         struct sockaddr_un sun = {
32                 .sun_family = AF_UNIX,
33         };
34         int ret;
35         int flags;
36         struct stat file_stat;
37
38         /*
39          * Initialise the socket to communicate with the secondary
40          * process.
41          */
42         ret = socket(AF_UNIX, SOCK_STREAM, 0);
43         if (ret < 0) {
44                 rte_errno = errno;
45                 DRV_LOG(WARNING, "port %u secondary process not supported: %s",
46                         dev->data->port_id, strerror(errno));
47                 goto error;
48         }
49         priv->primary_socket = ret;
50         flags = fcntl(priv->primary_socket, F_GETFL, 0);
51         if (flags == -1) {
52                 rte_errno = errno;
53                 goto error;
54         }
55         ret = fcntl(priv->primary_socket, F_SETFL, flags | O_NONBLOCK);
56         if (ret < 0) {
57                 rte_errno = errno;
58                 goto error;
59         }
60         snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
61                  MLX5_DRIVER_NAME, priv->primary_socket);
62         ret = stat(sun.sun_path, &file_stat);
63         if (!ret)
64                 claim_zero(remove(sun.sun_path));
65         ret = bind(priv->primary_socket, (const struct sockaddr *)&sun,
66                    sizeof(sun));
67         if (ret < 0) {
68                 rte_errno = errno;
69                 DRV_LOG(WARNING,
70                         "port %u cannot bind socket, secondary process not"
71                         " supported: %s",
72                         dev->data->port_id, strerror(errno));
73                 goto close;
74         }
75         ret = listen(priv->primary_socket, 0);
76         if (ret < 0) {
77                 rte_errno = errno;
78                 DRV_LOG(WARNING, "port %u secondary process not supported: %s",
79                         dev->data->port_id, strerror(errno));
80                 goto close;
81         }
82         return 0;
83 close:
84         remove(sun.sun_path);
85 error:
86         claim_zero(close(priv->primary_socket));
87         priv->primary_socket = 0;
88         return -rte_errno;
89 }
90
91 /**
92  * Un-Initialise the socket to communicate with the secondary process
93  *
94  * @param[in] dev
95  */
96 void
97 mlx5_socket_uninit(struct rte_eth_dev *dev)
98 {
99         struct priv *priv = dev->data->dev_private;
100
101         MKSTR(path, "/var/tmp/%s_%d", MLX5_DRIVER_NAME, priv->primary_socket);
102         claim_zero(close(priv->primary_socket));
103         priv->primary_socket = 0;
104         claim_zero(remove(path));
105 }
106
107 /**
108  * Handle socket interrupts.
109  *
110  * @param dev
111  *   Pointer to Ethernet device.
112  */
113 void
114 mlx5_socket_handle(struct rte_eth_dev *dev)
115 {
116         struct priv *priv = dev->data->dev_private;
117         int conn_sock;
118         int ret = 0;
119         struct cmsghdr *cmsg = NULL;
120         struct ucred *cred = NULL;
121         char buf[CMSG_SPACE(sizeof(struct ucred))] = { 0 };
122         char vbuf[1024] = { 0 };
123         struct iovec io = {
124                 .iov_base = vbuf,
125                 .iov_len = sizeof(*vbuf),
126         };
127         struct msghdr msg = {
128                 .msg_iov = &io,
129                 .msg_iovlen = 1,
130                 .msg_control = buf,
131                 .msg_controllen = sizeof(buf),
132         };
133         int *fd;
134
135         /* Accept the connection from the client. */
136         conn_sock = accept(priv->primary_socket, NULL, NULL);
137         if (conn_sock < 0) {
138                 DRV_LOG(WARNING, "port %u connection failed: %s",
139                         dev->data->port_id, strerror(errno));
140                 return;
141         }
142         ret = setsockopt(conn_sock, SOL_SOCKET, SO_PASSCRED, &(int){1},
143                                          sizeof(int));
144         if (ret < 0) {
145                 ret = errno;
146                 DRV_LOG(WARNING, "port %u cannot change socket options: %s",
147                         dev->data->port_id, strerror(rte_errno));
148                 goto error;
149         }
150         ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
151         if (ret < 0) {
152                 ret = errno;
153                 DRV_LOG(WARNING, "port %u received an empty message: %s",
154                         dev->data->port_id, strerror(rte_errno));
155                 goto error;
156         }
157         /* Expect to receive credentials only. */
158         cmsg = CMSG_FIRSTHDR(&msg);
159         if (cmsg == NULL) {
160                 DRV_LOG(WARNING, "port %u no message", dev->data->port_id);
161                 goto error;
162         }
163         if ((cmsg->cmsg_type == SCM_CREDENTIALS) &&
164                 (cmsg->cmsg_len >= sizeof(*cred))) {
165                 cred = (struct ucred *)CMSG_DATA(cmsg);
166                 assert(cred != NULL);
167         }
168         cmsg = CMSG_NXTHDR(&msg, cmsg);
169         if (cmsg != NULL) {
170                 DRV_LOG(WARNING, "port %u message wrongly formatted",
171                         dev->data->port_id);
172                 goto error;
173         }
174         /* Make sure all the ancillary data was received and valid. */
175         if ((cred == NULL) || (cred->uid != getuid()) ||
176             (cred->gid != getgid())) {
177                 DRV_LOG(WARNING, "port %u wrong credentials",
178                         dev->data->port_id);
179                 goto error;
180         }
181         /* Set-up the ancillary data. */
182         cmsg = CMSG_FIRSTHDR(&msg);
183         assert(cmsg != NULL);
184         cmsg->cmsg_level = SOL_SOCKET;
185         cmsg->cmsg_type = SCM_RIGHTS;
186         cmsg->cmsg_len = CMSG_LEN(sizeof(priv->ctx->cmd_fd));
187         fd = (int *)CMSG_DATA(cmsg);
188         *fd = priv->ctx->cmd_fd;
189         ret = sendmsg(conn_sock, &msg, 0);
190         if (ret < 0)
191                 DRV_LOG(WARNING, "port %u cannot send response",
192                         dev->data->port_id);
193 error:
194         close(conn_sock);
195 }
196
197 /**
198  * Connect to the primary process.
199  *
200  * @param[in] dev
201  *   Pointer to Ethernet structure.
202  *
203  * @return
204  *   fd on success, negative errno value otherwise and rte_errno is set.
205  */
206 int
207 mlx5_socket_connect(struct rte_eth_dev *dev)
208 {
209         struct priv *priv = dev->data->dev_private;
210         struct sockaddr_un sun = {
211                 .sun_family = AF_UNIX,
212         };
213         int socket_fd = -1;
214         int *fd = NULL;
215         int ret;
216         struct ucred *cred;
217         char buf[CMSG_SPACE(sizeof(*cred))] = { 0 };
218         char vbuf[1024] = { 0 };
219         struct iovec io = {
220                 .iov_base = vbuf,
221                 .iov_len = sizeof(*vbuf),
222         };
223         struct msghdr msg = {
224                 .msg_control = buf,
225                 .msg_controllen = sizeof(buf),
226                 .msg_iov = &io,
227                 .msg_iovlen = 1,
228         };
229         struct cmsghdr *cmsg;
230
231         ret = socket(AF_UNIX, SOCK_STREAM, 0);
232         if (ret < 0) {
233                 rte_errno = errno;
234                 DRV_LOG(WARNING, "port %u cannot connect to primary",
235                         dev->data->port_id);
236                 goto error;
237         }
238         socket_fd = ret;
239         snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
240                  MLX5_DRIVER_NAME, priv->primary_socket);
241         ret = connect(socket_fd, (const struct sockaddr *)&sun, sizeof(sun));
242         if (ret < 0) {
243                 rte_errno = errno;
244                 DRV_LOG(WARNING, "port %u cannot connect to primary",
245                         dev->data->port_id);
246                 goto error;
247         }
248         cmsg = CMSG_FIRSTHDR(&msg);
249         if (cmsg == NULL) {
250                 rte_errno = EINVAL;
251                 DRV_LOG(DEBUG, "port %u cannot get first message",
252                         dev->data->port_id);
253                 goto error;
254         }
255         cmsg->cmsg_level = SOL_SOCKET;
256         cmsg->cmsg_type = SCM_CREDENTIALS;
257         cmsg->cmsg_len = CMSG_LEN(sizeof(*cred));
258         cred = (struct ucred *)CMSG_DATA(cmsg);
259         if (cred == NULL) {
260                 rte_errno = EINVAL;
261                 DRV_LOG(DEBUG, "port %u no credentials received",
262                         dev->data->port_id);
263                 goto error;
264         }
265         cred->pid = getpid();
266         cred->uid = getuid();
267         cred->gid = getgid();
268         ret = sendmsg(socket_fd, &msg, MSG_DONTWAIT);
269         if (ret < 0) {
270                 rte_errno = errno;
271                 DRV_LOG(WARNING,
272                         "port %u cannot send credentials to primary: %s",
273                         dev->data->port_id, strerror(errno));
274                 goto error;
275         }
276         ret = recvmsg(socket_fd, &msg, MSG_WAITALL);
277         if (ret <= 0) {
278                 rte_errno = errno;
279                 DRV_LOG(WARNING, "port %u no message from primary: %s",
280                         dev->data->port_id, strerror(errno));
281                 goto error;
282         }
283         cmsg = CMSG_FIRSTHDR(&msg);
284         if (cmsg == NULL) {
285                 rte_errno = EINVAL;
286                 DRV_LOG(WARNING, "port %u no file descriptor received",
287                         dev->data->port_id);
288                 goto error;
289         }
290         fd = (int *)CMSG_DATA(cmsg);
291         if (*fd < 0) {
292                 DRV_LOG(WARNING, "port %u no file descriptor received: %s",
293                         dev->data->port_id, strerror(errno));
294                 rte_errno = *fd;
295                 goto error;
296         }
297         ret = *fd;
298         close(socket_fd);
299         return 0;
300 error:
301         if (socket_fd != -1)
302                 close(socket_fd);
303         return -rte_errno;
304 }