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