vhost: disable host TSO for linear buffers without extbuf
[dpdk.git] / lib / librte_vhost / socket.c
index 01b60ff..a34bc7f 100644 (file)
@@ -40,6 +40,8 @@ struct vhost_user_socket {
        bool dequeue_zero_copy;
        bool iommu_support;
        bool use_builtin_virtio_net;
+       bool extbuf;
+       bool linearbuf;
 
        /*
         * The "supported_features" indicates the feature bits the
@@ -90,6 +92,7 @@ static struct vhost_user vhost_user = {
        .fdset = {
                .fd = { [0 ... MAX_FDS - 1] = {-1, NULL, NULL, NULL, 0} },
                .fd_mutex = PTHREAD_MUTEX_INITIALIZER,
+               .fd_pooling_mutex = PTHREAD_MUTEX_INITIALIZER,
                .num = 0
        },
        .vsocket_cnt = 0,
@@ -231,6 +234,12 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
        if (vsocket->dequeue_zero_copy)
                vhost_enable_dequeue_zero_copy(vid);
 
+       if (vsocket->extbuf)
+               vhost_enable_extbuf(vid);
+
+       if (vsocket->linearbuf)
+               vhost_enable_linearbuf(vid);
+
        RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
 
        if (vsocket->notify_ops->new_connection) {
@@ -239,7 +248,7 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
                        RTE_LOG(ERR, VHOST_CONFIG,
                                "failed to add vhost user connection with fd %d\n",
                                fd);
-                       goto err;
+                       goto err_cleanup;
                }
        }
 
@@ -256,7 +265,7 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
                if (vsocket->notify_ops->destroy_connection)
                        vsocket->notify_ops->destroy_connection(conn->vid);
 
-               goto err;
+               goto err_cleanup;
        }
 
        pthread_mutex_lock(&vsocket->conn_mutex);
@@ -266,6 +275,8 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
        fdset_pipe_notify(&vhost_user.fdset);
        return;
 
+err_cleanup:
+       vhost_destroy_device(vid);
 err:
        free(conn);
        close(fd);
@@ -294,13 +305,19 @@ vhost_user_read_cb(int connfd, void *dat, int *remove)
 
        ret = vhost_user_msg_handler(conn->vid, connfd);
        if (ret < 0) {
+               struct virtio_net *dev = get_device(conn->vid);
+
                close(connfd);
                *remove = 1;
-               vhost_destroy_device(conn->vid);
+
+               if (dev)
+                       vhost_destroy_device_notify(dev);
 
                if (vsocket->notify_ops->destroy_connection)
                        vsocket->notify_ops->destroy_connection(conn->vid);
 
+               vhost_destroy_device(conn->vid);
+
                pthread_mutex_lock(&vsocket->conn_mutex);
                TAILQ_REMOVE(&vsocket->conn_list, conn, next);
                pthread_mutex_unlock(&vsocket->conn_mutex);
@@ -546,6 +563,9 @@ find_vhost_user_socket(const char *path)
 {
        int i;
 
+       if (path == NULL)
+               return NULL;
+
        for (i = 0; i < vhost_user.vsocket_cnt; i++) {
                struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
 
@@ -561,7 +581,7 @@ rte_vhost_driver_attach_vdpa_device(const char *path, int did)
 {
        struct vhost_user_socket *vsocket;
 
-       if (rte_vdpa_get_device(did) == NULL)
+       if (rte_vdpa_get_device(did) == NULL || path == NULL)
                return -1;
 
        pthread_mutex_lock(&vhost_user.mutex);
@@ -706,6 +726,20 @@ unlock_exit:
        return ret;
 }
 
+int
+rte_vhost_driver_set_protocol_features(const char *path,
+               uint64_t protocol_features)
+{
+       struct vhost_user_socket *vsocket;
+
+       pthread_mutex_lock(&vhost_user.mutex);
+       vsocket = find_vhost_user_socket(path);
+       if (vsocket)
+               vsocket->protocol_features = protocol_features;
+       pthread_mutex_unlock(&vhost_user.mutex);
+       return vsocket ? 0 : -1;
+}
+
 int
 rte_vhost_driver_get_protocol_features(const char *path,
                uint64_t *protocol_features)
@@ -844,6 +878,16 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
                goto out_free;
        }
        vsocket->dequeue_zero_copy = flags & RTE_VHOST_USER_DEQUEUE_ZERO_COPY;
+       vsocket->extbuf = flags & RTE_VHOST_USER_EXTBUF_SUPPORT;
+       vsocket->linearbuf = flags & RTE_VHOST_USER_LINEARBUF_SUPPORT;
+
+       if (vsocket->dequeue_zero_copy &&
+           (flags & RTE_VHOST_USER_IOMMU_SUPPORT)) {
+               RTE_LOG(ERR, VHOST_CONFIG,
+                       "error: enabling dequeue zero copy and IOMMU features "
+                       "simultaneously is not supported\n");
+               goto out_mutex;
+       }
 
        /*
         * Set the supported features correctly for the builtin vhost-user
@@ -868,6 +912,18 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
         * not compatible with postcopy.
         */
        if (vsocket->dequeue_zero_copy) {
+               if (vsocket->extbuf) {
+                       RTE_LOG(ERR, VHOST_CONFIG,
+                       "error: zero copy is incompatible with external buffers\n");
+                       ret = -1;
+                       goto out_mutex;
+               }
+               if (vsocket->linearbuf) {
+                       RTE_LOG(ERR, VHOST_CONFIG,
+                       "error: zero copy is incompatible with linear buffers\n");
+                       ret = -1;
+                       goto out_mutex;
+               }
                vsocket->supported_features &= ~(1ULL << VIRTIO_F_IN_ORDER);
                vsocket->features &= ~(1ULL << VIRTIO_F_IN_ORDER);
 
@@ -877,6 +933,24 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
                        ~(1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT);
        }
 
+       /*
+        * We'll not be able to receive a buffer from guest in linear mode
+        * without external buffer if it will not fit in a single mbuf, which is
+        * likely if segmentation offloading enabled.
+        */
+       if (vsocket->linearbuf && !vsocket->extbuf) {
+               uint64_t seg_offload_features =
+                               (1ULL << VIRTIO_NET_F_HOST_TSO4) |
+                               (1ULL << VIRTIO_NET_F_HOST_TSO6) |
+                               (1ULL << VIRTIO_NET_F_HOST_UFO);
+
+               RTE_LOG(INFO, VHOST_CONFIG,
+                       "Linear buffers requested without external buffers, "
+                       "disabling host segmentation offloading support\n");
+               vsocket->supported_features &= ~seg_offload_features;
+               vsocket->features &= ~seg_offload_features;
+       }
+
        if (!(flags & RTE_VHOST_USER_IOMMU_SUPPORT)) {
                vsocket->supported_features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
                vsocket->features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
@@ -960,13 +1034,16 @@ rte_vhost_driver_unregister(const char *path)
        int count;
        struct vhost_user_connection *conn, *next;
 
+       if (path == NULL)
+               return -1;
+
+again:
        pthread_mutex_lock(&vhost_user.mutex);
 
        for (i = 0; i < vhost_user.vsocket_cnt; i++) {
                struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
 
                if (!strcmp(vsocket->path, path)) {
-again:
                        pthread_mutex_lock(&vsocket->conn_mutex);
                        for (conn = TAILQ_FIRST(&vsocket->conn_list);
                             conn != NULL;
@@ -982,6 +1059,7 @@ again:
                                                  conn->connfd) == -1) {
                                        pthread_mutex_unlock(
                                                        &vsocket->conn_mutex);
+                                       pthread_mutex_unlock(&vhost_user.mutex);
                                        goto again;
                                }