1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
8 #include <sys/socket.h>
16 #include "mlx5_utils.h"
19 * Initialise the socket to communicate with the secondary process
22 * Pointer to Ethernet device.
25 * 0 on success, a negative errno value otherwise and rte_errno is set.
28 mlx5_socket_init(struct rte_eth_dev *dev)
30 struct priv *priv = dev->data->dev_private;
31 struct sockaddr_un sun = {
32 .sun_family = AF_UNIX,
36 struct stat file_stat;
39 * Initialise the socket to communicate with the secondary
42 ret = socket(AF_UNIX, SOCK_STREAM, 0);
45 WARN("port %u secondary process not supported: %s",
46 dev->data->port_id, strerror(errno));
49 priv->primary_socket = ret;
50 flags = fcntl(priv->primary_socket, F_GETFL, 0);
55 ret = fcntl(priv->primary_socket, F_SETFL, flags | O_NONBLOCK);
60 snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
61 MLX5_DRIVER_NAME, priv->primary_socket);
62 ret = stat(sun.sun_path, &file_stat);
64 claim_zero(remove(sun.sun_path));
65 ret = bind(priv->primary_socket, (const struct sockaddr *)&sun,
69 WARN("port %u cannot bind socket, secondary process not"
70 " supported: %s", dev->data->port_id, strerror(errno));
73 ret = listen(priv->primary_socket, 0);
76 WARN("port %u secondary process not supported: %s",
77 dev->data->port_id, strerror(errno));
84 claim_zero(close(priv->primary_socket));
85 priv->primary_socket = 0;
90 * Un-Initialise the socket to communicate with the secondary process
95 mlx5_socket_uninit(struct rte_eth_dev *dev)
97 struct priv *priv = dev->data->dev_private;
99 MKSTR(path, "/var/tmp/%s_%d", MLX5_DRIVER_NAME, priv->primary_socket);
100 claim_zero(close(priv->primary_socket));
101 priv->primary_socket = 0;
102 claim_zero(remove(path));
106 * Handle socket interrupts.
109 * Pointer to Ethernet device.
112 mlx5_socket_handle(struct rte_eth_dev *dev)
114 struct priv *priv = dev->data->dev_private;
117 struct cmsghdr *cmsg = NULL;
118 struct ucred *cred = NULL;
119 char buf[CMSG_SPACE(sizeof(struct ucred))] = { 0 };
120 char vbuf[1024] = { 0 };
123 .iov_len = sizeof(*vbuf),
125 struct msghdr msg = {
129 .msg_controllen = sizeof(buf),
133 /* Accept the connection from the client. */
134 conn_sock = accept(priv->primary_socket, NULL, NULL);
136 WARN("port %u connection failed: %s", dev->data->port_id,
140 ret = setsockopt(conn_sock, SOL_SOCKET, SO_PASSCRED, &(int){1},
144 WARN("port %u cannot change socket options: %s",
145 dev->data->port_id, strerror(rte_errno));
148 ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
151 WARN("port %u received an empty message: %s",
152 dev->data->port_id, strerror(rte_errno));
155 /* Expect to receive credentials only. */
156 cmsg = CMSG_FIRSTHDR(&msg);
158 WARN("port %u no message", dev->data->port_id);
161 if ((cmsg->cmsg_type == SCM_CREDENTIALS) &&
162 (cmsg->cmsg_len >= sizeof(*cred))) {
163 cred = (struct ucred *)CMSG_DATA(cmsg);
164 assert(cred != NULL);
166 cmsg = CMSG_NXTHDR(&msg, cmsg);
168 WARN("port %u message wrongly formatted", dev->data->port_id);
171 /* Make sure all the ancillary data was received and valid. */
172 if ((cred == NULL) || (cred->uid != getuid()) ||
173 (cred->gid != getgid())) {
174 WARN("port %u wrong credentials", dev->data->port_id);
177 /* Set-up the ancillary data. */
178 cmsg = CMSG_FIRSTHDR(&msg);
179 assert(cmsg != NULL);
180 cmsg->cmsg_level = SOL_SOCKET;
181 cmsg->cmsg_type = SCM_RIGHTS;
182 cmsg->cmsg_len = CMSG_LEN(sizeof(priv->ctx->cmd_fd));
183 fd = (int *)CMSG_DATA(cmsg);
184 *fd = priv->ctx->cmd_fd;
185 ret = sendmsg(conn_sock, &msg, 0);
187 WARN("port %u cannot send response", dev->data->port_id);
193 * Connect to the primary process.
196 * Pointer to Ethernet structure.
199 * fd on success, negative errno value otherwise and rte_errno is set.
202 mlx5_socket_connect(struct rte_eth_dev *dev)
204 struct priv *priv = dev->data->dev_private;
205 struct sockaddr_un sun = {
206 .sun_family = AF_UNIX,
212 char buf[CMSG_SPACE(sizeof(*cred))] = { 0 };
213 char vbuf[1024] = { 0 };
216 .iov_len = sizeof(*vbuf),
218 struct msghdr msg = {
220 .msg_controllen = sizeof(buf),
224 struct cmsghdr *cmsg;
226 ret = socket(AF_UNIX, SOCK_STREAM, 0);
229 WARN("port %u cannot connect to primary", dev->data->port_id);
233 snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
234 MLX5_DRIVER_NAME, priv->primary_socket);
235 ret = connect(socket_fd, (const struct sockaddr *)&sun, sizeof(sun));
238 WARN("port %u cannot connect to primary", dev->data->port_id);
241 cmsg = CMSG_FIRSTHDR(&msg);
244 DEBUG("port %u cannot get first message", dev->data->port_id);
247 cmsg->cmsg_level = SOL_SOCKET;
248 cmsg->cmsg_type = SCM_CREDENTIALS;
249 cmsg->cmsg_len = CMSG_LEN(sizeof(*cred));
250 cred = (struct ucred *)CMSG_DATA(cmsg);
253 DEBUG("port %u no credentials received", dev->data->port_id);
256 cred->pid = getpid();
257 cred->uid = getuid();
258 cred->gid = getgid();
259 ret = sendmsg(socket_fd, &msg, MSG_DONTWAIT);
262 WARN("port %u cannot send credentials to primary: %s",
263 dev->data->port_id, strerror(errno));
266 ret = recvmsg(socket_fd, &msg, MSG_WAITALL);
269 WARN("port %u no message from primary: %s",
270 dev->data->port_id, strerror(errno));
273 cmsg = CMSG_FIRSTHDR(&msg);
276 WARN("port %u no file descriptor received", dev->data->port_id);
279 fd = (int *)CMSG_DATA(cmsg);
281 WARN("port %u no file descriptor received: %s",
282 dev->data->port_id, strerror(errno));