vhost-vdpa: multiqueue support

This patch implements the multiqueue support for vhost-vdpa. This is
done simply by reading the number of queue pairs from the config space
and initialize the datapath and control path net client.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20211020045600.16082-11-jasowang@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Jason Wang 2021-10-20 12:56:00 +08:00 committed by Michael S. Tsirkin
parent 22288fe5a3
commit 402378407d
2 changed files with 97 additions and 10 deletions

View File

@ -632,7 +632,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
} }
if (vhost_vdpa_one_time_request(dev)) { if (dev->vq_index + dev->nvqs != dev->last_index) {
return 0; return 0;
} }

View File

@ -18,6 +18,7 @@
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qapi/error.h" #include "qapi/error.h"
#include <linux/vhost.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <err.h> #include <err.h>
#include "standard-headers/linux/virtio_net.h" #include "standard-headers/linux/virtio_net.h"
@ -51,6 +52,14 @@ const int vdpa_feature_bits[] = {
VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_UFO,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_MRG_RXBUF,
VIRTIO_NET_F_MTU, VIRTIO_NET_F_MTU,
VIRTIO_NET_F_CTRL_RX,
VIRTIO_NET_F_CTRL_RX_EXTRA,
VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_NET_F_GUEST_ANNOUNCE,
VIRTIO_NET_F_CTRL_MAC_ADDR,
VIRTIO_NET_F_RSS,
VIRTIO_NET_F_MQ,
VIRTIO_NET_F_CTRL_VQ,
VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_PACKED, VIRTIO_F_RING_PACKED,
VIRTIO_NET_F_RSS, VIRTIO_NET_F_RSS,
@ -81,7 +90,8 @@ static int vhost_vdpa_net_check_device_id(struct vhost_net *net)
return ret; return ret;
} }
static int vhost_vdpa_add(NetClientState *ncs, void *be) static int vhost_vdpa_add(NetClientState *ncs, void *be,
int queue_pair_index, int nvqs)
{ {
VhostNetOptions options; VhostNetOptions options;
struct vhost_net *net = NULL; struct vhost_net *net = NULL;
@ -94,7 +104,7 @@ static int vhost_vdpa_add(NetClientState *ncs, void *be)
options.net_backend = ncs; options.net_backend = ncs;
options.opaque = be; options.opaque = be;
options.busyloop_timeout = 0; options.busyloop_timeout = 0;
options.nvqs = 2; options.nvqs = nvqs;
net = vhost_net_init(&options); net = vhost_net_init(&options);
if (!net) { if (!net) {
@ -172,18 +182,28 @@ static NetClientInfo net_vhost_vdpa_info = {
static NetClientState *net_vhost_vdpa_init(NetClientState *peer, static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
const char *device, const char *device,
const char *name, const char *name,
int vdpa_device_fd) int vdpa_device_fd,
int queue_pair_index,
int nvqs,
bool is_datapath)
{ {
NetClientState *nc = NULL; NetClientState *nc = NULL;
VhostVDPAState *s; VhostVDPAState *s;
int ret = 0; int ret = 0;
assert(name); assert(name);
nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); if (is_datapath) {
nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device,
name);
} else {
nc = qemu_new_net_control_client(&net_vhost_vdpa_info, peer,
device, name);
}
snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA);
s = DO_UPCAST(VhostVDPAState, nc, nc); s = DO_UPCAST(VhostVDPAState, nc, nc);
s->vhost_vdpa.device_fd = vdpa_device_fd; s->vhost_vdpa.device_fd = vdpa_device_fd;
ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa); s->vhost_vdpa.index = queue_pair_index;
ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs);
if (ret) { if (ret) {
qemu_del_net_client(nc); qemu_del_net_client(nc);
return NULL; return NULL;
@ -191,12 +211,52 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
return nc; return nc;
} }
static int vhost_vdpa_get_max_queue_pairs(int fd, int *has_cvq, Error **errp)
{
unsigned long config_size = offsetof(struct vhost_vdpa_config, buf);
struct vhost_vdpa_config *config;
__virtio16 *max_queue_pairs;
uint64_t features;
int ret;
ret = ioctl(fd, VHOST_GET_FEATURES, &features);
if (ret) {
error_setg(errp, "Fail to query features from vhost-vDPA device");
return ret;
}
if (features & (1 << VIRTIO_NET_F_CTRL_VQ)) {
*has_cvq = 1;
} else {
*has_cvq = 0;
}
if (features & (1 << VIRTIO_NET_F_MQ)) {
config = g_malloc0(config_size + sizeof(*max_queue_pairs));
config->off = offsetof(struct virtio_net_config, max_virtqueue_pairs);
config->len = sizeof(*max_queue_pairs);
ret = ioctl(fd, VHOST_VDPA_GET_CONFIG, config);
if (ret) {
error_setg(errp, "Fail to get config from vhost-vDPA device");
return -ret;
}
max_queue_pairs = (__virtio16 *)&config->buf;
return lduw_le_p(max_queue_pairs);
}
return 1;
}
int net_init_vhost_vdpa(const Netdev *netdev, const char *name, int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp) NetClientState *peer, Error **errp)
{ {
const NetdevVhostVDPAOptions *opts; const NetdevVhostVDPAOptions *opts;
int vdpa_device_fd; int vdpa_device_fd;
NetClientState *nc; NetClientState **ncs, *nc;
int queue_pairs, i, has_cvq = 0;
assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
opts = &netdev->u.vhost_vdpa; opts = &netdev->u.vhost_vdpa;
@ -206,11 +266,38 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
return -errno; return -errno;
} }
nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, vdpa_device_fd); queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd,
if (!nc) { &has_cvq, errp);
if (queue_pairs < 0) {
qemu_close(vdpa_device_fd); qemu_close(vdpa_device_fd);
return -1; return queue_pairs;
} }
return 0; ncs = g_malloc0(sizeof(*ncs) * queue_pairs);
for (i = 0; i < queue_pairs; i++) {
ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name,
vdpa_device_fd, i, 2, true);
if (!ncs[i])
goto err;
}
if (has_cvq) {
nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name,
vdpa_device_fd, i, 1, false);
if (!nc)
goto err;
}
g_free(ncs);
return 0;
err:
if (i) {
qemu_del_net_client(ncs[0]);
}
qemu_close(vdpa_device_fd);
g_free(ncs);
return -1;
} }