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:
parent
22288fe5a3
commit
402378407d
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
105
net/vhost-vdpa.c
105
net/vhost-vdpa.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (i) {
|
||||||
|
qemu_del_net_client(ncs[0]);
|
||||||
|
}
|
||||||
|
qemu_close(vdpa_device_fd);
|
||||||
|
g_free(ncs);
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user