vhost-vdpa: introduce vhost-vdpa net client
This patch set introduces a new net client type: vhost-vdpa. vhost-vdpa net client will set up a vDPA device which is specified by a "vhostdev" parameter. Signed-off-by: Lingshan Zhu <lingshan.zhu@intel.com> Signed-off-by: Tiwei Bie <tiwei.bie@intel.com> Signed-off-by: Cindy Lu <lulu@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Message-Id: <20200701145538.22333-15-lulu@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Acked-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
		
				
					committed by
					
						 Michael S. Tsirkin
						Michael S. Tsirkin
					
				
			
			
				
	
			
			
			
						parent
						
							108a64818e
						
					
				
				
					commit
					1e0a84ea49
				
			
							
								
								
									
										22
									
								
								include/net/vhost-vdpa.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/net/vhost-vdpa.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /* | ||||
|  * vhost-vdpa.h | ||||
|  * | ||||
|  * Copyright(c) 2017-2018 Intel Corporation. | ||||
|  * Copyright(c) 2020 Red Hat, Inc. | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef VHOST_VDPA_H | ||||
| #define VHOST_VDPA_H | ||||
|  | ||||
| #define TYPE_VHOST_VDPA "vhost-vdpa" | ||||
|  | ||||
| struct vhost_net *vhost_vdpa_get_vhost_net(NetClientState *nc); | ||||
| uint64_t vhost_vdpa_get_acked_features(NetClientState *nc); | ||||
|  | ||||
| extern const int vdpa_feature_bits[]; | ||||
|  | ||||
| #endif /* VHOST_VDPA_H */ | ||||
| @@ -26,7 +26,7 @@ tap-obj-$(CONFIG_SOLARIS) = tap-solaris.o | ||||
| tap-obj-y ?= tap-stub.o | ||||
| common-obj-$(CONFIG_POSIX) += tap.o $(tap-obj-y) | ||||
| common-obj-$(CONFIG_WIN32) += tap-win32.o | ||||
|  | ||||
| common-obj-$(CONFIG_VHOST_NET_VDPA) += vhost-vdpa.o | ||||
| vde.o-libs = $(VDE_LIBS) | ||||
|  | ||||
| common-obj-$(CONFIG_CAN_BUS) += can/ | ||||
|   | ||||
| @@ -61,4 +61,6 @@ int net_init_netmap(const Netdev *netdev, const char *name, | ||||
| int net_init_vhost_user(const Netdev *netdev, const char *name, | ||||
|                         NetClientState *peer, Error **errp); | ||||
|  | ||||
| int net_init_vhost_vdpa(const Netdev *netdev, const char *name, | ||||
|                         NetClientState *peer, Error **errp); | ||||
| #endif /* QEMU_NET_CLIENTS_H */ | ||||
|   | ||||
| @@ -966,6 +966,9 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( | ||||
| #ifdef CONFIG_VHOST_NET_USER | ||||
|         [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, | ||||
| #endif | ||||
| #ifdef CONFIG_VHOST_NET_VDPA | ||||
|         [NET_CLIENT_DRIVER_VHOST_VDPA] = net_init_vhost_vdpa, | ||||
| #endif | ||||
| #ifdef CONFIG_L2TPV3 | ||||
|         [NET_CLIENT_DRIVER_L2TPV3]    = net_init_l2tpv3, | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										228
									
								
								net/vhost-vdpa.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								net/vhost-vdpa.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| /* | ||||
|  * vhost-vdpa.c | ||||
|  * | ||||
|  * Copyright(c) 2017-2018 Intel Corporation. | ||||
|  * Copyright(c) 2020 Red Hat, Inc. | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "qemu/osdep.h" | ||||
| #include "clients.h" | ||||
| #include "net/vhost_net.h" | ||||
| #include "net/vhost-vdpa.h" | ||||
| #include "hw/virtio/vhost-vdpa.h" | ||||
| #include "qemu/config-file.h" | ||||
| #include "qemu/error-report.h" | ||||
| #include "qemu/option.h" | ||||
| #include "qapi/error.h" | ||||
| #include <sys/ioctl.h> | ||||
| #include <err.h> | ||||
| #include "standard-headers/linux/virtio_net.h" | ||||
| #include "monitor/monitor.h" | ||||
| #include "hw/virtio/vhost.h" | ||||
|  | ||||
| /* Todo:need to add the multiqueue support here */ | ||||
| typedef struct VhostVDPAState { | ||||
|     NetClientState nc; | ||||
|     struct vhost_vdpa vhost_vdpa; | ||||
|     VHostNetState *vhost_net; | ||||
|     uint64_t acked_features; | ||||
|     bool started; | ||||
| } VhostVDPAState; | ||||
|  | ||||
| const int vdpa_feature_bits[] = { | ||||
|     VIRTIO_F_NOTIFY_ON_EMPTY, | ||||
|     VIRTIO_RING_F_INDIRECT_DESC, | ||||
|     VIRTIO_RING_F_EVENT_IDX, | ||||
|     VIRTIO_F_ANY_LAYOUT, | ||||
|     VIRTIO_F_VERSION_1, | ||||
|     VIRTIO_NET_F_CSUM, | ||||
|     VIRTIO_NET_F_GUEST_CSUM, | ||||
|     VIRTIO_NET_F_GSO, | ||||
|     VIRTIO_NET_F_GUEST_TSO4, | ||||
|     VIRTIO_NET_F_GUEST_TSO6, | ||||
|     VIRTIO_NET_F_GUEST_ECN, | ||||
|     VIRTIO_NET_F_GUEST_UFO, | ||||
|     VIRTIO_NET_F_HOST_TSO4, | ||||
|     VIRTIO_NET_F_HOST_TSO6, | ||||
|     VIRTIO_NET_F_HOST_ECN, | ||||
|     VIRTIO_NET_F_HOST_UFO, | ||||
|     VIRTIO_NET_F_MRG_RXBUF, | ||||
|     VIRTIO_NET_F_MTU, | ||||
|     VIRTIO_F_IOMMU_PLATFORM, | ||||
|     VIRTIO_F_RING_PACKED, | ||||
|     VIRTIO_NET_F_GUEST_ANNOUNCE, | ||||
|     VHOST_INVALID_FEATURE_BIT | ||||
| }; | ||||
|  | ||||
| VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) | ||||
| { | ||||
|     VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | ||||
|     assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|     return s->vhost_net; | ||||
| } | ||||
|  | ||||
| uint64_t vhost_vdpa_get_acked_features(NetClientState *nc) | ||||
| { | ||||
|     VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | ||||
|     assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|     s->acked_features = vhost_net_get_acked_features(s->vhost_net); | ||||
|  | ||||
|     return s->acked_features; | ||||
| } | ||||
|  | ||||
| static int vhost_vdpa_net_check_device_id(struct vhost_net *net) | ||||
| { | ||||
|     uint32_t device_id; | ||||
|     int ret; | ||||
|     struct vhost_dev *hdev; | ||||
|  | ||||
|     hdev = (struct vhost_dev *)&net->dev; | ||||
|     ret = hdev->vhost_ops->vhost_get_device_id(hdev, &device_id); | ||||
|     if (device_id != VIRTIO_ID_NET) { | ||||
|         return -ENOTSUP; | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static void vhost_vdpa_del(NetClientState *ncs) | ||||
| { | ||||
|     VhostVDPAState *s; | ||||
|     assert(ncs->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|     s = DO_UPCAST(VhostVDPAState, nc, ncs); | ||||
|     if (s->vhost_net) { | ||||
|         vhost_net_cleanup(s->vhost_net); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int vhost_vdpa_add(NetClientState *ncs, void *be) | ||||
| { | ||||
|     VhostNetOptions options; | ||||
|     struct vhost_net *net = NULL; | ||||
|     VhostVDPAState *s; | ||||
|     int ret; | ||||
|  | ||||
|     options.backend_type = VHOST_BACKEND_TYPE_VDPA; | ||||
|     assert(ncs->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|     s = DO_UPCAST(VhostVDPAState, nc, ncs); | ||||
|     options.net_backend = ncs; | ||||
|     options.opaque      = be; | ||||
|     options.busyloop_timeout = 0; | ||||
|  | ||||
|     net = vhost_net_init(&options); | ||||
|     if (!net) { | ||||
|         error_report("failed to init vhost_net for queue"); | ||||
|         goto err; | ||||
|     } | ||||
|     if (s->vhost_net) { | ||||
|         vhost_net_cleanup(s->vhost_net); | ||||
|         g_free(s->vhost_net); | ||||
|     } | ||||
|     s->vhost_net = net; | ||||
|     ret = vhost_vdpa_net_check_device_id(net); | ||||
|     if (ret) { | ||||
|         goto err; | ||||
|     } | ||||
|     return 0; | ||||
| err: | ||||
|     if (net) { | ||||
|         vhost_net_cleanup(net); | ||||
|     } | ||||
|     vhost_vdpa_del(ncs); | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static void vhost_vdpa_cleanup(NetClientState *nc) | ||||
| { | ||||
|     VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | ||||
|  | ||||
|     if (s->vhost_net) { | ||||
|         vhost_net_cleanup(s->vhost_net); | ||||
|         g_free(s->vhost_net); | ||||
|         s->vhost_net = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc) | ||||
| { | ||||
|     assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static bool vhost_vdpa_has_ufo(NetClientState *nc) | ||||
| { | ||||
|     assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|     VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | ||||
|     uint64_t features = 0; | ||||
|     features |= (1ULL << VIRTIO_NET_F_HOST_UFO); | ||||
|     features = vhost_net_get_features(s->vhost_net, features); | ||||
|     return !!(features & (1ULL << VIRTIO_NET_F_HOST_UFO)); | ||||
|  | ||||
| } | ||||
|  | ||||
| static NetClientInfo net_vhost_vdpa_info = { | ||||
|         .type = NET_CLIENT_DRIVER_VHOST_VDPA, | ||||
|         .size = sizeof(VhostVDPAState), | ||||
|         .cleanup = vhost_vdpa_cleanup, | ||||
|         .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, | ||||
|         .has_ufo = vhost_vdpa_has_ufo, | ||||
| }; | ||||
|  | ||||
| static int net_vhost_vdpa_init(NetClientState *peer, const char *device, | ||||
|                                const char *name, const char *vhostdev) | ||||
| { | ||||
|     NetClientState *nc = NULL; | ||||
|     VhostVDPAState *s; | ||||
|     int vdpa_device_fd = -1; | ||||
|     int ret = 0; | ||||
|     assert(name); | ||||
|     nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); | ||||
|     snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); | ||||
|     nc->queue_index = 0; | ||||
|     s = DO_UPCAST(VhostVDPAState, nc, nc); | ||||
|     vdpa_device_fd = qemu_open(vhostdev, O_RDWR); | ||||
|     if (vdpa_device_fd == -1) { | ||||
|         return -errno; | ||||
|     } | ||||
|     s->vhost_vdpa.device_fd = vdpa_device_fd; | ||||
|     ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa); | ||||
|     assert(s->vhost_net); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp) | ||||
| { | ||||
|     const char *name = opaque; | ||||
|     const char *driver, *netdev; | ||||
|  | ||||
|     driver = qemu_opt_get(opts, "driver"); | ||||
|     netdev = qemu_opt_get(opts, "netdev"); | ||||
|     if (!driver || !netdev) { | ||||
|         return 0; | ||||
|     } | ||||
|     if (strcmp(netdev, name) == 0 && | ||||
|         !g_str_has_prefix(driver, "virtio-net-")) { | ||||
|         error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*"); | ||||
|         return -1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int net_init_vhost_vdpa(const Netdev *netdev, const char *name, | ||||
|                         NetClientState *peer, Error **errp) | ||||
| { | ||||
|     const NetdevVhostVDPAOptions *opts; | ||||
|  | ||||
|     assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); | ||||
|     opts = &netdev->u.vhost_vdpa; | ||||
|     /* verify net frontend */ | ||||
|     if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net, | ||||
|                           (char *)name, errp)) { | ||||
|         return -1; | ||||
|     } | ||||
|     return net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, opts->vhostdev); | ||||
| } | ||||
| @@ -428,16 +428,39 @@ | ||||
|     '*vhostforce':    'bool', | ||||
|     '*queues':        'int' } } | ||||
|  | ||||
| ## | ||||
| # @NetdevVhostVDPAOptions: | ||||
| # | ||||
| # Vhost-vdpa network backend | ||||
| # | ||||
| # vDPA device is a device that uses a datapath which complies with the virtio | ||||
| # specifications with a vendor specific control path. | ||||
| # | ||||
| # @vhostdev: path of vhost-vdpa device | ||||
| #            (default:'/dev/vhost-vdpa-0') | ||||
| # | ||||
| # @queues: number of queues to be created for multiqueue vhost-vdpa | ||||
| #          (default: 1) | ||||
| # | ||||
| # Since: 5.1 | ||||
| ## | ||||
| { 'struct': 'NetdevVhostVDPAOptions', | ||||
|   'data': { | ||||
|     '*vhostdev':     'str', | ||||
|     '*queues':       'int' } } | ||||
|  | ||||
| ## | ||||
| # @NetClientDriver: | ||||
| # | ||||
| # Available netdev drivers. | ||||
| # | ||||
| # Since: 2.7 | ||||
| # | ||||
| # @vhost-vdpa since 5.1 | ||||
| ## | ||||
| { 'enum': 'NetClientDriver', | ||||
|   'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', | ||||
|             'bridge', 'hubport', 'netmap', 'vhost-user' ] } | ||||
|             'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa' ] } | ||||
|  | ||||
| ## | ||||
| # @Netdev: | ||||
| @@ -465,7 +488,8 @@ | ||||
|     'bridge':   'NetdevBridgeOptions', | ||||
|     'hubport':  'NetdevHubPortOptions', | ||||
|     'netmap':   'NetdevNetmapOptions', | ||||
|     'vhost-user': 'NetdevVhostUserOptions' } } | ||||
|     'vhost-user': 'NetdevVhostUserOptions', | ||||
|     'vhost-vdpa': 'NetdevVhostVDPAOptions' } } | ||||
|  | ||||
| ## | ||||
| # @NetFilterDirection: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user