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