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