1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
7 #include <sys/socket.h>
10 /* sys/un.h with __USE_MISC uses strlen, which is unsafe */
12 #define REMOVED_USE_MISC
16 /* make sure we redefine __USE_MISC only if it was previously undefined */
17 #ifdef REMOVED_USE_MISC
19 #undef REMOVED_USE_MISC
23 #include <rte_eal_memconfig.h>
24 #include <rte_malloc.h>
27 #include "eal_filesystem.h"
29 #include "eal_thread.h"
33 * VFIO socket for communication between primary and secondary processes.
35 * This file is only compiled if CONFIG_RTE_EAL_VFIO is set to "y".
40 #define SOCKET_PATH_FMT "%s/.%s_mp_socket"
41 #define CMSGLEN (CMSG_LEN(sizeof(int)))
42 #define FD_TO_CMSGHDR(fd, chdr) \
44 (chdr).cmsg_len = CMSGLEN;\
45 (chdr).cmsg_level = SOL_SOCKET;\
46 (chdr).cmsg_type = SCM_RIGHTS;\
47 memcpy((chdr).__cmsg_data, &(fd), sizeof(fd));\
49 #define CMSGHDR_TO_FD(chdr, fd) \
50 memcpy(&(fd), (chdr).__cmsg_data, sizeof(fd))
52 static pthread_t socket_thread;
53 static int mp_socket_fd;
56 /* get socket path (/var/run if root, $HOME otherwise) */
58 get_socket_path(char *buffer, int bufsz)
60 const char *dir = "/var/run";
61 const char *home_dir = getenv("HOME");
63 if (getuid() != 0 && home_dir != NULL)
66 /* use current prefix as file path */
67 snprintf(buffer, bufsz, SOCKET_PATH_FMT, dir,
68 internal_config.hugefile_prefix);
74 * data flow for socket comm protocol:
75 * 1. client sends SOCKET_REQ_CONTAINER or SOCKET_REQ_GROUP
76 * 1a. in case of SOCKET_REQ_GROUP, client also then sends group number
77 * 2. server receives message
78 * 2a. in case of invalid group, SOCKET_ERR is sent back to client
79 * 2b. in case of unbound group, SOCKET_NO_FD is sent back to client
80 * 2c. in case of valid group, SOCKET_OK is sent and immediately followed by fd
82 * in case of any error, socket is closed.
85 /* send a request, return -1 on error */
87 vfio_mp_sync_send_request(int socket, int req)
94 memset(&hdr, 0, sizeof(hdr));
100 iov.iov_base = (char *) &buf;
101 iov.iov_len = sizeof(buf);
103 ret = sendmsg(socket, &hdr, 0);
109 /* receive a request and return it */
111 vfio_mp_sync_receive_request(int socket)
118 memset(&hdr, 0, sizeof(hdr));
124 iov.iov_base = (char *) &buf;
125 iov.iov_len = sizeof(buf);
127 ret = recvmsg(socket, &hdr, 0);
136 /* send OK in message, fd in control message */
138 vfio_mp_sync_send_fd(int socket, int fd)
142 struct cmsghdr *chdr;
143 char chdr_buf[CMSGLEN];
147 chdr = (struct cmsghdr *) chdr_buf;
148 memset(chdr, 0, sizeof(chdr_buf));
149 memset(&hdr, 0, sizeof(hdr));
153 iov.iov_base = (char *) &buf;
154 iov.iov_len = sizeof(buf);
155 hdr.msg_control = chdr;
156 hdr.msg_controllen = CMSGLEN;
159 FD_TO_CMSGHDR(fd, *chdr);
161 ret = sendmsg(socket, &hdr, 0);
167 /* receive OK in message, fd in control message */
169 vfio_mp_sync_receive_fd(int socket)
173 struct cmsghdr *chdr;
174 char chdr_buf[CMSGLEN];
180 chdr = (struct cmsghdr *) chdr_buf;
181 memset(chdr, 0, sizeof(chdr_buf));
182 memset(&hdr, 0, sizeof(hdr));
186 iov.iov_base = (char *) &buf;
187 iov.iov_len = sizeof(buf);
188 hdr.msg_control = chdr;
189 hdr.msg_controllen = CMSGLEN;
191 ret = recvmsg(socket, &hdr, 0);
197 if (req != SOCKET_OK)
200 CMSGHDR_TO_FD(*chdr, fd);
205 /* connect socket_fd in secondary process to the primary process's socket */
207 vfio_mp_sync_connect_to_primary(void)
209 struct sockaddr_un addr;
210 socklen_t sockaddr_len;
213 /* set up a socket */
214 socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
216 RTE_LOG(ERR, EAL, "Failed to create socket!\n");
220 get_socket_path(addr.sun_path, sizeof(addr.sun_path));
221 addr.sun_family = AF_UNIX;
223 sockaddr_len = sizeof(struct sockaddr_un);
225 if (connect(socket_fd, (struct sockaddr *) &addr, sockaddr_len) == 0)
228 /* if connect failed */
236 * socket listening thread for primary process
238 static __attribute__((noreturn)) void *
239 vfio_mp_sync_thread(void __rte_unused * arg)
241 int ret, fd, vfio_data;
243 /* wait for requests on the socket */
246 struct sockaddr_un addr;
247 socklen_t sockaddr_len = sizeof(addr);
249 /* this is a blocking call */
250 conn_sock = accept(mp_socket_fd, (struct sockaddr *) &addr,
253 /* just restart on error */
257 /* set socket to linger after close */
262 if (setsockopt(conn_sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
263 RTE_LOG(WARNING, EAL, "Cannot set SO_LINGER option "
264 "on listen socket (%s)\n", strerror(errno));
266 ret = vfio_mp_sync_receive_request(conn_sock);
269 case SOCKET_REQ_CONTAINER:
270 fd = rte_vfio_get_container_fd();
272 vfio_mp_sync_send_request(conn_sock, SOCKET_ERR);
274 vfio_mp_sync_send_fd(conn_sock, fd);
278 case SOCKET_REQ_GROUP:
279 /* wait for group number */
280 vfio_data = vfio_mp_sync_receive_request(conn_sock);
286 fd = rte_vfio_get_group_fd(vfio_data);
289 vfio_mp_sync_send_request(conn_sock, SOCKET_ERR);
290 /* if VFIO group exists but isn't bound to VFIO driver */
292 vfio_mp_sync_send_request(conn_sock, SOCKET_NO_FD);
293 /* if group exists and is bound to VFIO driver */
295 vfio_mp_sync_send_request(conn_sock, SOCKET_OK);
296 vfio_mp_sync_send_fd(conn_sock, fd);
299 case SOCKET_CLR_GROUP:
300 /* wait for group fd */
301 vfio_data = vfio_mp_sync_receive_request(conn_sock);
307 ret = rte_vfio_clear_group(vfio_data);
310 vfio_mp_sync_send_request(conn_sock, SOCKET_NO_FD);
312 vfio_mp_sync_send_request(conn_sock, SOCKET_OK);
315 vfio_mp_sync_send_request(conn_sock, SOCKET_ERR);
323 vfio_mp_sync_socket_setup(void)
326 struct sockaddr_un addr;
327 socklen_t sockaddr_len;
329 /* set up a socket */
330 socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
332 RTE_LOG(ERR, EAL, "Failed to create socket!\n");
336 get_socket_path(addr.sun_path, sizeof(addr.sun_path));
337 addr.sun_family = AF_UNIX;
339 sockaddr_len = sizeof(struct sockaddr_un);
341 unlink(addr.sun_path);
343 ret = bind(socket_fd, (struct sockaddr *) &addr, sockaddr_len);
345 RTE_LOG(ERR, EAL, "Failed to bind socket: %s!\n", strerror(errno));
350 ret = listen(socket_fd, 50);
352 RTE_LOG(ERR, EAL, "Failed to listen: %s!\n", strerror(errno));
357 /* save the socket in local configuration */
358 mp_socket_fd = socket_fd;
364 * set up a local socket and tell it to listen for incoming connections
367 vfio_mp_sync_setup(void)
370 char thread_name[RTE_MAX_THREAD_NAME_LEN];
372 if (vfio_mp_sync_socket_setup() < 0) {
373 RTE_LOG(ERR, EAL, "Failed to set up local socket!\n");
377 ret = pthread_create(&socket_thread, NULL,
378 vfio_mp_sync_thread, NULL);
381 "Failed to create thread for communication with secondary processes!\n");
386 /* Set thread_name for aid in debugging. */
387 snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "vfio-sync");
388 ret = rte_thread_setname(socket_thread, thread_name);
391 "Failed to set thread name for secondary processes!\n");