From patchwork Wed Mar 17 20:25:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 89412 X-Patchwork-Delegate: maxime.coquelin@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id B5379A0562; Wed, 17 Mar 2021 21:25:48 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 233A6140F57; Wed, 17 Mar 2021 21:25:47 +0100 (CET) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by mails.dpdk.org (Postfix) with ESMTP id B99B8140F55; Wed, 17 Mar 2021 21:25:45 +0100 (CET) X-Originating-IP: 78.45.89.65 Received: from im-t490s.redhat.com (ip-78-45-89-65.net.upcbroadband.cz [78.45.89.65]) (Authenticated sender: i.maximets@ovn.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id E701A60007; Wed, 17 Mar 2021 20:25:43 +0000 (UTC) From: Ilya Maximets To: Maxime Coquelin Cc: Chenbo Xia , dev@dpdk.org, Adrian Moreno , Stefan Hajnoczi , Julia Suvorova , Ilya Maximets , stable@dpdk.org, Zhiyong Yang Date: Wed, 17 Mar 2021 21:25:27 +0100 Message-Id: <20210317202530.4145673-2-i.maximets@ovn.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210317202530.4145673-1-i.maximets@ovn.org> References: <20210317202530.4145673-1-i.maximets@ovn.org> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 1/4] net/virtio: fix interrupt unregistering for listening socket X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" virtio_user_dev_server_reconnect() is typically called from the interrupt context while checking the link state: vhost_user_update_link_state() --> virtio_user_dev_server_reconnect() Under this conditions callback unregistering always fails. This means that listenfd is never unregistered and continue to trigger interrupts. For example, if second client will try to connect to the same socket, the server will receive interrupts infinitely because it will not accept them while listen fd is readable and generates epoll events. Fix that by moving reconfiguration of interrupts out of the interrupt context to alarm handler. 'virtio_user_dev_delayed_handler' renamed to 'virtio_user_dev_delayed_disconnect_handler' to better reflect its purpose. Additionally improved error logging around interrupt management. Fixes: bd8f50a45d0f ("net/virtio-user: support server mode") Cc: stable@dpdk.org Signed-off-by: Ilya Maximets Reviewed-by: Maxime Coquelin --- CC: Zhiyong Yang drivers/net/virtio/virtio_user/vhost_user.c | 4 +- .../net/virtio/virtio_user/virtio_user_dev.c | 70 ++++++++++++++----- .../net/virtio/virtio_user/virtio_user_dev.h | 2 +- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/drivers/net/virtio/virtio_user/vhost_user.c b/drivers/net/virtio/virtio_user/vhost_user.c index f8569f6e6f..25f74c625b 100644 --- a/drivers/net/virtio/virtio_user/vhost_user.c +++ b/drivers/net/virtio/virtio_user/vhost_user.c @@ -957,7 +957,9 @@ vhost_user_update_link_state(struct virtio_user_dev *dev) * of interrupt handling, callback cannot be * unregistered here, set an alarm to do it. */ - rte_eal_alarm_set(1, virtio_user_dev_delayed_handler, (void *)dev); + rte_eal_alarm_set(1, + virtio_user_dev_delayed_disconnect_handler, + (void *)dev); } else { dev->net_status |= VIRTIO_NET_S_LINK_UP; } diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c index 1b54d55bd8..68cece42d3 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.c +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -885,7 +886,7 @@ virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev) } void -virtio_user_dev_delayed_handler(void *param) +virtio_user_dev_delayed_disconnect_handler(void *param) { struct virtio_user_dev *dev = param; struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->port_id]; @@ -894,14 +895,27 @@ virtio_user_dev_delayed_handler(void *param) PMD_DRV_LOG(ERR, "interrupt disable failed"); return; } - rte_intr_callback_unregister(eth_dev->intr_handle, - virtio_interrupt_handler, eth_dev); + PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", + eth_dev->intr_handle->fd); + if (rte_intr_callback_unregister(eth_dev->intr_handle, + virtio_interrupt_handler, + eth_dev) != 1) + PMD_DRV_LOG(ERR, "interrupt unregister failed"); + if (dev->is_server) { if (dev->ops->server_disconnect) dev->ops->server_disconnect(dev); + eth_dev->intr_handle->fd = dev->ops->get_intr_fd(dev); - rte_intr_callback_register(eth_dev->intr_handle, - virtio_interrupt_handler, eth_dev); + + PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", + eth_dev->intr_handle->fd); + + if (rte_intr_callback_register(eth_dev->intr_handle, + virtio_interrupt_handler, + eth_dev)) + PMD_DRV_LOG(ERR, "interrupt register failed"); + if (rte_intr_enable(eth_dev->intr_handle) < 0) { PMD_DRV_LOG(ERR, "interrupt enable failed"); return; @@ -909,6 +923,32 @@ virtio_user_dev_delayed_handler(void *param) } } +static void +virtio_user_dev_delayed_intr_reconfig_handler(void *param) +{ + struct virtio_user_dev *dev = param; + struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->port_id]; + + PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", + eth_dev->intr_handle->fd); + + if (rte_intr_callback_unregister(eth_dev->intr_handle, + virtio_interrupt_handler, + eth_dev) != 1) + PMD_DRV_LOG(ERR, "interrupt unregister failed"); + + eth_dev->intr_handle->fd = dev->ops->get_intr_fd(dev); + + PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", eth_dev->intr_handle->fd); + + if (rte_intr_callback_register(eth_dev->intr_handle, + virtio_interrupt_handler, eth_dev)) + PMD_DRV_LOG(ERR, "interrupt register failed"); + + if (rte_intr_enable(eth_dev->intr_handle) < 0) + PMD_DRV_LOG(ERR, "interrupt enable failed"); +} + int virtio_user_dev_server_reconnect(struct virtio_user_dev *dev) { @@ -974,18 +1014,14 @@ virtio_user_dev_server_reconnect(struct virtio_user_dev *dev) PMD_DRV_LOG(ERR, "interrupt disable failed"); return -1; } - rte_intr_callback_unregister(eth_dev->intr_handle, - virtio_interrupt_handler, - eth_dev); - - eth_dev->intr_handle->fd = dev->ops->get_intr_fd(dev); - rte_intr_callback_register(eth_dev->intr_handle, - virtio_interrupt_handler, eth_dev); - - if (rte_intr_enable(eth_dev->intr_handle) < 0) { - PMD_DRV_LOG(ERR, "interrupt enable failed"); - return -1; - } + /* + * This function can be called from the interrupt handler, so + * we can't unregister interrupt handler here. Setting + * alarm to do that later. + */ + rte_eal_alarm_set(1, + virtio_user_dev_delayed_intr_reconfig_handler, + (void *)dev); } PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!"); return 0; diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h index 8a62f7ea79..15d177ccd2 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.h +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h @@ -78,7 +78,7 @@ uint8_t virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs); int virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status); int virtio_user_dev_update_status(struct virtio_user_dev *dev); int virtio_user_dev_update_link_state(struct virtio_user_dev *dev); -void virtio_user_dev_delayed_handler(void *param); +void virtio_user_dev_delayed_disconnect_handler(void *param); int virtio_user_dev_server_reconnect(struct virtio_user_dev *dev); extern const char * const virtio_user_backend_strings[]; #endif From patchwork Wed Mar 17 20:25:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 89413 X-Patchwork-Delegate: maxime.coquelin@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5CE5DA0561; Wed, 17 Mar 2021 21:25:57 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 88D5F140F61; Wed, 17 Mar 2021 21:25:51 +0100 (CET) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by mails.dpdk.org (Postfix) with ESMTP id E8360140F61 for ; Wed, 17 Mar 2021 21:25:49 +0100 (CET) X-Originating-IP: 78.45.89.65 Received: from im-t490s.redhat.com (ip-78-45-89-65.net.upcbroadband.cz [78.45.89.65]) (Authenticated sender: i.maximets@ovn.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 749DA6000B; Wed, 17 Mar 2021 20:25:48 +0000 (UTC) From: Ilya Maximets To: Maxime Coquelin Cc: Chenbo Xia , dev@dpdk.org, Adrian Moreno , Stefan Hajnoczi , Julia Suvorova , Ilya Maximets Date: Wed, 17 Mar 2021 21:25:28 +0100 Message-Id: <20210317202530.4145673-3-i.maximets@ovn.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210317202530.4145673-1-i.maximets@ovn.org> References: <20210317202530.4145673-1-i.maximets@ovn.org> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC 2/4] vhost: add support for SocketPair Broker X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" New flag RTE_VHOST_USER_SOCKETPAIR_BROKER to say that provided socket is a path to SocketPair Broker socket in a following format: '/path/to/socketpair/broker.sock,broker-key=' This format is chosen to avoid lots of code changes and refactoring inside the vhost library, mainly because vhost library treats socket path as a unique device identifier. '' is a broker key that will be used by a broker to identify two clients that needs to be paired together, i.e. vhost device will be connected with a client that provided the same key. libspbroker needed for a build. Signed-off-by: Ilya Maximets --- doc/guides/prog_guide/vhost_lib.rst | 10 ++ lib/librte_vhost/meson.build | 7 + lib/librte_vhost/rte_vhost.h | 1 + lib/librte_vhost/socket.c | 245 +++++++++++++++++++++++++--- 4 files changed, 237 insertions(+), 26 deletions(-) diff --git a/doc/guides/prog_guide/vhost_lib.rst b/doc/guides/prog_guide/vhost_lib.rst index dc29229167..f0f0d3fde7 100644 --- a/doc/guides/prog_guide/vhost_lib.rst +++ b/doc/guides/prog_guide/vhost_lib.rst @@ -118,6 +118,16 @@ The following is an overview of some key Vhost API functions: It is disabled by default. + - ``RTE_VHOST_USER_SOCKETPAIR_BROKER`` + + Enabling of this flag makes vhost library to treat socket ``path`` as a + path to SocketPair Broker. In this case ``path`` should include + ``,broker-key=`` after the actual broker's socket path. ```` + will be used as a broker key, so it will be able to connect 2 processes + that provided the same key. + + Incompatible with ``RTE_VHOST_USER_NO_RECONNECT``. + * ``rte_vhost_driver_set_features(path, features)`` This function sets the feature bits the vhost-user driver supports. The diff --git a/lib/librte_vhost/meson.build b/lib/librte_vhost/meson.build index 6185deab33..3292edcb52 100644 --- a/lib/librte_vhost/meson.build +++ b/lib/librte_vhost/meson.build @@ -15,6 +15,13 @@ elif (toolchain == 'clang' and cc.version().version_compare('>=3.7.0')) elif (toolchain == 'icc' and cc.version().version_compare('>=16.0.0')) cflags += '-DVHOST_ICC_UNROLL_PRAGMA' endif + +spbroker_dep = dependency('spbroker', required: false) +if spbroker_dep.found() + dpdk_conf.set('RTE_LIBRTE_VHOST_SOCKETPAIR_BROKER', 1) + ext_deps += spbroker_dep +endif + dpdk_conf.set('RTE_LIBRTE_VHOST_POSTCOPY', cc.has_header('linux/userfaultfd.h')) cflags += '-fno-strict-aliasing' diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h index 010f160869..87662c9f7f 100644 --- a/lib/librte_vhost/rte_vhost.h +++ b/lib/librte_vhost/rte_vhost.h @@ -36,6 +36,7 @@ extern "C" { /* support only linear buffers (no chained mbufs) */ #define RTE_VHOST_USER_LINEARBUF_SUPPORT (1ULL << 6) #define RTE_VHOST_USER_ASYNC_COPY (1ULL << 7) +#define RTE_VHOST_USER_SOCKETPAIR_BROKER (1ULL << 8) /* Features. */ #ifndef VIRTIO_NET_F_GUEST_ANNOUNCE diff --git a/lib/librte_vhost/socket.c b/lib/librte_vhost/socket.c index 0169d36481..f0a1c9044c 100644 --- a/lib/librte_vhost/socket.c +++ b/lib/librte_vhost/socket.c @@ -16,6 +16,10 @@ #include #include +#ifdef RTE_LIBRTE_VHOST_SOCKETPAIR_BROKER +#include +#endif + #include #include "fd_man.h" @@ -33,9 +37,11 @@ struct vhost_user_socket { struct vhost_user_connection_list conn_list; pthread_mutex_t conn_mutex; char *path; + char *broker_key; int socket_fd; struct sockaddr_un un; bool is_server; + bool is_broker; bool reconnect; bool iommu_support; bool use_builtin_virtio_net; @@ -81,7 +87,8 @@ struct vhost_user { static void vhost_user_server_new_connection(int fd, void *data, int *remove); static void vhost_user_read_cb(int fd, void *dat, int *remove); static int create_unix_socket(struct vhost_user_socket *vsocket); -static int vhost_user_start_client(struct vhost_user_socket *vsocket); +static int recreate_unix_socket(struct vhost_user_socket *vsocket); +static int vhost_user_start(struct vhost_user_socket *vsocket); static struct vhost_user vhost_user = { .fdset = { @@ -283,6 +290,81 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket) close(fd); } +#ifdef RTE_LIBRTE_VHOST_SOCKETPAIR_BROKER +static int +vhost_user_broker_msg_handler(int fd, struct vhost_user_socket *vsocket) +{ + int peer_fd; + char *err; + + peer_fd = sp_broker_receive_set_pair(fd, &err); + if (peer_fd < 0) { + VHOST_LOG_CONFIG(ERR, + "failed to receive SP_BROKER_SET_PAIR on fd %d: %s\n", + fd, err); + free(err); + return -1; + } + + VHOST_LOG_CONFIG(INFO, "new vhost user connection is %d\n", peer_fd); + vhost_user_add_connection(peer_fd, vsocket); + return 0; +} + +static void +vhost_user_broker_msg_cb(int connfd, void *dat, int *remove) +{ + struct vhost_user_socket *vsocket = dat; + int ret; + + ret = vhost_user_broker_msg_handler(connfd, vsocket); + + /* Don't need a broker connection anymore. */ + *remove = 1; + + if (ret < 0) { + recreate_unix_socket(vsocket); + vhost_user_start(vsocket); + } +} + +static int +vhost_user_start_broker_connection( + int fd __rte_unused, + struct vhost_user_socket *vsocket __rte_unused) +{ + char *err; + int ret; + + ret = sp_broker_send_get_pair(fd, vsocket->broker_key, + vsocket->is_server, &err); + if (ret) { + VHOST_LOG_CONFIG(ERR, + "failed to send SP_BROKER_GET_PAIR request on fd %d: %s\n", + fd, err); + free(err); + return -1; + } + + ret = fdset_add(&vhost_user.fdset, fd, vhost_user_broker_msg_cb, + NULL, vsocket); + if (ret < 0) { + VHOST_LOG_CONFIG(ERR, + "failed to add broker fd %d to vhost fdset\n", fd); + return -1; + } + return 0; +} +#else +static int +vhost_user_start_broker_connection( + int fd __rte_unused, + struct vhost_user_socket *vsocket __rte_unused) +{ + return -1; +} +#endif + /* call back when there is new vhost-user connection from client */ static void vhost_user_server_new_connection(int fd, void *dat, int *remove __rte_unused) @@ -321,7 +403,7 @@ vhost_user_read_cb(int connfd, void *dat, int *remove) if (vsocket->reconnect) { create_unix_socket(vsocket); - vhost_user_start_client(vsocket); + vhost_user_start(vsocket); } pthread_mutex_lock(&vsocket->conn_mutex); @@ -337,14 +419,17 @@ create_unix_socket(struct vhost_user_socket *vsocket) { int fd; struct sockaddr_un *un = &vsocket->un; + char *broker_key = strstr(vsocket->path, ",broker-key="); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; - VHOST_LOG_CONFIG(INFO, "vhost-user %s: socket created, fd: %d\n", - vsocket->is_server ? "server" : "client", fd); + VHOST_LOG_CONFIG(INFO, "vhost-user %s: %ssocket created, fd: %d\n", + vsocket->is_server ? "server" : "client", + vsocket->is_broker ? "broker " : "", fd); - if (!vsocket->is_server && fcntl(fd, F_SETFL, O_NONBLOCK)) { + if ((!vsocket->is_server || vsocket->is_broker) + && fcntl(fd, F_SETFL, O_NONBLOCK)) { VHOST_LOG_CONFIG(ERR, "vhost-user: can't set nonblocking mode for socket, fd: " "%d (%s)\n", fd, strerror(errno)); @@ -352,12 +437,21 @@ create_unix_socket(struct vhost_user_socket *vsocket) return -1; } + /* Temporarily limiting the path by the actual path. */ + if (vsocket->is_broker && broker_key) + broker_key[0] = '\0'; + memset(un, 0, sizeof(*un)); un->sun_family = AF_UNIX; strncpy(un->sun_path, vsocket->path, sizeof(un->sun_path)); un->sun_path[sizeof(un->sun_path) - 1] = '\0'; vsocket->socket_fd = fd; + + /* Restoring original path. */ + if (vsocket->is_broker && broker_key) + broker_key[0] = ','; + return 0; } @@ -425,7 +519,8 @@ static struct vhost_user_reconnect_list reconn_list; static pthread_t reconn_tid; static int -vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz) +vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz, + bool disable_nonblock) { int ret, flags; @@ -433,6 +528,9 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz) if (ret < 0 && errno != EISCONN) return -1; + if (!disable_nonblock) + return 0; + flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { VHOST_LOG_CONFIG(ERR, @@ -447,8 +545,22 @@ vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz) return 0; } +static int +recreate_unix_socket(struct vhost_user_socket *vsocket) +{ + close(vsocket->socket_fd); + if (create_unix_socket(vsocket) < 0) { + VHOST_LOG_CONFIG(ERR, + "Failed to re-create socket for %s\n", + vsocket->un.sun_path); + vsocket->socket_fd = -1; + return -2; + } + return 0; +} + static void * -vhost_user_client_reconnect(void *arg __rte_unused) +vhost_user_reconnect(void *arg __rte_unused) { int ret; struct vhost_user_reconnect *reconn, *next; @@ -466,7 +578,8 @@ vhost_user_client_reconnect(void *arg __rte_unused) ret = vhost_user_connect_nonblock(reconn->fd, (struct sockaddr *)&reconn->un, - sizeof(reconn->un)); + sizeof(reconn->un), + !reconn->vsocket->is_broker); if (ret == -2) { close(reconn->fd); VHOST_LOG_CONFIG(ERR, @@ -478,8 +591,26 @@ vhost_user_client_reconnect(void *arg __rte_unused) continue; VHOST_LOG_CONFIG(INFO, - "%s: connected\n", reconn->vsocket->path); - vhost_user_add_connection(reconn->fd, reconn->vsocket); + "%s: connected\n", + reconn->vsocket->un.sun_path); + + if (reconn->vsocket->is_broker) { + struct vhost_user_socket *vsocket; + + vsocket = reconn->vsocket; + if (vhost_user_start_broker_connection( + reconn->fd, vsocket)) { + if (recreate_unix_socket(vsocket)) { + goto remove_fd; + } else { + reconn->fd = vsocket->socket_fd; + continue; + } + } + } else { + vhost_user_add_connection(reconn->fd, + reconn->vsocket); + } remove_fd: TAILQ_REMOVE(&reconn_list.head, reconn, next); free(reconn); @@ -505,7 +636,7 @@ vhost_user_reconnect_init(void) TAILQ_INIT(&reconn_list.head); ret = rte_ctrl_thread_create(&reconn_tid, "vhost_reconn", NULL, - vhost_user_client_reconnect, NULL); + vhost_user_reconnect, NULL); if (ret != 0) { VHOST_LOG_CONFIG(ERR, "failed to create reconnect thread"); if (pthread_mutex_destroy(&reconn_list.mutex)) { @@ -518,18 +649,25 @@ vhost_user_reconnect_init(void) } static int -vhost_user_start_client(struct vhost_user_socket *vsocket) +vhost_user_start(struct vhost_user_socket *vsocket) { int ret; int fd = vsocket->socket_fd; - const char *path = vsocket->path; + const char *path = vsocket->un.sun_path; struct vhost_user_reconnect *reconn; ret = vhost_user_connect_nonblock(fd, (struct sockaddr *)&vsocket->un, - sizeof(vsocket->un)); + sizeof(vsocket->un), + !vsocket->is_broker); if (ret == 0) { - vhost_user_add_connection(fd, vsocket); - return 0; + if (!vsocket->is_broker) { + vhost_user_add_connection(fd, vsocket); + return 0; + } else if (vhost_user_start_broker_connection(fd, vsocket)) { + ret = recreate_unix_socket(vsocket); + } else { + return 0; + } } VHOST_LOG_CONFIG(WARNING, @@ -822,6 +960,11 @@ rte_vhost_driver_get_queue_num(const char *path, uint32_t *queue_num) static void vhost_user_socket_mem_free(struct vhost_user_socket *vsocket) { + if (vsocket && vsocket->broker_key) { + free(vsocket->broker_key); + vsocket->broker_key = NULL; + } + if (vsocket && vsocket->path) { free(vsocket->path); vsocket->path = NULL; @@ -946,15 +1089,50 @@ rte_vhost_driver_register(const char *path, uint64_t flags) #endif } - if ((flags & RTE_VHOST_USER_CLIENT) != 0) { + if ((flags & RTE_VHOST_USER_SOCKETPAIR_BROKER) != 0) { +#ifndef RTE_LIBRTE_VHOST_SOCKETPAIR_BROKER + VHOST_LOG_CONFIG(ERR, + "SocketPair Broker requested but not compiled\n"); + ret = -1; + goto out_mutex; +#endif + char *broker_key = strstr(vsocket->path, ",broker-key="); + + if (!broker_key || !broker_key[12]) { + VHOST_LOG_CONFIG(ERR, + "Connection to SocketPair Broker requested but" + " key is not provided: %s\n", vsocket->path); + ret = -1; + goto out_mutex; + } + vsocket->is_broker = true; + vsocket->broker_key = strdup(broker_key + 12); + if (vsocket->broker_key == NULL) { + VHOST_LOG_CONFIG(ERR, + "error: failed to copy broker key\n"); + ret = -1; + goto out_mutex; + } + } + + if ((flags & RTE_VHOST_USER_CLIENT) == 0) + vsocket->is_server = true; + + if (!vsocket->is_server || vsocket->is_broker) { vsocket->reconnect = !(flags & RTE_VHOST_USER_NO_RECONNECT); + if (vsocket->is_broker && !vsocket->reconnect) { + VHOST_LOG_CONFIG(ERR, + "SocketPair Broker with NO_RECONNECT " + "is not supported\n"); + ret = -1; + goto out_mutex; + } if (vsocket->reconnect && reconn_tid == 0) { if (vhost_user_reconnect_init() != 0) goto out_mutex; } - } else { - vsocket->is_server = true; } + ret = create_unix_socket(vsocket); if (ret < 0) { goto out_mutex; @@ -1052,7 +1230,23 @@ rte_vhost_driver_unregister(const char *path) } pthread_mutex_unlock(&vsocket->conn_mutex); - if (vsocket->is_server) { + if (vsocket->reconnect) { + if (vhost_user_remove_reconnect(vsocket)) { + /* + * reconn->fd is a socket_fd for + * client and broker connections and + * it's closed now. + */ + vsocket->socket_fd = -1; + } + } + + /* + * socket_fd is still valid for server connection + * or broker connection that is currently connected + * to the broker. + */ + if (vsocket->socket_fd != -1) { /* * If r/wcb is executing, release vhost_user's * mutex lock, and try again since the r/wcb @@ -1063,13 +1257,12 @@ rte_vhost_driver_unregister(const char *path) pthread_mutex_unlock(&vhost_user.mutex); goto again; } - close(vsocket->socket_fd); - unlink(path); - } else if (vsocket->reconnect) { - vhost_user_remove_reconnect(vsocket); } + if (vsocket->is_server && !vsocket->is_broker) + unlink(path); + pthread_mutex_destroy(&vsocket->conn_mutex); vhost_user_socket_mem_free(vsocket); @@ -1152,8 +1345,8 @@ rte_vhost_driver_start(const char *path) } } - if (vsocket->is_server) + if (vsocket->is_server && !vsocket->is_broker) return vhost_user_start_server(vsocket); else - return vhost_user_start_client(vsocket); + return vhost_user_start(vsocket); } From patchwork Wed Mar 17 20:25:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 89414 X-Patchwork-Delegate: maxime.coquelin@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7AC46A0561; Wed, 17 Mar 2021 21:26:06 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4D671140F6F; Wed, 17 Mar 2021 21:25:54 +0100 (CET) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by mails.dpdk.org (Postfix) with ESMTP id 74FE0140F6D for ; Wed, 17 Mar 2021 21:25:53 +0100 (CET) X-Originating-IP: 78.45.89.65 Received: from im-t490s.redhat.com (ip-78-45-89-65.net.upcbroadband.cz [78.45.89.65]) (Authenticated sender: i.maximets@ovn.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 118F460005; Wed, 17 Mar 2021 20:25:51 +0000 (UTC) From: Ilya Maximets To: Maxime Coquelin Cc: Chenbo Xia , dev@dpdk.org, Adrian Moreno , Stefan Hajnoczi , Julia Suvorova , Ilya Maximets Date: Wed, 17 Mar 2021 21:25:29 +0100 Message-Id: <20210317202530.4145673-4-i.maximets@ovn.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210317202530.4145673-1-i.maximets@ovn.org> References: <20210317202530.4145673-1-i.maximets@ovn.org> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC 3/4] net/vhost: add support for SocketPair Broker X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" New configuration option "broker-key" to identify that "iface" points to the socket of SocketPair Broker and provide the pairing key. Some functions inside rte_eth_vhost.c are using socket path as a unique identifier, but that is not true. Simply concatinating key to iface name to avoid big code refactoring. And vhost library already expects the socket path in this format. Ex.: --vdev="eth_vhost0,iface=./one.socket,broker-key=mykey,client=1" Signed-off-by: Ilya Maximets --- doc/guides/nics/vhost.rst | 5 ++++ drivers/net/vhost/rte_eth_vhost.c | 42 +++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/doc/guides/nics/vhost.rst b/doc/guides/nics/vhost.rst index ee802ec4a8..1e6b8464c7 100644 --- a/doc/guides/nics/vhost.rst +++ b/doc/guides/nics/vhost.rst @@ -34,6 +34,11 @@ The user can specify below arguments in `--vdev` option. It is used to specify a path to connect to a QEMU virtio-net device. +#. ``broker-key``: + + It is used to specify that ``iface`` points to a SocketPair Broker and + value is used as a pairing key. + #. ``queues``: It is used to specify the number of queues virtio-net device has. diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c index d198fc8a8e..1b0ca47b47 100644 --- a/drivers/net/vhost/rte_eth_vhost.c +++ b/drivers/net/vhost/rte_eth_vhost.c @@ -27,6 +27,7 @@ RTE_LOG_REGISTER(vhost_logtype, pmd.net.vhost, NOTICE); enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; #define ETH_VHOST_IFACE_ARG "iface" +#define ETH_VHOST_BROKER_KEY_ARG "broker-key" #define ETH_VHOST_QUEUES_ARG "queues" #define ETH_VHOST_CLIENT_ARG "client" #define ETH_VHOST_IOMMU_SUPPORT "iommu-support" @@ -38,6 +39,7 @@ enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; static const char *valid_arguments[] = { ETH_VHOST_IFACE_ARG, + ETH_VHOST_BROKER_KEY_ARG, ETH_VHOST_QUEUES_ARG, ETH_VHOST_CLIENT_ARG, ETH_VHOST_IOMMU_SUPPORT, @@ -104,6 +106,7 @@ struct vhost_queue { struct pmd_internal { rte_atomic32_t dev_attached; char *iface_name; + char *broker_key; uint64_t flags; uint64_t disable_flags; uint16_t max_queues; @@ -1403,14 +1406,15 @@ static const struct eth_dev_ops ops = { static int eth_dev_vhost_create(struct rte_vdev_device *dev, char *iface_name, - int16_t queues, const unsigned int numa_node, uint64_t flags, - uint64_t disable_flags) + char *broker_key, int16_t queues, const unsigned int numa_node, + uint64_t flags, uint64_t disable_flags) { const char *name = rte_vdev_device_name(dev); struct rte_eth_dev_data *data; struct pmd_internal *internal = NULL; struct rte_eth_dev *eth_dev = NULL; struct rte_ether_addr *eth_addr = NULL; + int iface_name_len, name_len; VHOST_LOG(INFO, "Creating VHOST-USER backend on numa socket %u\n", numa_node); @@ -1434,11 +1438,22 @@ eth_dev_vhost_create(struct rte_vdev_device *dev, char *iface_name, * - and point eth_dev structure to new eth_dev_data structure */ internal = eth_dev->data->dev_private; - internal->iface_name = rte_malloc_socket(name, strlen(iface_name) + 1, + + iface_name_len = strlen(iface_name); + name_len = iface_name_len; + if (broker_key) + name_len += strlen(broker_key) + 12; + + internal->iface_name = rte_malloc_socket(name, name_len + 1, 0, numa_node); if (internal->iface_name == NULL) goto error; + strcpy(internal->iface_name, iface_name); + if (broker_key) { + strcpy(internal->iface_name + iface_name_len, ",broker-key="); + strcpy(internal->iface_name + iface_name_len + 12, broker_key); + } data->nb_rx_queues = queues; data->nb_tx_queues = queues; @@ -1471,14 +1486,14 @@ eth_dev_vhost_create(struct rte_vdev_device *dev, char *iface_name, } static inline int -open_iface(const char *key __rte_unused, const char *value, void *extra_args) +open_str(const char *key __rte_unused, const char *value, void *extra_args) { - const char **iface_name = extra_args; + const char **str = extra_args; if (value == NULL) return -1; - *iface_name = value; + *str = value; return 0; } @@ -1504,6 +1519,7 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev) struct rte_kvargs *kvlist = NULL; int ret = 0; char *iface_name; + char *broker_key = NULL; uint16_t queues; uint64_t flags = 0; uint64_t disable_flags = 0; @@ -1540,7 +1556,7 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev) if (rte_kvargs_count(kvlist, ETH_VHOST_IFACE_ARG) == 1) { ret = rte_kvargs_process(kvlist, ETH_VHOST_IFACE_ARG, - &open_iface, &iface_name); + &open_str, &iface_name); if (ret < 0) goto out_free; } else { @@ -1548,6 +1564,16 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev) goto out_free; } + if (rte_kvargs_count(kvlist, ETH_VHOST_BROKER_KEY_ARG) == 1) { + ret = rte_kvargs_process(kvlist, ETH_VHOST_BROKER_KEY_ARG, + &open_str, &broker_key); + if (ret < 0) + goto out_free; + + if (broker_key) + flags |= RTE_VHOST_USER_SOCKETPAIR_BROKER; + } + if (rte_kvargs_count(kvlist, ETH_VHOST_QUEUES_ARG) == 1) { ret = rte_kvargs_process(kvlist, ETH_VHOST_QUEUES_ARG, &open_int, &queues); @@ -1625,7 +1651,7 @@ rte_pmd_vhost_probe(struct rte_vdev_device *dev) if (dev->device.numa_node == SOCKET_ID_ANY) dev->device.numa_node = rte_socket_id(); - ret = eth_dev_vhost_create(dev, iface_name, queues, + ret = eth_dev_vhost_create(dev, iface_name, broker_key, queues, dev->device.numa_node, flags, disable_flags); if (ret == -1) VHOST_LOG(ERR, "Failed to create %s\n", name); From patchwork Wed Mar 17 20:25:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Maximets X-Patchwork-Id: 89415 X-Patchwork-Delegate: maxime.coquelin@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id DD924A0561; Wed, 17 Mar 2021 21:26:12 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 920F7140F73; Wed, 17 Mar 2021 21:25:58 +0100 (CET) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by mails.dpdk.org (Postfix) with ESMTP id 05634140F67 for ; Wed, 17 Mar 2021 21:25:57 +0100 (CET) X-Originating-IP: 78.45.89.65 Received: from im-t490s.redhat.com (ip-78-45-89-65.net.upcbroadband.cz [78.45.89.65]) (Authenticated sender: i.maximets@ovn.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 90E3960002; Wed, 17 Mar 2021 20:25:55 +0000 (UTC) From: Ilya Maximets To: Maxime Coquelin Cc: Chenbo Xia , dev@dpdk.org, Adrian Moreno , Stefan Hajnoczi , Julia Suvorova , Ilya Maximets Date: Wed, 17 Mar 2021 21:25:30 +0100 Message-Id: <20210317202530.4145673-5-i.maximets@ovn.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210317202530.4145673-1-i.maximets@ovn.org> References: <20210317202530.4145673-1-i.maximets@ovn.org> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC 4/4] net/virtio: add support for SocketPair Broker X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" New configuration option 'broker-key' to specify that the socket path is actually a path to SocketPair Broker's socket. The value of a 'broker-key' argument will be used as a broker key, so the broker will be able to identify which vhost device virtio-user should be paired with. Ex.: --vdev="net_virtio_user,path=broker.socket,broker-key=,server=1" libspbroker needed for a build. Had to implement few tricks to trigger interrupts by alarm for the case where we have no any sockets open, i.e. broker is disconnected and vhost connection is dead. OTOH, this infrastructure might be used later to implement client reconnection for virtio-user. Signed-off-by: Ilya Maximets --- doc/guides/nics/virtio.rst | 5 + drivers/net/virtio/meson.build | 6 + drivers/net/virtio/virtio_user/vhost_user.c | 118 +++++++++++++++++- .../net/virtio/virtio_user/virtio_user_dev.c | 92 ++++++++++---- .../net/virtio/virtio_user/virtio_user_dev.h | 4 +- drivers/net/virtio/virtio_user_ethdev.c | 30 ++++- 6 files changed, 227 insertions(+), 28 deletions(-) diff --git a/doc/guides/nics/virtio.rst b/doc/guides/nics/virtio.rst index 02e74a6e77..e3ca5b57f8 100644 --- a/doc/guides/nics/virtio.rst +++ b/doc/guides/nics/virtio.rst @@ -376,6 +376,11 @@ Below devargs are supported by the virtio-user vdev: It is used to specify a path to connect to vhost backend. +#. ``broker-key``: + + It is used to specify that ``path`` points to a SocketPair Broker, value + is used as a pairing key. + #. ``mac``: It is used to specify the MAC address. diff --git a/drivers/net/virtio/meson.build b/drivers/net/virtio/meson.build index d595cfdcab..aada19d8da 100644 --- a/drivers/net/virtio/meson.build +++ b/drivers/net/virtio/meson.build @@ -7,6 +7,12 @@ if is_windows subdir_done() endif +spbroker_dep = dependency('spbroker', required: false) +if spbroker_dep.found() + dpdk_conf.set('VIRTIO_SOCKETPAIR_BROKER', 1) + ext_deps += spbroker_dep +endif + sources += files('virtio.c', 'virtio_ethdev.c', 'virtio_pci_ethdev.c', diff --git a/drivers/net/virtio/virtio_user/vhost_user.c b/drivers/net/virtio/virtio_user/vhost_user.c index 25f74c625b..9d87cda2f5 100644 --- a/drivers/net/virtio/virtio_user/vhost_user.c +++ b/drivers/net/virtio/virtio_user/vhost_user.c @@ -11,6 +11,11 @@ #include #include +#ifdef VIRTIO_SOCKETPAIR_BROKER +#include +#endif + + #include #include #include @@ -21,6 +26,7 @@ struct vhost_user_data { int vhostfd; int listenfd; + int brokerfd; uint64_t protocol_features; }; @@ -790,12 +796,78 @@ vhost_user_server_disconnect(struct virtio_user_dev *dev) return 0; } +static void +vhost_user_update_broker_fd(struct virtio_user_dev *dev __rte_unused) +{ +#ifdef VIRTIO_SOCKETPAIR_BROKER + struct vhost_user_data *data = dev->backend_data; + char *err = NULL; + int flags; + + if (data->brokerfd != -1) + return; + + data->brokerfd = sp_broker_connect(dev->path, false, &err); + if (data->brokerfd < 0) { + PMD_DRV_LOG(WARNING, "failed to connect to broker: %s", err); + free(err); + data->brokerfd = -1; + return; + } + + if (sp_broker_send_get_pair(data->brokerfd, dev->broker_key, + dev->is_server, &err)) { + PMD_DRV_LOG(WARNING, + "failed to send GET_PAIR request: %s", err); + free(err); + close(data->brokerfd); + data->brokerfd = -1; + return; + } + + flags = fcntl(data->brokerfd, F_GETFL); + if (fcntl(data->brokerfd, F_SETFL, flags | O_NONBLOCK) == -1) { + PMD_DRV_LOG(ERR, "error setting O_NONBLOCK flag"); + close(data->brokerfd); + data->brokerfd = -1; + return; + } +#endif +} + static int vhost_user_server_reconnect(struct virtio_user_dev *dev) { struct vhost_user_data *data = dev->backend_data; int fd; +#ifdef VIRTIO_SOCKETPAIR_BROKER + if (dev->broker_key) { + char *err; + + vhost_user_update_broker_fd(dev); + if (data->brokerfd == -1) + return -1; + + fd = sp_broker_receive_set_pair(data->brokerfd, &err); + if (fd < 0) { + PMD_DRV_LOG(DEBUG, + "failed to receive SET_PAIR: %s", err); + free(err); + /* + * Unfortunately, since connection is non-blocking + * we can't reliably say if the other end is dead for + * a case where it didn't close the socket gracefully. + * Closing current connection to re-establish later. + */ + close(data->brokerfd); + data->brokerfd = -1; + return -1; + } + data->vhostfd = fd; + return 0; + } +#endif fd = accept(data->listenfd, NULL, NULL); if (fd < 0) return -1; @@ -832,6 +904,29 @@ vhost_user_setup(struct virtio_user_dev *dev) data->vhostfd = -1; data->listenfd = -1; + data->brokerfd = -1; + + if (dev->broker_key) { +#ifdef VIRTIO_SOCKETPAIR_BROKER + char *err; + + fd = sp_broker_get_pair(dev->path, dev->broker_key, + dev->is_server, &err); + if (fd < 0) { + PMD_DRV_LOG(ERR, + "virtio-user failed to connect to broker: %s", + err); + free(err); + goto err_data; + } + data->vhostfd = fd; + return 0; +#else + PMD_DRV_LOG(ERR, "virtio-user broker connection requested " + "but not compiled"); + goto err_data; +#endif + } fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { @@ -890,6 +985,11 @@ vhost_user_destroy(struct virtio_user_dev *dev) data->listenfd = -1; } + if (data->brokerfd >= 0) { + close(data->brokerfd); + data->brokerfd = -1; + } + free(data); dev->backend_data = NULL; @@ -983,8 +1083,22 @@ vhost_user_get_intr_fd(struct virtio_user_dev *dev) { struct vhost_user_data *data = dev->backend_data; - if (dev->is_server && data->vhostfd == -1) - return data->listenfd; + if (data->vhostfd == -1) { + if (dev->broker_key) { + vhost_user_update_broker_fd(dev); + return data->brokerfd; + } + if (dev->is_server) + return data->listenfd; + } else if (data->brokerfd != -1) { + /* + * Broker not needed anymore and we need to close the socket + * because other end will be closed by the broker anyway. + */ + PMD_DRV_LOG(DEBUG, "Closing broker fd: %d", data->brokerfd); + close(data->brokerfd); + data->brokerfd = -1; + } return data->vhostfd; } diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c index 68cece42d3..8b53af0724 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.c +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c @@ -414,11 +414,16 @@ virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused, static int virtio_user_dev_setup(struct virtio_user_dev *dev) { - if (dev->is_server) { - if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) { - PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!"); - return -1; - } + if (dev->is_server && + dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) { + PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!"); + return -1; + } + + if (dev->broker_key && + dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) { + PMD_DRV_LOG(ERR, "Broker connection only supports vhost-user!"); + return -1; } switch (dev->backend_type) { @@ -483,10 +488,10 @@ virtio_user_dev_setup(struct virtio_user_dev *dev) 1ULL << VIRTIO_F_RING_PACKED) int -virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, - int cq, int queue_size, const char *mac, char **ifname, - int server, int mrg_rxbuf, int in_order, int packed_vq, - enum virtio_user_backend_type backend_type) +virtio_user_dev_init(struct virtio_user_dev *dev, char *path, char **broker_key, + int queues, int cq, int queue_size, const char *mac, + char **ifname, int server, int mrg_rxbuf, int in_order, + int packed_vq, enum virtio_user_backend_type backend_type) { uint64_t backend_features; int i; @@ -511,6 +516,11 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, parse_mac(dev, mac); + if (*broker_key) { + dev->broker_key = *broker_key; + *broker_key = NULL; + } + if (*ifname) { dev->ifname = *ifname; *ifname = NULL; @@ -595,6 +605,10 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, void virtio_user_dev_uninit(struct virtio_user_dev *dev) { + struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->port_id]; + + rte_eal_alarm_cancel(virtio_interrupt_handler, eth_dev); + virtio_user_stop_device(dev); rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev); @@ -603,9 +617,11 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev) free(dev->ifname); - if (dev->is_server) + if (dev->is_server && !dev->broker_key) unlink(dev->path); + free(dev->broker_key); + dev->ops->destroy(dev); } @@ -929,21 +945,44 @@ virtio_user_dev_delayed_intr_reconfig_handler(void *param) struct virtio_user_dev *dev = param; struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->port_id]; - PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", - eth_dev->intr_handle->fd); + if (rte_intr_disable(eth_dev->intr_handle) < 0) { + PMD_DRV_LOG(ERR, "interrupt disable failed"); + return; + } - if (rte_intr_callback_unregister(eth_dev->intr_handle, - virtio_interrupt_handler, - eth_dev) != 1) - PMD_DRV_LOG(ERR, "interrupt unregister failed"); + if (eth_dev->intr_handle->fd != -1) { + PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", + eth_dev->intr_handle->fd); + + if (rte_intr_callback_unregister(eth_dev->intr_handle, + virtio_interrupt_handler, + eth_dev) != 1) + PMD_DRV_LOG(ERR, "interrupt unregister failed"); + } eth_dev->intr_handle->fd = dev->ops->get_intr_fd(dev); - PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", eth_dev->intr_handle->fd); + rte_eal_alarm_cancel(virtio_interrupt_handler, eth_dev); + if (eth_dev->intr_handle->fd == -1) { + PMD_DRV_LOG(DEBUG, "Scheduling interrupt as alarm"); + /* + * There is no interrupt source. Setting alarm + * instead to try to re-connect later. + */ + rte_eal_alarm_set(US_PER_S, virtio_interrupt_handler, + (void *)eth_dev); + return; + } + + if (eth_dev->intr_handle->fd != -1) { + PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", + eth_dev->intr_handle->fd); - if (rte_intr_callback_register(eth_dev->intr_handle, - virtio_interrupt_handler, eth_dev)) - PMD_DRV_LOG(ERR, "interrupt register failed"); + if (rte_intr_callback_register(eth_dev->intr_handle, + virtio_interrupt_handler, + eth_dev)) + PMD_DRV_LOG(ERR, "interrupt register failed"); + } if (rte_intr_enable(eth_dev->intr_handle) < 0) PMD_DRV_LOG(ERR, "interrupt enable failed"); @@ -963,6 +1002,15 @@ virtio_user_dev_server_reconnect(struct virtio_user_dev *dev) if (dev->ops->server_reconnect(dev)) { PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path); + if (dev->broker_key) { + /* + * We might need to re-establish broker connection, so + * we need to re-configure interrupts for it. + */ + rte_eal_alarm_set(1, + virtio_user_dev_delayed_intr_reconfig_handler, + (void *)dev); + } return -1; } @@ -1010,10 +1058,6 @@ virtio_user_dev_server_reconnect(struct virtio_user_dev *dev) } } if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) { - if (rte_intr_disable(eth_dev->intr_handle) < 0) { - PMD_DRV_LOG(ERR, "interrupt disable failed"); - return -1; - } /* * This function can be called from the interrupt handler, so * we can't unregister interrupt handler here. Setting diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h index 15d177ccd2..f1d75c76d3 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.h +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h @@ -47,6 +47,7 @@ struct virtio_user_dev { uint8_t mac_addr[RTE_ETHER_ADDR_LEN]; char path[PATH_MAX]; char *ifname; + char *broker_key; union { struct vring vrings[VIRTIO_MAX_VIRTQUEUES]; @@ -65,7 +66,8 @@ struct virtio_user_dev { int virtio_user_dev_set_features(struct virtio_user_dev *dev); int virtio_user_start_device(struct virtio_user_dev *dev); int virtio_user_stop_device(struct virtio_user_dev *dev); -int virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, +int virtio_user_dev_init(struct virtio_user_dev *dev, char *path, + char **broker_key, int queues, int cq, int queue_size, const char *mac, char **ifname, int server, int mrg_rxbuf, int in_order, int packed_vq, diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c index 1810a54694..bace903658 100644 --- a/drivers/net/virtio/virtio_user_ethdev.c +++ b/drivers/net/virtio/virtio_user_ethdev.c @@ -315,6 +315,8 @@ static const char *valid_args[] = { VIRTIO_USER_ARG_SPEED, #define VIRTIO_USER_ARG_VECTORIZED "vectorized" VIRTIO_USER_ARG_VECTORIZED, +#define VIRTIO_USER_ARG_BROKER_KEY "broker-key" + VIRTIO_USER_ARG_BROKER_KEY, NULL }; @@ -467,6 +469,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev) uint64_t packed_vq = 0; uint64_t vectorized = 0; char *path = NULL; + char *broker_key = NULL; char *ifname = NULL; char *mac_addr = NULL; int ret = -1; @@ -578,6 +581,28 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev) } } + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_BROKER_KEY) == 1) { +#ifndef VIRTIO_SOCKETPAIR_BROKER + PMD_INIT_LOG(ERR, + "arg %s requested but support for SocketPair Broker " + "is not compiled", + VIRTIO_USER_ARG_BROKER_KEY); + goto end; +#endif + if (backend_type != VIRTIO_USER_BACKEND_VHOST_USER) { + PMD_INIT_LOG(ERR, + "arg %s applies only to vhost-user backend", + VIRTIO_USER_ARG_BROKER_KEY); + goto end; + } + if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_BROKER_KEY, + &get_string_arg, &broker_key) < 0) { + PMD_INIT_LOG(ERR, "error to parse %s", + VIRTIO_USER_ARG_BROKER_KEY); + goto end; + } + } + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_CQ_NUM) == 1) { if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_CQ_NUM, &get_integer_arg, &cq) < 0) { @@ -645,7 +670,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev) dev = eth_dev->data->dev_private; hw = &dev->hw; - if (virtio_user_dev_init(dev, path, queues, cq, + if (virtio_user_dev_init(dev, path, &broker_key, queues, cq, queue_size, mac_addr, &ifname, server_mode, mrg_rxbuf, in_order, packed_vq, backend_type) < 0) { PMD_INIT_LOG(ERR, "virtio_user_dev_init fails"); @@ -682,6 +707,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *vdev) rte_kvargs_free(kvlist); if (path) free(path); + if (broker_key) + free(broker_key); if (mac_addr) free(mac_addr); if (ifname) @@ -777,6 +804,7 @@ RTE_PMD_REGISTER_PARAM_STRING(net_virtio_user, "queue_size= " "queues= " "iface= " + "broker_key= " "server=<0|1> " "mrg_rxbuf=<0|1> " "in_order=<0|1> "