1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
3 * Copyright 2016 Mellanox Technologies, Ltd
7 #include <sys/socket.h>
15 #include "mlx5_utils.h"
18 * Initialise the socket to communicate with the secondary process
21 * Pointer to Ethernet device.
24 * 0 on success, a negative errno value otherwise and rte_errno is set.
27 mlx5_socket_init(struct rte_eth_dev *dev)
29 struct mlx5_priv *priv = dev->data->dev_private;
30 struct sockaddr_un sun = {
31 .sun_family = AF_UNIX,
37 * Close the last socket that was used to communicate
38 * with the secondary process
40 if (priv->primary_socket)
41 mlx5_socket_uninit(dev);
43 * Initialise the socket to communicate with the secondary
46 ret = socket(AF_UNIX, SOCK_STREAM, 0);
49 DRV_LOG(WARNING, "port %u secondary process not supported: %s",
50 dev->data->port_id, strerror(errno));
53 priv->primary_socket = ret;
54 flags = fcntl(priv->primary_socket, F_GETFL, 0);
59 ret = fcntl(priv->primary_socket, F_SETFL, flags | O_NONBLOCK);
64 snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
65 MLX5_DRIVER_NAME, priv->primary_socket);
67 ret = bind(priv->primary_socket, (const struct sockaddr *)&sun,
72 "port %u cannot bind socket, secondary process not"
74 dev->data->port_id, strerror(errno));
77 ret = listen(priv->primary_socket, 0);
80 DRV_LOG(WARNING, "port %u secondary process not supported: %s",
81 dev->data->port_id, strerror(errno));
88 claim_zero(close(priv->primary_socket));
89 priv->primary_socket = 0;
94 * Un-Initialise the socket to communicate with the secondary process
99 mlx5_socket_uninit(struct rte_eth_dev *dev)
101 struct mlx5_priv *priv = dev->data->dev_private;
103 MKSTR(path, "/var/tmp/%s_%d", MLX5_DRIVER_NAME, priv->primary_socket);
104 claim_zero(close(priv->primary_socket));
105 priv->primary_socket = 0;
106 claim_zero(remove(path));
110 * Handle socket interrupts.
113 * Pointer to Ethernet device.
116 mlx5_socket_handle(struct rte_eth_dev *dev)
118 struct mlx5_priv *priv = dev->data->dev_private;
121 struct cmsghdr *cmsg = NULL;
122 struct ucred *cred = NULL;
123 char buf[CMSG_SPACE(sizeof(struct ucred))] = { 0 };
124 char vbuf[1024] = { 0 };
127 .iov_len = sizeof(*vbuf),
129 struct msghdr msg = {
133 .msg_controllen = sizeof(buf),
137 /* Accept the connection from the client. */
138 conn_sock = accept(priv->primary_socket, NULL, NULL);
140 DRV_LOG(WARNING, "port %u connection failed: %s",
141 dev->data->port_id, strerror(errno));
144 ret = setsockopt(conn_sock, SOL_SOCKET, SO_PASSCRED, &(int){1},
148 DRV_LOG(WARNING, "port %u cannot change socket options: %s",
149 dev->data->port_id, strerror(rte_errno));
152 ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
155 DRV_LOG(WARNING, "port %u received an empty message: %s",
156 dev->data->port_id, strerror(rte_errno));
159 /* Expect to receive credentials only. */
160 cmsg = CMSG_FIRSTHDR(&msg);
162 DRV_LOG(WARNING, "port %u no message", dev->data->port_id);
165 if ((cmsg->cmsg_type == SCM_CREDENTIALS) &&
166 (cmsg->cmsg_len >= sizeof(*cred))) {
167 cred = (struct ucred *)CMSG_DATA(cmsg);
168 assert(cred != NULL);
170 cmsg = CMSG_NXTHDR(&msg, cmsg);
172 DRV_LOG(WARNING, "port %u message wrongly formatted",
176 /* Make sure all the ancillary data was received and valid. */
177 if ((cred == NULL) || (cred->uid != getuid()) ||
178 (cred->gid != getgid())) {
179 DRV_LOG(WARNING, "port %u wrong credentials",
183 /* Set-up the ancillary data. */
184 cmsg = CMSG_FIRSTHDR(&msg);
185 assert(cmsg != NULL);
186 cmsg->cmsg_level = SOL_SOCKET;
187 cmsg->cmsg_type = SCM_RIGHTS;
188 cmsg->cmsg_len = CMSG_LEN(sizeof(priv->ctx->cmd_fd));
189 fd = (int *)CMSG_DATA(cmsg);
190 *fd = priv->ctx->cmd_fd;
191 ret = sendmsg(conn_sock, &msg, 0);
193 DRV_LOG(WARNING, "port %u cannot send response",
200 * Connect to the primary process.
203 * Pointer to Ethernet structure.
206 * fd on success, negative errno value otherwise and rte_errno is set.
209 mlx5_socket_connect(struct rte_eth_dev *dev)
211 struct mlx5_priv *priv = dev->data->dev_private;
212 struct sockaddr_un sun = {
213 .sun_family = AF_UNIX,
219 char buf[CMSG_SPACE(sizeof(*cred))] = { 0 };
220 char vbuf[1024] = { 0 };
223 .iov_len = sizeof(*vbuf),
225 struct msghdr msg = {
227 .msg_controllen = sizeof(buf),
231 struct cmsghdr *cmsg;
233 ret = socket(AF_UNIX, SOCK_STREAM, 0);
236 DRV_LOG(WARNING, "port %u cannot connect to primary",
241 snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
242 MLX5_DRIVER_NAME, priv->primary_socket);
243 ret = connect(socket_fd, (const struct sockaddr *)&sun, sizeof(sun));
246 DRV_LOG(WARNING, "port %u cannot connect to primary",
250 cmsg = CMSG_FIRSTHDR(&msg);
253 DRV_LOG(DEBUG, "port %u cannot get first message",
257 cmsg->cmsg_level = SOL_SOCKET;
258 cmsg->cmsg_type = SCM_CREDENTIALS;
259 cmsg->cmsg_len = CMSG_LEN(sizeof(*cred));
260 cred = (struct ucred *)CMSG_DATA(cmsg);
263 DRV_LOG(DEBUG, "port %u no credentials received",
267 cred->pid = getpid();
268 cred->uid = getuid();
269 cred->gid = getgid();
270 ret = sendmsg(socket_fd, &msg, MSG_DONTWAIT);
274 "port %u cannot send credentials to primary: %s",
275 dev->data->port_id, strerror(errno));
278 ret = recvmsg(socket_fd, &msg, MSG_WAITALL);
281 DRV_LOG(WARNING, "port %u no message from primary: %s",
282 dev->data->port_id, strerror(errno));
285 cmsg = CMSG_FIRSTHDR(&msg);
288 DRV_LOG(WARNING, "port %u no file descriptor received",
292 fd = (int *)CMSG_DATA(cmsg);
294 DRV_LOG(WARNING, "port %u no file descriptor received: %s",
295 dev->data->port_id, strerror(errno));