net/mlx5: use port id in PMD log
[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                 WARN("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                 WARN("port %u cannot bind socket, secondary process not"
70                      " supported: %s", dev->data->port_id, strerror(errno));
71                 goto close;
72         }
73         ret = listen(priv->primary_socket, 0);
74         if (ret < 0) {
75                 rte_errno = errno;
76                 WARN("port %u secondary process not supported: %s",
77                      dev->data->port_id, strerror(errno));
78                 goto close;
79         }
80         return 0;
81 close:
82         remove(sun.sun_path);
83 error:
84         claim_zero(close(priv->primary_socket));
85         priv->primary_socket = 0;
86         return -rte_errno;
87 }
88
89 /**
90  * Un-Initialise the socket to communicate with the secondary process
91  *
92  * @param[in] dev
93  */
94 void
95 mlx5_socket_uninit(struct rte_eth_dev *dev)
96 {
97         struct priv *priv = dev->data->dev_private;
98
99         MKSTR(path, "/var/tmp/%s_%d", MLX5_DRIVER_NAME, priv->primary_socket);
100         claim_zero(close(priv->primary_socket));
101         priv->primary_socket = 0;
102         claim_zero(remove(path));
103 }
104
105 /**
106  * Handle socket interrupts.
107  *
108  * @param dev
109  *   Pointer to Ethernet device.
110  */
111 void
112 mlx5_socket_handle(struct rte_eth_dev *dev)
113 {
114         struct priv *priv = dev->data->dev_private;
115         int conn_sock;
116         int ret = 0;
117         struct cmsghdr *cmsg = NULL;
118         struct ucred *cred = NULL;
119         char buf[CMSG_SPACE(sizeof(struct ucred))] = { 0 };
120         char vbuf[1024] = { 0 };
121         struct iovec io = {
122                 .iov_base = vbuf,
123                 .iov_len = sizeof(*vbuf),
124         };
125         struct msghdr msg = {
126                 .msg_iov = &io,
127                 .msg_iovlen = 1,
128                 .msg_control = buf,
129                 .msg_controllen = sizeof(buf),
130         };
131         int *fd;
132
133         /* Accept the connection from the client. */
134         conn_sock = accept(priv->primary_socket, NULL, NULL);
135         if (conn_sock < 0) {
136                 WARN("port %u connection failed: %s", dev->data->port_id,
137                      strerror(errno));
138                 return;
139         }
140         ret = setsockopt(conn_sock, SOL_SOCKET, SO_PASSCRED, &(int){1},
141                                          sizeof(int));
142         if (ret < 0) {
143                 ret = errno;
144                 WARN("port %u cannot change socket options: %s",
145                      dev->data->port_id, strerror(rte_errno));
146                 goto error;
147         }
148         ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
149         if (ret < 0) {
150                 ret = errno;
151                 WARN("port %u received an empty message: %s",
152                      dev->data->port_id, strerror(rte_errno));
153                 goto error;
154         }
155         /* Expect to receive credentials only. */
156         cmsg = CMSG_FIRSTHDR(&msg);
157         if (cmsg == NULL) {
158                 WARN("port %u no message", dev->data->port_id);
159                 goto error;
160         }
161         if ((cmsg->cmsg_type == SCM_CREDENTIALS) &&
162                 (cmsg->cmsg_len >= sizeof(*cred))) {
163                 cred = (struct ucred *)CMSG_DATA(cmsg);
164                 assert(cred != NULL);
165         }
166         cmsg = CMSG_NXTHDR(&msg, cmsg);
167         if (cmsg != NULL) {
168                 WARN("port %u message wrongly formatted", dev->data->port_id);
169                 goto error;
170         }
171         /* Make sure all the ancillary data was received and valid. */
172         if ((cred == NULL) || (cred->uid != getuid()) ||
173             (cred->gid != getgid())) {
174                 WARN("port %u wrong credentials", dev->data->port_id);
175                 goto error;
176         }
177         /* Set-up the ancillary data. */
178         cmsg = CMSG_FIRSTHDR(&msg);
179         assert(cmsg != NULL);
180         cmsg->cmsg_level = SOL_SOCKET;
181         cmsg->cmsg_type = SCM_RIGHTS;
182         cmsg->cmsg_len = CMSG_LEN(sizeof(priv->ctx->cmd_fd));
183         fd = (int *)CMSG_DATA(cmsg);
184         *fd = priv->ctx->cmd_fd;
185         ret = sendmsg(conn_sock, &msg, 0);
186         if (ret < 0)
187                 WARN("port %u cannot send response", dev->data->port_id);
188 error:
189         close(conn_sock);
190 }
191
192 /**
193  * Connect to the primary process.
194  *
195  * @param[in] dev
196  *   Pointer to Ethernet structure.
197  *
198  * @return
199  *   fd on success, negative errno value otherwise and rte_errno is set.
200  */
201 int
202 mlx5_socket_connect(struct rte_eth_dev *dev)
203 {
204         struct priv *priv = dev->data->dev_private;
205         struct sockaddr_un sun = {
206                 .sun_family = AF_UNIX,
207         };
208         int socket_fd = -1;
209         int *fd = NULL;
210         int ret;
211         struct ucred *cred;
212         char buf[CMSG_SPACE(sizeof(*cred))] = { 0 };
213         char vbuf[1024] = { 0 };
214         struct iovec io = {
215                 .iov_base = vbuf,
216                 .iov_len = sizeof(*vbuf),
217         };
218         struct msghdr msg = {
219                 .msg_control = buf,
220                 .msg_controllen = sizeof(buf),
221                 .msg_iov = &io,
222                 .msg_iovlen = 1,
223         };
224         struct cmsghdr *cmsg;
225
226         ret = socket(AF_UNIX, SOCK_STREAM, 0);
227         if (ret < 0) {
228                 rte_errno = errno;
229                 WARN("port %u cannot connect to primary", dev->data->port_id);
230                 goto error;
231         }
232         socket_fd = ret;
233         snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
234                  MLX5_DRIVER_NAME, priv->primary_socket);
235         ret = connect(socket_fd, (const struct sockaddr *)&sun, sizeof(sun));
236         if (ret < 0) {
237                 rte_errno = errno;
238                 WARN("port %u cannot connect to primary", dev->data->port_id);
239                 goto error;
240         }
241         cmsg = CMSG_FIRSTHDR(&msg);
242         if (cmsg == NULL) {
243                 rte_errno = EINVAL;
244                 DEBUG("port %u cannot get first message", dev->data->port_id);
245                 goto error;
246         }
247         cmsg->cmsg_level = SOL_SOCKET;
248         cmsg->cmsg_type = SCM_CREDENTIALS;
249         cmsg->cmsg_len = CMSG_LEN(sizeof(*cred));
250         cred = (struct ucred *)CMSG_DATA(cmsg);
251         if (cred == NULL) {
252                 rte_errno = EINVAL;
253                 DEBUG("port %u no credentials received", dev->data->port_id);
254                 goto error;
255         }
256         cred->pid = getpid();
257         cred->uid = getuid();
258         cred->gid = getgid();
259         ret = sendmsg(socket_fd, &msg, MSG_DONTWAIT);
260         if (ret < 0) {
261                 rte_errno = errno;
262                 WARN("port %u cannot send credentials to primary: %s",
263                      dev->data->port_id, strerror(errno));
264                 goto error;
265         }
266         ret = recvmsg(socket_fd, &msg, MSG_WAITALL);
267         if (ret <= 0) {
268                 rte_errno = errno;
269                 WARN("port %u no message from primary: %s",
270                      dev->data->port_id, strerror(errno));
271                 goto error;
272         }
273         cmsg = CMSG_FIRSTHDR(&msg);
274         if (cmsg == NULL) {
275                 rte_errno = EINVAL;
276                 WARN("port %u no file descriptor received", dev->data->port_id);
277                 goto error;
278         }
279         fd = (int *)CMSG_DATA(cmsg);
280         if (*fd < 0) {
281                 WARN("port %u no file descriptor received: %s",
282                      dev->data->port_id, strerror(errno));
283                 rte_errno = *fd;
284                 goto error;
285         }
286         ret = *fd;
287         close(socket_fd);
288         return 0;
289 error:
290         if (socket_fd != -1)
291                 close(socket_fd);
292         return -rte_errno;
293 }