[KVMTOOL][PATCHv2] vhost-net: enable multiqueue support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch enables vhost-net multi queue support in kvmtool, without any Linux kernel modification.
The patch takes the same approach as QEMU -- for each queue pair a new /dev/vhost-net fd is created.
Fds are kept in ndev->vhost_fds, with ndev->vhost_fd == ndev->vhost_fds[0] (to avoid further modification to the existent source code).
Thanks, Antonio Barbalace

----

diff --git a/virtio/net.c b/virtio/net.c
index 1ee3c19..acdd741 100644
--- a/virtio/net.c
+++ b/virtio/net.c
@@ -58,6 +58,7 @@ struct net_dev {
 u32features, queue_pairs;

 intvhost_fd;
+intvhost_fds[VIRTIO_NET_NUM_QUEUES];
 inttap_fd;
 chartap_name[IFNAMSIZ];
 booltap_ufo;
@@ -512,6 +513,8 @@ static int virtio_net__vhost_set_features(struct net_dev *ndev)
 {
 u64 features = 1UL << VIRTIO_RING_F_EVENT_IDX;
 u64 vhost_features;
+u32 i;
+int r = 0;

 if (ioctl(ndev->vhost_fd, VHOST_GET_FEATURES, &vhost_features) != 0)
 die_perror("VHOST_GET_FEATURES failed");
@@ -521,7 +524,13 @@ static int virtio_net__vhost_set_features(struct net_dev *ndev)
 has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF))
 features |= 1UL << VIRTIO_NET_F_MRG_RXBUF;

-return ioctl(ndev->vhost_fd, VHOST_SET_FEATURES, &features);
+for (i = 0 ; i < ndev->queue_pairs ; i++) {
+r = ioctl(ndev->vhost_fds[i], VHOST_SET_FEATURES, &features);
+if (r < 0)
+break;
+}
+
+return r;
 }

 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
@@ -578,13 +587,13 @@ static bool is_ctrl_vq(struct net_dev *ndev, u32 vq)
 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
    u32 pfn)
 {
-struct vhost_vring_state state = { .index = vq };
+struct vhost_vring_state state = { .index = vq % 2 };
 struct net_dev_queue *net_queue;
 struct vhost_vring_addr addr;
 struct net_dev *ndev = dev;
 struct virt_queue *queue;
 void *p;
-int r;
+int r, vq_fd = vq / 2;

 compat__remove_message(compat_id);

@@ -619,23 +628,24 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
 if (queue->endian != VIRTIO_ENDIAN_HOST)
 die_perror("VHOST requires the same endianness in guest and host");

-state.num = queue->vring.num;
-r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_NUM, &state);
+state.num = queue->vring.num;
+r = ioctl(ndev->vhost_fds[vq_fd], VHOST_SET_VRING_NUM, &state);
 if (r < 0)
 die_perror("VHOST_SET_VRING_NUM failed");
+
 state.num = 0;
-r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_BASE, &state);
+r = ioctl(ndev->vhost_fds[vq_fd], VHOST_SET_VRING_BASE, &state);
 if (r < 0)
 die_perror("VHOST_SET_VRING_BASE failed");

 addr = (struct vhost_vring_addr) {
-.index = vq,
+.index = vq % 2,
 .desc_user_addr = (u64)(unsigned long)queue->vring.desc,
 .avail_user_addr = (u64)(unsigned long)queue->vring.avail,
 .used_user_addr = (u64)(unsigned long)queue->vring.used,
 };

-r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_ADDR, &addr);
+r = ioctl(ndev->vhost_fds[vq_fd], VHOST_SET_VRING_ADDR, &addr);
 if (r < 0)
 die_perror("VHOST_SET_VRING_ADDR failed");

@@ -659,7 +669,7 @@ static void exit_vq(struct kvm *kvm, void *dev, u32 vq)
  */
 if (ndev->vhost_fd && !is_ctrl_vq(ndev, vq)) {
 pr_warning("Cannot reset VHOST queue");
-ioctl(ndev->vhost_fd, VHOST_RESET_OWNER);
+ioctl(ndev->vhost_fds[(vq /2)], VHOST_RESET_OWNER);
 return;
 }

@@ -682,7 +692,7 @@ static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
 return;

 file = (struct vhost_vring_file) {
-.index= vq,
+.index= vq % 2,
 .fd= eventfd(0, 0),
 };

@@ -693,29 +703,30 @@ static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
 queue->irqfd = file.fd;
 queue->gsi = gsi;

-r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_CALL, &file);
+r = ioctl(ndev->vhost_fds[(vq /2)], VHOST_SET_VRING_CALL, &file);
 if (r < 0)
 die_perror("VHOST_SET_VRING_CALL failed");
+
 file.fd = ndev->tap_fd;
-r = ioctl(ndev->vhost_fd, VHOST_NET_SET_BACKEND, &file);
+r = ioctl(ndev->vhost_fds[(vq /2)], VHOST_NET_SET_BACKEND, &file);
 if (r != 0)
 die("VHOST_NET_SET_BACKEND failed %d", errno);
-
 }

 static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd)
 {
 struct net_dev *ndev = dev;
 struct vhost_vring_file file = {
-.index= vq,
+.index= vq % 2,
 .fd= efd,
 };
 int r;

-if (ndev->vhost_fd == 0 || is_ctrl_vq(ndev, vq))
+if (ndev->vhost_fd == 0 || is_ctrl_vq(ndev, vq)) {
 return;
+}
+r = ioctl(ndev->vhost_fds[(vq /2)], VHOST_SET_VRING_KICK, &file);

-r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_KICK, &file);
 if (r < 0)
 die_perror("VHOST_SET_VRING_KICK failed");
 }
@@ -777,10 +788,6 @@ static void virtio_net__vhost_init(struct kvm *kvm, struct net_dev *ndev)
 struct vhost_memory *mem;
 int r, i;

-ndev->vhost_fd = open("/dev/vhost-net", O_RDWR);
-if (ndev->vhost_fd < 0)
-die_perror("Failed openning vhost-net device");
-
 mem = calloc(1, sizeof(*mem) + kvm->mem_slots * sizeof(struct vhost_memory_region));
 if (mem == NULL)
 die("Failed allocating memory for vhost memory map");
@@ -796,13 +803,22 @@ static void virtio_net__vhost_init(struct kvm *kvm, struct net_dev *ndev)
 }
 mem->nregions = i;

-r = ioctl(ndev->vhost_fd, VHOST_SET_OWNER);
-if (r != 0)
-die_perror("VHOST_SET_OWNER failed");
+for (i = 0 ; (i < (int)ndev->queue_pairs) &&
+(i < VIRTIO_NET_NUM_QUEUES) ; i++) {

-r = ioctl(ndev->vhost_fd, VHOST_SET_MEM_TABLE, mem);
-if (r != 0)
-die_perror("VHOST_SET_MEM_TABLE failed");
+ndev->vhost_fds[i] = open("/dev/vhost-net", O_RDWR);
+if (ndev->vhost_fds[i] < 0)
+die_perror("Failed openning vhost-net device");
+
+r = ioctl(ndev->vhost_fds[i], VHOST_SET_OWNER);
+if (r != 0)
+die_perror("VHOST_SET_OWNER failed");
+
+r = ioctl(ndev->vhost_fds[i], VHOST_SET_MEM_TABLE, mem);
+if (r != 0)
+die_perror("VHOST_SET_MEM_TABLE failed");
+}
+ndev->vhost_fd = ndev->vhost_fds[0];

 ndev->vdev.use_vhost = true;

diff --git a/virtio/pci.c b/virtio/pci.c
index c652949..2c456df 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -44,7 +44,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde
  * Vhost will poll the eventfd in host kernel side, otherwise we
  * need to poll in userspace.
  */
-if (!vdev->use_vhost)
+if (!vdev->use_vhost || (vdev->ops->get_vq_count(kvm, vpci->dev) == (int)vq + 1))
 flags |= IOEVENTFD_FLAG_USER_POLL;

 /* ioport */



The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux