1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
3 * Copyright 2016 Mellanox Technologies, Ltd
9 #include <sys/socket.h>
17 #include "mlx5_utils.h"
20 * Initialise the socket to communicate with the secondary process
23 * Pointer to Ethernet device.
26 * 0 on success, a negative errno value otherwise and rte_errno is set.
29 mlx5_socket_init(struct rte_eth_dev *dev)
31 struct priv *priv = dev->data->dev_private;
32 struct sockaddr_un sun = {
33 .sun_family = AF_UNIX,
39 * Close the last socket that was used to communicate
40 * with the secondary process
42 if (priv->primary_socket)
43 mlx5_socket_uninit(dev);
45 * Initialise the socket to communicate with the secondary
48 ret = socket(AF_UNIX, SOCK_STREAM, 0);
51 DRV_LOG(WARNING, "port %u secondary process not supported: %s",
52 dev->data->port_id, strerror(errno));
55 priv->primary_socket = ret;
56 flags = fcntl(priv->primary_socket, F_GETFL, 0);
61 ret = fcntl(priv->primary_socket, F_SETFL, flags | O_NONBLOCK);
66 snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
67 MLX5_DRIVER_NAME, priv->primary_socket);
69 ret = bind(priv->primary_socket, (const struct sockaddr *)&sun,
74 "port %u cannot bind socket, secondary process not"
76 dev->data->port_id, strerror(errno));
79 ret = listen(priv->primary_socket, 0);
82 DRV_LOG(WARNING, "port %u secondary process not supported: %s",
83 dev->data->port_id, strerror(errno));
90 claim_zero(close(priv->primary_socket));
91 priv->primary_socket = 0;
96 * Un-Initialise the socket to communicate with the secondary process
101 mlx5_socket_uninit(struct rte_eth_dev *dev)
103 struct priv *priv = dev->data->dev_private;
105 MKSTR(path, "/var/tmp/%s_%d", MLX5_DRIVER_NAME, priv->primary_socket);
106 claim_zero(close(priv->primary_socket));
107 priv->primary_socket = 0;
108 claim_zero(remove(path));
112 * Handle socket interrupts.
115 * Pointer to Ethernet device.
118 mlx5_socket_handle(struct rte_eth_dev *dev)
120 struct priv *priv = dev->data->dev_private;
123 struct cmsghdr *cmsg = NULL;
124 struct ucred *cred = NULL;
125 char buf[CMSG_SPACE(sizeof(struct ucred))] = { 0 };
126 char vbuf[1024] = { 0 };
129 .iov_len = sizeof(*vbuf),
131 struct msghdr msg = {
135 .msg_controllen = sizeof(buf),
139 /* Accept the connection from the client. */
140 conn_sock = accept(priv->primary_socket, NULL, NULL);
142 DRV_LOG(WARNING, "port %u connection failed: %s",
143 dev->data->port_id, strerror(errno));
146 ret = setsockopt(conn_sock, SOL_SOCKET, SO_PASSCRED, &(int){1},
150 DRV_LOG(WARNING, "port %u cannot change socket options: %s",
151 dev->data->port_id, strerror(rte_errno));
154 ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
157 DRV_LOG(WARNING, "port %u received an empty message: %s",
158 dev->data->port_id, strerror(rte_errno));
161 /* Expect to receive credentials only. */
162 cmsg = CMSG_FIRSTHDR(&msg);
164 DRV_LOG(WARNING, "port %u no message", dev->data->port_id);
167 if ((cmsg->cmsg_type == SCM_CREDENTIALS) &&
168 (cmsg->cmsg_len >= sizeof(*cred))) {
169 cred = (struct ucred *)CMSG_DATA(cmsg);
170 assert(cred != NULL);
172 cmsg = CMSG_NXTHDR(&msg, cmsg);
174 DRV_LOG(WARNING, "port %u message wrongly formatted",
178 /* Make sure all the ancillary data was received and valid. */
179 if ((cred == NULL) || (cred->uid != getuid()) ||
180 (cred->gid != getgid())) {
181 DRV_LOG(WARNING, "port %u wrong credentials",
185 /* Set-up the ancillary data. */
186 cmsg = CMSG_FIRSTHDR(&msg);
187 assert(cmsg != NULL);
188 cmsg->cmsg_level = SOL_SOCKET;
189 cmsg->cmsg_type = SCM_RIGHTS;
190 cmsg->cmsg_len = CMSG_LEN(sizeof(priv->ctx->cmd_fd));
191 fd = (int *)CMSG_DATA(cmsg);
192 *fd = priv->ctx->cmd_fd;
193 ret = sendmsg(conn_sock, &msg, 0);
195 DRV_LOG(WARNING, "port %u cannot send response",
202 * Connect to the primary process.
205 * Pointer to Ethernet structure.
208 * fd on success, negative errno value otherwise and rte_errno is set.
211 mlx5_socket_connect(struct rte_eth_dev *dev)
213 struct priv *priv = dev->data->dev_private;
214 struct sockaddr_un sun = {
215 .sun_family = AF_UNIX,
221 char buf[CMSG_SPACE(sizeof(*cred))] = { 0 };
222 char vbuf[1024] = { 0 };
225 .iov_len = sizeof(*vbuf),
227 struct msghdr msg = {
229 .msg_controllen = sizeof(buf),
233 struct cmsghdr *cmsg;
235 ret = socket(AF_UNIX, SOCK_STREAM, 0);
238 DRV_LOG(WARNING, "port %u cannot connect to primary",
243 snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
244 MLX5_DRIVER_NAME, priv->primary_socket);
245 ret = connect(socket_fd, (const struct sockaddr *)&sun, sizeof(sun));
248 DRV_LOG(WARNING, "port %u cannot connect to primary",
252 cmsg = CMSG_FIRSTHDR(&msg);
255 DRV_LOG(DEBUG, "port %u cannot get first message",
259 cmsg->cmsg_level = SOL_SOCKET;
260 cmsg->cmsg_type = SCM_CREDENTIALS;
261 cmsg->cmsg_len = CMSG_LEN(sizeof(*cred));
262 cred = (struct ucred *)CMSG_DATA(cmsg);
265 DRV_LOG(DEBUG, "port %u no credentials received",
269 cred->pid = getpid();
270 cred->uid = getuid();
271 cred->gid = getgid();
272 ret = sendmsg(socket_fd, &msg, MSG_DONTWAIT);
276 "port %u cannot send credentials to primary: %s",
277 dev->data->port_id, strerror(errno));
280 ret = recvmsg(socket_fd, &msg, MSG_WAITALL);
283 DRV_LOG(WARNING, "port %u no message from primary: %s",
284 dev->data->port_id, strerror(errno));
287 cmsg = CMSG_FIRSTHDR(&msg);
290 DRV_LOG(WARNING, "port %u no file descriptor received",
294 fd = (int *)CMSG_DATA(cmsg);
296 DRV_LOG(WARNING, "port %u no file descriptor received: %s",
297 dev->data->port_id, strerror(errno));