get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/85391/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 85391,
    "url": "http://patches.dpdk.org/api/patches/85391/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20201218073851.93609-3-chenbo.xia@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20201218073851.93609-3-chenbo.xia@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20201218073851.93609-3-chenbo.xia@intel.com",
    "date": "2020-12-18T07:38:44",
    "name": "[2/9] vfio_user: implement lifecycle related APIs",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "453df774f2ada5fe476a0b1077df720bada47582",
    "submitter": {
        "id": 1276,
        "url": "http://patches.dpdk.org/api/people/1276/?format=api",
        "name": "Chenbo Xia",
        "email": "chenbo.xia@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20201218073851.93609-3-chenbo.xia@intel.com/mbox/",
    "series": [
        {
            "id": 14361,
            "url": "http://patches.dpdk.org/api/series/14361/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=14361",
            "date": "2020-12-18T07:38:42",
            "name": "Introduce vfio-user library",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/14361/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/85391/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/85391/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 328E3A09F6;\n\tFri, 18 Dec 2020 08:54:54 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 63CD1CA5A;\n\tFri, 18 Dec 2020 08:54:16 +0100 (CET)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by dpdk.org (Postfix) with ESMTP id 98F08CA4D\n for <dev@dpdk.org>; Fri, 18 Dec 2020 08:54:13 +0100 (CET)",
            "from fmsmga008.fm.intel.com ([10.253.24.58])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 17 Dec 2020 23:54:13 -0800",
            "from npg-dpdk-virtio-xiachenbo-nw.sh.intel.com ([10.67.119.123])\n by fmsmga008.fm.intel.com with ESMTP; 17 Dec 2020 23:54:10 -0800"
        ],
        "IronPort-SDR": [
            "\n ujJHuStRotN8OEfCt52mYCgc0THEcanYm5+YcdibJ1u8wGzAhDdRhWpNOvaDxDpVTYd5IFH6EW\n 1EYEOztoC44w==",
            "\n k7H+Wd+PeF0WDYqtLIREWkF669uEmNO2wAxcV58LZ/3FC88r7YX9ucPKaZkMEegD01IDpLm3Ev\n tgW+ltMvkHEg=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9838\"; a=\"260126140\"",
            "E=Sophos;i=\"5.78,429,1599548400\"; d=\"scan'208\";a=\"260126140\"",
            "E=Sophos;i=\"5.78,429,1599548400\"; d=\"scan'208\";a=\"340270311\""
        ],
        "X-ExtLoop1": "1",
        "From": "Chenbo Xia <chenbo.xia@intel.com>",
        "To": "dev@dpdk.org,\n\tthomas@monjalon.net,\n\tdavid.marchand@redhat.com",
        "Cc": "stephen@networkplumber.org, cunming.liang@intel.com, xiuchun.lu@intel.com,\n miao.li@intel.com, jingjing.wu@intel.com",
        "Date": "Fri, 18 Dec 2020 15:38:44 +0800",
        "Message-Id": "<20201218073851.93609-3-chenbo.xia@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20201218073851.93609-1-chenbo.xia@intel.com>",
        "References": "<20201218073851.93609-1-chenbo.xia@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 2/9] vfio_user: implement lifecycle related APIs",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch implements three lifecycle related APIs for vfio-user server,\nwhich are rte_vfio_user_register(), rte_vfio_user_unregister() and\nrte_vfio_user_start(). Socket an device management is implemented\nalong with the API introduction.\n\nSigned-off-by: Chenbo Xia <chenbo.xia@intel.com>\nSigned-off-by: Xiuchun Lu <xiuchun.lu@intel.com>\n---\n lib/librte_vfio_user/meson.build        |   3 +-\n lib/librte_vfio_user/rte_vfio_user.h    |  51 ++\n lib/librte_vfio_user/version.map        |   6 +\n lib/librte_vfio_user/vfio_user_base.h   |   4 +\n lib/librte_vfio_user/vfio_user_server.c | 690 ++++++++++++++++++++++++\n lib/librte_vfio_user/vfio_user_server.h |  55 ++\n 6 files changed, 808 insertions(+), 1 deletion(-)\n create mode 100644 lib/librte_vfio_user/rte_vfio_user.h\n create mode 100644 lib/librte_vfio_user/vfio_user_server.c\n create mode 100644 lib/librte_vfio_user/vfio_user_server.h",
    "diff": "diff --git a/lib/librte_vfio_user/meson.build b/lib/librte_vfio_user/meson.build\nindex 0f6407b80f..b7363f61c6 100644\n--- a/lib/librte_vfio_user/meson.build\n+++ b/lib/librte_vfio_user/meson.build\n@@ -6,4 +6,5 @@ if not is_linux\n \treason = 'only supported on Linux'\n endif\n \n-sources = files('vfio_user_base.c')\n+sources = files('vfio_user_base.c', 'vfio_user_server.c')\n+headers = files('rte_vfio_user.h')\ndiff --git a/lib/librte_vfio_user/rte_vfio_user.h b/lib/librte_vfio_user/rte_vfio_user.h\nnew file mode 100644\nindex 0000000000..0d4f6c1be2\n--- /dev/null\n+++ b/lib/librte_vfio_user/rte_vfio_user.h\n@@ -0,0 +1,51 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#ifndef _RTE_VFIO_USER_H\n+#define _RTE_VFIO_USER_H\n+\n+#include <rte_compat.h>\n+\n+/**\n+ *  Below APIs are for vfio-user server (device provider) to use:\n+ *\t*rte_vfio_user_register\n+ *\t*rte_vfio_user_unregister\n+ *\t*rte_vfio_user_start\n+ */\n+\n+/**\n+ * Register a vfio-user device.\n+ *\n+ * @param sock_addr\n+ *   Unix domain socket address\n+ * @return\n+ *   0 on success, -1 on failure\n+ */\n+__rte_experimental\n+int rte_vfio_user_register(const char *sock_addr);\n+\n+/**\n+ * Unregister a vfio-user device.\n+ *\n+ * @param sock_addr\n+ *   Unix domain socket address\n+ * @return\n+ *   0 on success, -1 on failure\n+ */\n+__rte_experimental\n+int rte_vfio_user_unregister(const char *sock_addr);\n+\n+/**\n+ * Start vfio-user handling for the device.\n+ *\n+ * This function triggers vfio-user message handling.\n+ * @param sock_addr\n+ *   Unix domain socket address\n+ * @return\n+ *   0 on success, -1 on failure\n+ */\n+__rte_experimental\n+int rte_vfio_user_start(const char *sock_addr);\n+\n+#endif\ndiff --git a/lib/librte_vfio_user/version.map b/lib/librte_vfio_user/version.map\nindex 33c1b976f1..e53095eda8 100644\n--- a/lib/librte_vfio_user/version.map\n+++ b/lib/librte_vfio_user/version.map\n@@ -1,3 +1,9 @@\n EXPERIMENTAL {\n+\tglobal:\n+\n+\trte_vfio_user_register;\n+\trte_vfio_user_unregister;\n+\trte_vfio_user_start;\n+\n \tlocal: *;\n };\ndiff --git a/lib/librte_vfio_user/vfio_user_base.h b/lib/librte_vfio_user/vfio_user_base.h\nindex 6db45b1819..926cecfa7a 100644\n--- a/lib/librte_vfio_user/vfio_user_base.h\n+++ b/lib/librte_vfio_user/vfio_user_base.h\n@@ -7,6 +7,10 @@\n \n #include <rte_log.h>\n \n+#include \"rte_vfio_user.h\"\n+\n+#define VFIO_USER_VERSION_MAJOR 1\n+#define VFIO_USER_VERSION_MINOR 0\n #define VFIO_USER_MAX_FD 1024\n #define VFIO_USER_MAX_VERSION_DATA 512\n \ndiff --git a/lib/librte_vfio_user/vfio_user_server.c b/lib/librte_vfio_user/vfio_user_server.c\nnew file mode 100644\nindex 0000000000..545c779fb0\n--- /dev/null\n+++ b/lib/librte_vfio_user/vfio_user_server.c\n@@ -0,0 +1,690 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#include <unistd.h>\n+#include <fcntl.h>\n+#include <pthread.h>\n+#include <sys/socket.h>\n+#include <sys/un.h>\n+\n+#include \"vfio_user_server.h\"\n+\n+#define MAX_VFIO_USER_DEVICE 1024\n+\n+static struct vfio_user_server *vfio_user_devices[MAX_VFIO_USER_DEVICE];\n+static pthread_mutex_t vfio_dev_mutex = PTHREAD_MUTEX_INITIALIZER;\n+\n+static struct vfio_user_ep_sock vfio_ep_sock = {\n+\t.ep = {\n+\t\t.fd_mutex = PTHREAD_MUTEX_INITIALIZER,\n+\t\t.fd_num = 0\n+\t},\n+\t.sock_num = 0,\n+\t.mutex = PTHREAD_MUTEX_INITIALIZER,\n+};\n+\n+static int vfio_user_negotiate_version(struct vfio_user_server *dev,\n+\tVFIO_USER_MSG *msg)\n+{\n+\tstruct vfio_user_version *ver = &msg->payload.ver;\n+\n+\tif (vfio_user_check_msg_fdnum(msg, 0) != 0)\n+\t\treturn -EINVAL;\n+\n+\tif (ver->major == dev->ver.major && ver->minor <= dev->ver.minor)\n+\t\treturn 0;\n+\telse\n+\t\treturn -ENOTSUP;\n+}\n+\n+static vfio_user_msg_handler_t vfio_user_msg_handlers[VFIO_USER_MAX] = {\n+\t[VFIO_USER_NONE] = NULL,\n+\t[VFIO_USER_VERSION] = vfio_user_negotiate_version,\n+};\n+\n+static struct vfio_user_server_socket *\n+find_vfio_user_socket(const char *sock_addr)\n+{\n+\tuint32_t i;\n+\n+\tif (sock_addr == NULL)\n+\t\treturn NULL;\n+\n+\tfor (i = 0; i < vfio_ep_sock.sock_num; i++) {\n+\t\tstruct vfio_user_server_socket *s = vfio_ep_sock.sock[i];\n+\n+\t\tif (!strcmp(s->sock.sock_addr, sock_addr))\n+\t\t\treturn s;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static struct vfio_user_server_socket *\n+vfio_user_create_sock(const char *sock_addr)\n+{\n+\tstruct vfio_user_server_socket *sk;\n+\tstruct vfio_user_socket *sock;\n+\tint fd;\n+\tstruct sockaddr_un *un;\n+\n+\tpthread_mutex_lock(&vfio_ep_sock.mutex);\n+\tif (vfio_ep_sock.sock_num == VFIO_USER_MAX_FD) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to create socket:\"\n+\t\t\t\" socket num reaches max\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tsk = find_vfio_user_socket(sock_addr);\n+\tif (sk) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to create socket:\"\n+\t\t\t\"socket addr exists\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tsk = malloc(sizeof(*sk));\n+\tif (!sk) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to alloc server socket\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tsock = &sk->sock;\n+\tsock->sock_addr = strdup(sock_addr);\n+\tif (!sock->sock_addr) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to copy sock_addr\\n\");\n+\t\tgoto err_dup;\n+\t}\n+\n+\tfd = socket(AF_UNIX, SOCK_STREAM, 0);\n+\tif (fd < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to create socket\\n\");\n+\t\tgoto err_sock;\n+\t}\n+\n+\tif (fcntl(fd, F_SETFL, O_NONBLOCK)) {\n+\t\tVFIO_USER_LOG(ERR, \"can't set nonblocking mode for socket, \"\n+\t\t\t\"fd: %d (%s)\\n\", fd, strerror(errno));\n+\t\tgoto err_fcntl;\n+\t}\n+\n+\tun = &sk->un;\n+\tmemset(un, 0, sizeof(*un));\n+\tun->sun_family = AF_UNIX;\n+\tstrncpy(un->sun_path, sock->sock_addr, sizeof(un->sun_path));\n+\tun->sun_path[sizeof(un->sun_path) - 1] = '\\0';\n+\tsock->sock_fd = fd;\n+\tsk->conn_fd = -1;\n+\n+\tvfio_ep_sock.sock[vfio_ep_sock.sock_num++] = sk;\n+\n+\tpthread_mutex_unlock(&vfio_ep_sock.mutex);\n+\n+\treturn sk;\n+\n+err_fcntl:\n+\tclose(fd);\n+err_sock:\n+\tfree(sock->sock_addr);\n+err_dup:\n+\tfree(sk);\n+err:\n+\tpthread_mutex_unlock(&vfio_ep_sock.mutex);\n+\treturn NULL;\n+}\n+\n+static void vfio_user_delete_sock(struct vfio_user_server_socket *sk)\n+{\n+\tuint32_t i, end;\n+\tstruct vfio_user_socket *sock;\n+\n+\tif (!sk)\n+\t\treturn;\n+\n+\tpthread_mutex_lock(&vfio_ep_sock.mutex);\n+\n+\tfor (i = 0; i < vfio_ep_sock.sock_num; i++) {\n+\t\tif (vfio_ep_sock.sock[i] == sk)\n+\t\t\tbreak;\n+\t}\n+\n+\tsock = &sk->sock;\n+\tend = --vfio_ep_sock.sock_num;\n+\tvfio_ep_sock.sock[i] = vfio_ep_sock.sock[end];\n+\tvfio_ep_sock.sock[end] = NULL;\n+\n+\tfree(sock->sock_addr);\n+\tclose(sock->sock_fd);\n+\tif (sk->conn_fd != -1)\n+\t\tclose(sk->conn_fd);\n+\tunlink(sock->sock_addr);\n+\tfree(sk);\n+\n+\tpthread_mutex_unlock(&vfio_ep_sock.mutex);\n+}\n+\n+static inline int vfio_user_init_epoll(struct vfio_user_epoll *ep)\n+{\n+\tint epfd = epoll_create(1);\n+\tif (epfd < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to create epoll fd\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tep->epfd = epfd;\n+\treturn 0;\n+}\n+\n+static inline void vfio_user_destroy_epoll(struct vfio_user_epoll *ep)\n+{\n+\tclose(ep->epfd);\n+\tep->epfd = -1;\n+}\n+\n+static int vfio_user_add_listen_fd(struct vfio_user_epoll *ep,\n+\tint sock_fd, event_handler evh, void *data)\n+{\n+\tstruct epoll_event evt;\n+\tint ret = 0;\n+\tuint32_t event = EPOLLIN | EPOLLPRI;\n+\n+\tpthread_mutex_lock(&ep->fd_mutex);\n+\n+\tevt.events = event;\n+\tevt.data.ptr = &ep->fdinfo[ep->fd_num];\n+\n+\tif (ep->fd_num >= VFIO_USER_MAX_FD) {\n+\t\tVFIO_USER_LOG(ERR, \"Error add listen fd, \"\n+\t\t\t\"exceed max num\\n\");\n+\t\tret = -1;\n+\t\tgoto err;\n+\t}\n+\n+\tep->fdinfo[ep->fd_num].fd = sock_fd;\n+\tep->fdinfo[ep->fd_num].event = event;\n+\tep->fdinfo[ep->fd_num].ev_handle = evh;\n+\tep->fdinfo[ep->fd_num].data = data;\n+\n+\tif (epoll_ctl(ep->epfd, EPOLL_CTL_ADD, sock_fd, &evt) < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Error add listen fd, \"\n+\t\t\t\"epoll_ctl failed\\n\");\n+\t\tret = -1;\n+\t\tgoto err;\n+\t}\n+\n+\tep->fd_num++;\n+err:\n+\tpthread_mutex_unlock(&ep->fd_mutex);\n+\treturn ret;\n+}\n+\n+static int vfio_user_del_listen_fd(struct vfio_user_epoll *ep,\n+\tint sock_fd)\n+{\n+\tstruct epoll_event evt;\n+\tuint32_t event = EPOLLIN | EPOLLPRI;\n+\tuint32_t i;\n+\tint ret = 0;\n+\n+\tpthread_mutex_lock(&ep->fd_mutex);\n+\n+\tfor (i = 0; i < ep->fd_num; i++) {\n+\t\tif (ep->fdinfo[i].fd == sock_fd) {\n+\t\t\tep->fdinfo[i].fd = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tevt.events = event;\n+\tevt.data.ptr = &ep->fdinfo[i];\n+\n+\tif (epoll_ctl(ep->epfd, EPOLL_CTL_DEL, sock_fd, &evt) < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Error del listen fd, \"\n+\t\t\t\"epoll_ctl failed\\n\");\n+\t\tret = -1;\n+\t}\n+\n+\tpthread_mutex_unlock(&ep->fd_mutex);\n+\treturn ret;\n+}\n+\n+static inline int next_mv_src_idx(FD_INFO *info, int end)\n+{\n+\tint i;\n+\n+\tfor (i = end; i >= 0 && info[i].fd == -1; i--)\n+\t\t;\n+\n+\treturn i;\n+}\n+\n+static void vfio_user_fd_cleanup(struct vfio_user_epoll *ep)\n+{\n+\tint mv_src_idx, mv_dst_idx;\n+\tif (ep->fd_num != 0) {\n+\t\tpthread_mutex_lock(&ep->fd_mutex);\n+\n+\t\tmv_src_idx = next_mv_src_idx(ep->fdinfo, ep->fd_num - 1);\n+\t\tfor (mv_dst_idx = 0; mv_dst_idx < mv_src_idx; mv_dst_idx++) {\n+\t\t\tif (ep->fdinfo[mv_dst_idx].fd != -1)\n+\t\t\t\tcontinue;\n+\t\t\tep->fdinfo[mv_dst_idx] = ep->fdinfo[mv_src_idx];\n+\t\t\tmv_src_idx = next_mv_src_idx(ep->fdinfo,\n+\t\t\t\tmv_src_idx - 1);\n+\t\t}\n+\t\tep->fd_num = mv_src_idx + 1;\n+\n+\t\tpthread_mutex_unlock(&ep->fd_mutex);\n+\t}\n+}\n+\n+static void *vfio_user_fd_event_handler(void *arg)\n+{\n+\tstruct vfio_user_epoll *ep = arg;\n+\tstruct epoll_event *events;\n+\tint num_fd, i, ret, cleanup;\n+\tevent_handler evh;\n+\tFD_INFO *info;\n+\n+\twhile (1) {\n+\t\tevents = ep->events;\n+\t\tnum_fd = epoll_wait(ep->epfd, events,\n+\t\t\tVFIO_USER_MAX_FD, 1000);\n+\t\tif (num_fd <= 0)\n+\t\t\tcontinue;\n+\t\tcleanup = 0;\n+\n+\t\tfor (i = 0; i < num_fd; i++) {\n+\t\t\tinfo = (FD_INFO *)events[i].data.ptr;\n+\t\t\tevh = info->ev_handle;\n+\n+\t\t\tif (evh) {\n+\t\t\t\tret = evh(info->fd, info->data);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\tinfo->fd = -1;\n+\t\t\t\t\tcleanup = 1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (cleanup)\n+\t\t\tvfio_user_fd_cleanup(ep);\n+\t}\n+\treturn NULL;\n+}\n+\n+static inline int vfio_user_add_device(void)\n+{\n+\tstruct vfio_user_server *dev;\n+\tint i;\n+\n+\tpthread_mutex_lock(&vfio_dev_mutex);\n+\tfor (i = 0; i < MAX_VFIO_USER_DEVICE; i++) {\n+\t\tif (vfio_user_devices[i] == NULL)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (i == MAX_VFIO_USER_DEVICE) {\n+\t\tVFIO_USER_LOG(ERR, \"vfio user device num reaches max!\\n\");\n+\t\ti = -1;\n+\t\tgoto exit;\n+\t}\n+\n+\tdev = malloc(sizeof(struct vfio_user_server));\n+\tif (dev == NULL) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to alloc new vfio-user dev.\\n\");\n+\t\ti = -1;\n+\t\tgoto exit;\n+\t}\n+\n+\tmemset(dev, 0, sizeof(struct vfio_user_server));\n+\tvfio_user_devices[i] = dev;\n+\tdev->dev_id = i;\n+\tdev->conn_fd = -1;\n+\n+exit:\n+\tpthread_mutex_unlock(&vfio_dev_mutex);\n+\treturn i;\n+}\n+\n+static inline void vfio_user_del_device(struct vfio_user_server *dev)\n+{\n+\tif (dev == NULL)\n+\t\treturn;\n+\n+\tpthread_mutex_lock(&vfio_dev_mutex);\n+\tvfio_user_devices[dev->dev_id] = NULL;\n+\tfree(dev);\n+\tpthread_mutex_unlock(&vfio_dev_mutex);\n+}\n+\n+static inline struct vfio_user_server *vfio_user_get_device(int dev_id)\n+{\n+\tstruct vfio_user_server *dev;\n+\n+\tpthread_mutex_lock(&vfio_dev_mutex);\n+\tdev = vfio_user_devices[dev_id];\n+\tif (!dev)\n+\t\tVFIO_USER_LOG(ERR, \"Device %d not found.\\n\", dev_id);\n+\tpthread_mutex_unlock(&vfio_dev_mutex);\n+\n+\treturn dev;\n+}\n+\n+static int vfio_user_message_handler(int dev_id, int fd)\n+{\n+\tstruct vfio_user_server *dev;\n+\tVFIO_USER_MSG msg;\n+\tuint32_t cmd;\n+\tint ret = 0;\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\tif (!dev)\n+\t\treturn -1;\n+\n+\tret = vfio_user_recv_msg(fd, &msg);\n+\tif (ret <= 0) {\n+\t\tif (ret < 0)\n+\t\t\tVFIO_USER_LOG(ERR, \"Read message failed\\n\");\n+\t\telse\n+\t\t\tVFIO_USER_LOG(ERR, \"Peer closed\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (msg.msg_id != dev->msg_id)\n+\t\treturn -1;\n+\tret = 0;\n+\tcmd = msg.cmd;\n+\tdev->msg_id++;\n+\tif (cmd > VFIO_USER_NONE && cmd < VFIO_USER_MAX &&\n+\t\t\tvfio_user_msg_str[cmd]) {\n+\t\tVFIO_USER_LOG(INFO, \"Read message %s\\n\",\n+\t\t\tvfio_user_msg_str[cmd]);\n+\t} else {\n+\t\tVFIO_USER_LOG(ERR, \"Read unknown message\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (vfio_user_msg_handlers[cmd])\n+\t\tret = vfio_user_msg_handlers[cmd](dev, &msg);\n+\telse {\n+\t\tVFIO_USER_LOG(ERR, \"Handler not defined for %s\\n\",\n+\t\t\tvfio_user_msg_str[cmd]);\n+\t\tret = -1;\n+\t\tgoto handle_end;\n+\t}\n+\n+\tif (!(msg.flags & VFIO_USER_NEED_NO_RP)) {\n+\t\tif (ret < 0) {\n+\t\t\tmsg.flags |= VFIO_USER_ERROR;\n+\t\t\tmsg.err = -ret;\n+\t\t\t/* If an error occurs, the reply message must\n+\t\t\t * only include the reply header.\n+\t\t\t */\n+\t\t\tmsg.size = VFIO_USER_MSG_HDR_SIZE;\n+\t\t\tVFIO_USER_LOG(ERR, \"Handle status error(%d) for %s\\n\",\n+\t\t\t\tret, vfio_user_msg_str[cmd]);\n+\t\t}\n+\n+\t\tret = vfio_user_reply_msg(fd, &msg);\n+\t\tif (ret < 0) {\n+\t\t\tVFIO_USER_LOG(ERR, \"Reply error for %s\\n\",\n+\t\t\t\tvfio_user_msg_str[cmd]);\n+\t\t} else {\n+\t\t\tVFIO_USER_LOG(INFO, \"Reply %s succeeds\\n\",\n+\t\t\t\tvfio_user_msg_str[cmd]);\n+\t\t\tret = 0;\n+\t\t}\n+\t}\n+\n+handle_end:\n+\treturn ret;\n+}\n+\n+static int vfio_user_sock_read(int fd, void *data)\n+{\n+\tstruct vfio_user_server_socket *sk = data;\n+\tint ret, dev_id = sk->sock.dev_id;\n+\n+\tret = vfio_user_message_handler(dev_id, fd);\n+\tif (ret < 0) {\n+\t\tstruct vfio_user_server *dev;\n+\n+\t\tvfio_user_del_listen_fd(&vfio_ep_sock.ep, sk->conn_fd);\n+\t\tclose(fd);\n+\t\tsk->conn_fd = -1;\n+\t\tdev = vfio_user_get_device(dev_id);\n+\t\tif (dev)\n+\t\t\tdev->msg_id = 0;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static void\n+vfio_user_set_ifname(int dev_id, const char *sock_addr, unsigned int size)\n+{\n+\tstruct vfio_user_server *dev;\n+\tunsigned int len;\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\tif (!dev)\n+\t\treturn;\n+\n+\tlen = size > sizeof(dev->sock_addr) ?\n+\t\tsizeof(dev->sock_addr) : size;\n+\tstrncpy(dev->sock_addr, sock_addr, len);\n+\tdev->sock_addr[len] = '\\0';\n+}\n+\n+static int\n+vfio_user_add_new_connection(int fd, void *data)\n+{\n+\tstruct vfio_user_server *dev;\n+\tint dev_id;\n+\tsize_t size;\n+\tstruct vfio_user_server_socket *sk = data;\n+\tstruct vfio_user_socket *sock = &sk->sock;\n+\tint conn_fd;\n+\tint ret;\n+\n+\tif (sk->conn_fd != -1)\n+\t\treturn 0;\n+\n+\tconn_fd = accept(fd, NULL, NULL);\n+\tif (fd < 0)\n+\t\treturn -1;\n+\n+\tVFIO_USER_LOG(INFO, \"New vfio-user client(%s) connected\\n\",\n+\t\tsock->sock_addr);\n+\n+\tif (sock == NULL)\n+\t\treturn -1;\n+\n+\tdev_id = sock->dev_id;\n+\tsk->conn_fd = conn_fd;\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\tif (!dev)\n+\t\treturn -1;\n+\n+\tdev->conn_fd = conn_fd;\n+\n+\tsize = strnlen(sock->sock_addr, PATH_MAX);\n+\tvfio_user_set_ifname(dev_id, sock->sock_addr, size);\n+\n+\tret = vfio_user_add_listen_fd(&vfio_ep_sock.ep,\n+\t\tconn_fd, vfio_user_sock_read, sk);\n+\tif (ret < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to add fd %d into vfio server fdset\\n\",\n+\t\t\tconn_fd);\n+\t\tgoto err_cleanup;\n+\t}\n+\n+\treturn 0;\n+\n+err_cleanup:\n+\tclose(fd);\n+\treturn -1;\n+}\n+\n+static int\n+vfio_user_start_server(struct vfio_user_server_socket *sk)\n+{\n+\tstruct vfio_user_server *dev;\n+\tint ret;\n+\tstruct vfio_user_socket *sock = &sk->sock;\n+\tint fd = sock->sock_fd;\n+\tconst char *path = sock->sock_addr;\n+\n+\tdev = vfio_user_get_device(sock->dev_id);\n+\tif (!dev) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to start, \"\n+\t\t\t\"device not found\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (dev->started) {\n+\t\tVFIO_USER_LOG(INFO, \"device already started\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\tunlink(path);\n+\tret = bind(fd, (struct sockaddr *)&sk->un, sizeof(sk->un));\n+\tif (ret < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"failed to bind to %s: %s;\"\n+\t\t\t\"remove it and try again\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\tgoto err;\n+\t}\n+\n+\tret = listen(fd, 128);\n+\tif (ret < 0)\n+\t\tgoto err;\n+\n+\tret = vfio_user_add_listen_fd(&vfio_ep_sock.ep,\n+\t\tfd, vfio_user_add_new_connection, (void *)sk);\n+\tif (ret < 0) {\n+\t\tVFIO_USER_LOG(ERR, \"failed to add listen fd %d to \"\n+\t\t\t\"vfio-user server fdset\\n\", fd);\n+\t\tgoto err;\n+\t}\n+\n+\tdev->started = 1;\n+\n+\treturn 0;\n+\n+err:\n+\tclose(fd);\n+\treturn -1;\n+}\n+\n+int rte_vfio_user_register(const char *sock_addr)\n+{\n+\tstruct vfio_user_server_socket *sk;\n+\tstruct vfio_user_server *dev;\n+\tint dev_id;\n+\n+\tif (!sock_addr)\n+\t\treturn -1;\n+\n+\tsk = vfio_user_create_sock(sock_addr);\n+\tif (!sk) {\n+\t\tVFIO_USER_LOG(ERR, \"Create socket failed\\n\");\n+\t\tgoto exit;\n+\t}\n+\n+\tdev_id = vfio_user_add_device();\n+\tif (dev_id == -1) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to add new vfio device\\n\");\n+\t\tgoto err_add_dev;\n+\t}\n+\tsk->sock.dev_id = dev_id;\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\n+\tdev->ver.major = VFIO_USER_VERSION_MAJOR;\n+\tdev->ver.minor = VFIO_USER_VERSION_MINOR;\n+\n+\treturn 0;\n+\n+err_add_dev:\n+\tvfio_user_delete_sock(sk);\n+exit:\n+\treturn -1;\n+}\n+\n+int rte_vfio_user_unregister(const char *sock_addr)\n+{\n+\tstruct vfio_user_server_socket *sk;\n+\tstruct vfio_user_server *dev;\n+\tint dev_id;\n+\n+\tpthread_mutex_lock(&vfio_ep_sock.mutex);\n+\tsk = find_vfio_user_socket(sock_addr);\n+\tpthread_mutex_unlock(&vfio_ep_sock.mutex);\n+\n+\tif (!sk) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to unregister:\"\n+\t\t\t\"socket addr not registered.\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tdev_id = sk->sock.dev_id;\n+\t/* Client may already disconnect before unregistration */\n+\tif (sk->conn_fd != -1)\n+\t\tvfio_user_del_listen_fd(&vfio_ep_sock.ep, sk->conn_fd);\n+\tvfio_user_del_listen_fd(&vfio_ep_sock.ep, sk->sock.sock_fd);\n+\tvfio_user_fd_cleanup(&vfio_ep_sock.ep);\n+\tvfio_user_delete_sock(sk);\n+\n+\tdev = vfio_user_get_device(dev_id);\n+\tif (!dev) {\n+\t\tVFIO_USER_LOG(ERR, \"Failed to unregister:\"\n+\t\t\t\"device not found.\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tvfio_user_del_device(dev);\n+\n+\treturn 0;\n+}\n+\n+int rte_vfio_user_start(const char *sock_addr)\n+{\n+\tstatic pthread_t pid;\n+\tstruct vfio_user_server_socket *sock;\n+\n+\tpthread_mutex_lock(&vfio_ep_sock.mutex);\n+\n+\tsock = find_vfio_user_socket(sock_addr);\n+\tif (!sock) {\n+\t\tVFIO_USER_LOG(ERR, \"sock_addr not registered to vfio_user \"\n+\t\t\t\"before start\\n\");\n+\t\tgoto exit;\n+\t}\n+\n+\tif (pid == 0) {\n+\t\tstruct vfio_user_epoll *ep = &vfio_ep_sock.ep;\n+\n+\t\tif (vfio_user_init_epoll(ep)) {\n+\t\t\tVFIO_USER_LOG(ERR, \"Init vfio-user epoll failed\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (pthread_create(&pid, NULL,\n+\t\t\tvfio_user_fd_event_handler, ep)) {\n+\t\t\tvfio_user_destroy_epoll(ep);\n+\t\t\tVFIO_USER_LOG(ERR, \"Event handler thread create failed\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tpthread_mutex_unlock(&vfio_ep_sock.mutex);\n+\n+\treturn vfio_user_start_server(sock);\n+\n+exit:\n+\tpthread_mutex_unlock(&vfio_ep_sock.mutex);\n+\treturn -1;\n+}\ndiff --git a/lib/librte_vfio_user/vfio_user_server.h b/lib/librte_vfio_user/vfio_user_server.h\nnew file mode 100644\nindex 0000000000..00e3f6353d\n--- /dev/null\n+++ b/lib/librte_vfio_user/vfio_user_server.h\n@@ -0,0 +1,55 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#ifndef _VFIO_USER_SERVER_H\n+#define _VFIO_USER_SERVER_H\n+\n+#include <sys/epoll.h>\n+\n+#include \"vfio_user_base.h\"\n+\n+struct vfio_user_server {\n+\tint dev_id;\n+\tint started;\n+\tint conn_fd;\n+\tuint32_t msg_id;\n+\tchar sock_addr[PATH_MAX];\n+\tstruct vfio_user_version ver;\n+};\n+\n+typedef int (*event_handler)(int fd, void *data);\n+\n+typedef struct listen_fd_info {\n+\tint fd;\n+\tuint32_t event;\n+\tevent_handler ev_handle;\n+\tvoid *data;\n+} FD_INFO;\n+\n+struct vfio_user_epoll {\n+\tint epfd;\n+\tFD_INFO fdinfo[VFIO_USER_MAX_FD];\n+\tuint32_t fd_num;\t/* Current num of listen_fd */\n+\tstruct epoll_event events[VFIO_USER_MAX_FD];\n+\tpthread_mutex_t fd_mutex;\n+};\n+\n+struct vfio_user_server_socket {\n+\tstruct vfio_user_socket sock;\n+\tstruct sockaddr_un un;\n+\t/* For vfio-user protocol v0.1, a server only supports one client */\n+\tint conn_fd;\n+};\n+\n+struct vfio_user_ep_sock {\n+\tstruct vfio_user_epoll ep;\n+\tstruct vfio_user_server_socket *sock[VFIO_USER_MAX_FD];\n+\tuint32_t sock_num;\n+\tpthread_mutex_t mutex;\n+};\n+\n+typedef int (*vfio_user_msg_handler_t)(struct vfio_user_server *dev,\n+\t\t\t\t\tVFIO_USER_MSG *msg);\n+\n+#endif\n",
    "prefixes": [
        "2/9"
    ]
}