Allow reconnecting on failure when both RTE_VHOST_USER_RECONNECT and RTE_VHOST_USER_CLIENT flags are set.
Reconnecting means two things here: - when DPDK app starts first and QEMU (as the server) is not started, without reconnecting, DPDK app would simply fail on vhost-user registration. - when QEMU reboots, without reconnecting, you can't re-establish the connection without restarting DPDK app. This patch make it work well for both above cases. It simply creates a new thread, and keep trying calling "connect()", until it succeeds. Signed-off-by: Yuanhan Liu <yuanhan.liu at linux.intel.com> --- lib/librte_vhost/rte_virtio_net.h | 1 + lib/librte_vhost/vhost_user/vhost-net-user.c | 63 +++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/lib/librte_vhost/rte_virtio_net.h b/lib/librte_vhost/rte_virtio_net.h index c84e7ab..f354d52 100644 --- a/lib/librte_vhost/rte_virtio_net.h +++ b/lib/librte_vhost/rte_virtio_net.h @@ -52,6 +52,7 @@ #include <rte_ether.h> #define RTE_VHOST_USER_CLIENT (1ULL << 0) +#define RTE_VHOST_USER_RECONNECT (1ULL << 1) struct rte_mbuf; diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c index aa98717..07bce6e 100644 --- a/lib/librte_vhost/vhost_user/vhost-net-user.c +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c @@ -59,6 +59,7 @@ struct vhost_user_socket { char *path; int listenfd; int is_server; + int reconnect; }; struct vhost_user_connection { @@ -78,6 +79,7 @@ struct vhost_user { static void vhost_user_server_new_connection(int fd, void *data, int *remove); static void vhost_user_msg_handler(int fd, void *dat, int *remove); +static int vhost_user_create_client(struct vhost_user_socket *vsocket); static struct vhost_user vhost_user = { .fdset = { @@ -304,6 +306,8 @@ vhost_user_msg_handler(int connfd, void *dat, int *remove) vid = conn->vid; ret = read_vhost_message(connfd, &msg); if (ret <= 0 || msg.request >= VHOST_USER_MAX) { + struct vhost_user_socket *vsocket = conn->vsocket; + if (ret < 0) RTE_LOG(ERR, VHOST_CONFIG, "vhost read message failed\n"); @@ -319,6 +323,9 @@ vhost_user_msg_handler(int connfd, void *dat, int *remove) free(conn); vhost_destroy_device(vid); + if (vsocket->reconnect) + vhost_user_create_client(vsocket); + return; } @@ -470,6 +477,33 @@ err: return -1; } +struct reconnect_info { + struct sockaddr_un un; + int fd; + struct vhost_user_socket *vsocket; +}; + +static void * +vhost_user_client_reconnect(void *arg) +{ + struct reconnect_info *reconn = arg; + int ret; + + RTE_LOG(ERR, VHOST_CONFIG, "reconnecting...\n"); + while (1) { + ret = connect(reconn->fd, (struct sockaddr *)&reconn->un, + sizeof(reconn->un)); + if (ret == 0) + break; + sleep(1); + } + + vhost_user_add_connection(reconn->fd, reconn->vsocket); + free(reconn); + + return NULL; +} + static int vhost_user_create_client(struct vhost_user_socket *vsocket) { @@ -477,22 +511,40 @@ vhost_user_create_client(struct vhost_user_socket *vsocket) int ret; struct sockaddr_un un; const char *path = vsocket->path; + struct reconnect_info *reconn; + pthread_t tid; fd = create_unix_socket(path, &un, vsocket->is_server); if (fd < 0) return -1; ret = connect(fd, (struct sockaddr *)&un, sizeof(un)); - if (ret < 0) { - RTE_LOG(ERR, VHOST_CONFIG, "failed to connect to %s: %s\n", - path, strerror(errno)); + if (ret == 0) { + vhost_user_add_connection(fd, vsocket); + return 0; + } + + RTE_LOG(ERR, VHOST_CONFIG, + "failed to connect to %s: %s\n", + path, strerror(errno)); + + if (!vsocket->reconnect) { close(fd); return -1; } - vhost_user_add_connection(fd, vsocket); + /* Create a thread to try reconnecting, to not block the caller. */ + reconn = malloc(sizeof(*reconn)); + reconn->un = un; + reconn->fd = fd; + reconn->vsocket = vsocket; + ret = pthread_create(&tid, NULL, vhost_user_client_reconnect, reconn); + if (ret < 0) { + close(fd); + RTE_LOG(ERR, VHOST_CONFIG, "failed to create reconnect thread"); + } - return 0; + return ret; } /* @@ -524,6 +576,7 @@ rte_vhost_driver_register(const char *path, uint64_t flags) vsocket->path = strdup(path); if ((flags & RTE_VHOST_USER_CLIENT) != 0) { + vsocket->reconnect = !!(flags & RTE_VHOST_USER_RECONNECT); ret = vhost_user_create_client(vsocket); } else { vsocket->is_server = 1; -- 1.9.0