This patch introduces vfio-user library, which follows vfio-user
protocol v1.0. As vfio-user has server and client implementaion,
this patch introduces basic structures and internal functions that
will be used by both server and client.

Signed-off-by: Chenbo Xia <chenbo....@intel.com>
Signed-off-by: Xiuchun Lu <xiuchun...@intel.com>
---
 MAINTAINERS                           |   4 +
 lib/librte_vfio_user/meson.build      |   9 ++
 lib/librte_vfio_user/version.map      |   3 +
 lib/librte_vfio_user/vfio_user_base.c | 205 ++++++++++++++++++++++++++
 lib/librte_vfio_user/vfio_user_base.h |  65 ++++++++
 lib/meson.build                       |   1 +
 6 files changed, 287 insertions(+)
 create mode 100644 lib/librte_vfio_user/meson.build
 create mode 100644 lib/librte_vfio_user/version.map
 create mode 100644 lib/librte_vfio_user/vfio_user_base.c
 create mode 100644 lib/librte_vfio_user/vfio_user_base.h

diff --git a/MAINTAINERS b/MAINTAINERS
index eafe9f8c46..5fb4880758 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1540,6 +1540,10 @@ M: Nithin Dabilpuram <ndabilpu...@marvell.com>
 M: Pavan Nikhilesh <pbhagavat...@marvell.com>
 F: lib/librte_node/
 
+Vfio-user - EXPERIMENTAL
+M: Chenbo Xia <chenbo....@intel.com>
+M: Xiuchun Lu <xiuchun...@intel.com>
+F: lib/librte_vfio_user/
 
 Test Applications
 -----------------
diff --git a/lib/librte_vfio_user/meson.build b/lib/librte_vfio_user/meson.build
new file mode 100644
index 0000000000..0f6407b80f
--- /dev/null
+++ b/lib/librte_vfio_user/meson.build
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2020 Intel Corporation
+
+if not is_linux
+       build = false
+       reason = 'only supported on Linux'
+endif
+
+sources = files('vfio_user_base.c')
diff --git a/lib/librte_vfio_user/version.map b/lib/librte_vfio_user/version.map
new file mode 100644
index 0000000000..33c1b976f1
--- /dev/null
+++ b/lib/librte_vfio_user/version.map
@@ -0,0 +1,3 @@
+EXPERIMENTAL {
+       local: *;
+};
diff --git a/lib/librte_vfio_user/vfio_user_base.c 
b/lib/librte_vfio_user/vfio_user_base.c
new file mode 100644
index 0000000000..bbad553e0a
--- /dev/null
+++ b/lib/librte_vfio_user/vfio_user_base.c
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include "vfio_user_base.h"
+
+int vfio_user_log_level;
+
+const char *vfio_user_msg_str[VFIO_USER_MAX] = {
+       [VFIO_USER_NONE] = "VFIO_USER_NONE",
+       [VFIO_USER_VERSION] = "VFIO_USER_VERSION",
+};
+
+inline void vfio_user_close_msg_fds(VFIO_USER_MSG *msg)
+{
+       int i;
+
+       for (i = 0; i < msg->fd_num; i++)
+               close(msg->fds[i]);
+}
+
+int vfio_user_check_msg_fdnum(VFIO_USER_MSG *msg, int expected_fds)
+{
+       if (msg->fd_num == expected_fds)
+               return 0;
+
+       VFIO_USER_LOG(ERR, "Expect %d FDs for request %s, received %d\n",
+               expected_fds, vfio_user_msg_str[msg->cmd], msg->fd_num);
+
+       vfio_user_close_msg_fds(msg);
+
+       return -1;
+}
+
+static int vfio_user_recv_fd_msg(int sockfd, char *buf, int buflen, int *fds,
+       int max_fds, int *fd_num)
+{
+       struct iovec iov;
+       struct msghdr msgh;
+       char control[CMSG_SPACE(max_fds * sizeof(int))];
+       struct cmsghdr *cmsg;
+       int fd_sz, got_fds = 0;
+       int ret, i;
+
+       *fd_num = 0;
+
+       memset(&msgh, 0, sizeof(msgh));
+       iov.iov_base = buf;
+       iov.iov_len  = buflen;
+
+       msgh.msg_iov = &iov;
+       msgh.msg_iovlen = 1;
+       msgh.msg_control = control;
+       msgh.msg_controllen = sizeof(control);
+
+       ret = recvmsg(sockfd, &msgh, 0);
+       if (ret <= 0) {
+               if (ret)
+                       VFIO_USER_LOG(DEBUG, "recvmsg failed\n");
+               return ret;
+       }
+
+       if (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
+               VFIO_USER_LOG(ERR, "Message is truncated\n");
+               return -1;
+       }
+
+       for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
+               cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+               if ((cmsg->cmsg_level == SOL_SOCKET) &&
+                       (cmsg->cmsg_type == SCM_RIGHTS)) {
+                       fd_sz = cmsg->cmsg_len - CMSG_LEN(0);
+                       got_fds = fd_sz / sizeof(int);
+                       if (got_fds >= max_fds) {
+                               /* Invalid message, close fds */
+                               int *close_fd = (int *)CMSG_DATA(cmsg);
+                               for (i = 0; i < got_fds; i++) {
+                                       close_fd += i;
+                                       close(*close_fd);
+                               }
+                               VFIO_USER_LOG(ERR, "fd num exceeds max "
+                                       "in vfio-user msg\n");
+                               return -1;
+                       }
+                       *fd_num = got_fds;
+                       memcpy(fds, CMSG_DATA(cmsg), got_fds * sizeof(int));
+                       break;
+               }
+       }
+
+       /* Make unused file descriptors invalid */
+       while (got_fds < max_fds)
+               fds[got_fds++] = -1;
+
+       return ret;
+}
+
+int vfio_user_recv_msg(int sockfd, VFIO_USER_MSG *msg)
+{
+       int ret;
+
+       ret = vfio_user_recv_fd_msg(sockfd, (char *)msg, VFIO_USER_MSG_HDR_SIZE,
+               msg->fds, VFIO_USER_MAX_FD, &msg->fd_num);
+       if (ret <= 0) {
+               return ret;
+       } else if (ret != VFIO_USER_MSG_HDR_SIZE) {
+               VFIO_USER_LOG(ERR, "Read unexpected header size\n");
+               ret = -1;
+               goto err;
+       }
+
+       if (msg->size > VFIO_USER_MSG_HDR_SIZE) {
+               if (msg->size > (sizeof(msg->payload) +
+                       VFIO_USER_MSG_HDR_SIZE)) {
+                       VFIO_USER_LOG(ERR, "Read invalid msg size: %d\n",
+                               msg->size);
+                       ret = -1;
+                       goto err;
+               }
+
+               ret = read(sockfd, &msg->payload,
+                       msg->size - VFIO_USER_MSG_HDR_SIZE);
+               if (ret <= 0)
+                       goto err;
+               if (ret != (int)(msg->size - VFIO_USER_MSG_HDR_SIZE)) {
+                       VFIO_USER_LOG(ERR, "Read payload failed\n");
+                       ret = -1;
+                       goto err;
+               }
+       }
+
+       return ret;
+err:
+       vfio_user_close_msg_fds(msg);
+       return ret;
+}
+
+static int
+vfio_user_send_fd_msg(int sockfd, char *buf, int buflen, int *fds, int fd_num)
+{
+
+       struct iovec iov;
+       struct msghdr msgh;
+       size_t fdsize = fd_num * sizeof(int);
+       char control[CMSG_SPACE(fdsize)];
+       struct cmsghdr *cmsg;
+       int ret;
+
+       memset(&msgh, 0, sizeof(msgh));
+       iov.iov_base = buf;
+       iov.iov_len = buflen;
+
+       msgh.msg_iov = &iov;
+       msgh.msg_iovlen = 1;
+
+       if (fds && fd_num > 0) {
+               msgh.msg_control = control;
+               msgh.msg_controllen = sizeof(control);
+               cmsg = CMSG_FIRSTHDR(&msgh);
+               cmsg->cmsg_len = CMSG_LEN(fdsize);
+               cmsg->cmsg_level = SOL_SOCKET;
+               cmsg->cmsg_type = SCM_RIGHTS;
+               memcpy(CMSG_DATA(cmsg), fds, fdsize);
+       } else {
+               msgh.msg_control = NULL;
+               msgh.msg_controllen = 0;
+       }
+
+       do {
+               ret = sendmsg(sockfd, &msgh, MSG_NOSIGNAL);
+       } while (ret < 0 && errno == EINTR);
+
+       if (ret < 0) {
+               VFIO_USER_LOG(ERR, "sendmsg error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+int vfio_user_send_msg(int sockfd, VFIO_USER_MSG *msg)
+{
+       if (!msg)
+               return 0;
+
+       return vfio_user_send_fd_msg(sockfd, (char *)msg,
+               msg->size, msg->fds, msg->fd_num);
+}
+
+int vfio_user_reply_msg(int sockfd, VFIO_USER_MSG *msg)
+{
+       if (!msg)
+               return 0;
+
+       msg->flags |= VFIO_USER_NEED_NO_RP;
+       msg->flags |= VFIO_USER_TYPE_REPLY;
+
+       return vfio_user_send_msg(sockfd, msg);
+}
+
+RTE_LOG_REGISTER(vfio_user_log_level, lib.vfio, INFO);
diff --git a/lib/librte_vfio_user/vfio_user_base.h 
b/lib/librte_vfio_user/vfio_user_base.h
new file mode 100644
index 0000000000..6db45b1819
--- /dev/null
+++ b/lib/librte_vfio_user/vfio_user_base.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _VFIO_USER_BASE_H
+#define _VFIO_USER_BASE_H
+
+#include <rte_log.h>
+
+#define VFIO_USER_MAX_FD 1024
+#define VFIO_USER_MAX_VERSION_DATA 512
+
+extern int vfio_user_log_level;
+extern const char *vfio_user_msg_str[];
+
+#define VFIO_USER_LOG(level, fmt, args...)                     \
+       rte_log(RTE_LOG_ ## level, vfio_user_log_level,         \
+       "VFIO_USER: " fmt, ## args)
+
+struct vfio_user_socket {
+       char *sock_addr;
+       int sock_fd;
+       int dev_id;
+};
+
+typedef enum VFIO_USER_CMD_TYPE {
+       VFIO_USER_NONE = 0,
+       VFIO_USER_VERSION = 1,
+       VFIO_USER_MAX = 2,
+} VFIO_USER_CMD_TYPE;
+
+struct vfio_user_version {
+       uint16_t major;
+       uint16_t minor;
+       /* Version data (JSON), for now not supported */
+       uint8_t ver_data[VFIO_USER_MAX_VERSION_DATA];
+};
+
+typedef struct vfio_user_msg {
+       uint16_t msg_id;
+       uint16_t cmd;
+       uint32_t size;
+#define VFIO_USER_TYPE_CMD     (0x0)           /* Message type is COMMAND */
+#define VFIO_USER_TYPE_REPLY   (0x1 << 0)      /* Message type is REPLY */
+#define VFIO_USER_NEED_NO_RP   (0x1 << 4)      /* Message needs no reply */
+#define VFIO_USER_ERROR                (0x1 << 5)      /* Reply message has 
error */
+       uint32_t flags;
+       uint32_t err;                           /* Valid in reply, optional */
+       union {
+               struct vfio_user_version ver;
+       } payload;
+       int fds[VFIO_USER_MAX_FD];
+       int fd_num;
+} __attribute((packed)) VFIO_USER_MSG;
+
+#define VFIO_USER_MSG_HDR_SIZE offsetof(VFIO_USER_MSG, payload.ver)
+
+void vfio_user_close_msg_fds(VFIO_USER_MSG *msg);
+int vfio_user_check_msg_fdnum(VFIO_USER_MSG *msg, int expected_fds);
+void vfio_user_close_msg_fds(VFIO_USER_MSG *msg);
+int vfio_user_recv_msg(int sockfd, VFIO_USER_MSG *msg);
+int vfio_user_send_msg(int sockfd, VFIO_USER_MSG *msg);
+int vfio_user_reply_msg(int sockfd, VFIO_USER_MSG *msg);
+
+#endif
diff --git a/lib/meson.build b/lib/meson.build
index ed00f89146..b7fbfcc95b 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -28,6 +28,7 @@ libraries = [
        'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',
        # ipsec lib depends on net, crypto and security
        'ipsec',
+       'vfio_user',
        #fib lib depends on rib
        'fib',
        # add pkt framework libs which use other libs from above
-- 
2.17.1

Reply via email to