This patch adds support to using the vhost-net device when using a tap backed
virtio-net device.
Activating vhost-net is done by appending a 'vhost=1' flag to the net device
configuration. For example:
'kvm run -n mode=tap,vhost=1'
Cc: Michael S. Tsirkin m...@redhat.com
Signed-off-by: Sasha Levin levinsasha...@gmail.com
---
tools/kvm/builtin-run.c|2 +
tools/kvm/include/kvm/virtio-net.h |1 +
tools/kvm/virtio/net.c | 120 +++-
3 files changed, 122 insertions(+), 1 deletions(-)
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
index 13025db..3b00bf0 100644
--- a/tools/kvm/builtin-run.c
+++ b/tools/kvm/builtin-run.c
@@ -217,6 +217,8 @@ static int set_net_param(struct virtio_net_params *p, const
char *param,
p-guest_ip = strdup(val);
} else if (strcmp(param, host_ip) == 0) {
p-host_ip = strdup(val);
+ } else if (strcmp(param, vhost) == 0) {
+ p-vhost = atoi(val);
}
return 0;
diff --git a/tools/kvm/include/kvm/virtio-net.h
b/tools/kvm/include/kvm/virtio-net.h
index 58ae162..dade8cb 100644
--- a/tools/kvm/include/kvm/virtio-net.h
+++ b/tools/kvm/include/kvm/virtio-net.h
@@ -11,6 +11,7 @@ struct virtio_net_params {
char host_mac[6];
struct kvm *kvm;
int mode;
+ int vhost;
};
void virtio_net__init(const struct virtio_net_params *params);
diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c
index cee2b5b..58ca4ed 100644
--- a/tools/kvm/virtio/net.c
+++ b/tools/kvm/virtio/net.c
@@ -10,6 +10,7 @@
#include kvm/guest_compat.h
#include kvm/virtio-trans.h
+#include linux/vhost.h
#include linux/virtio_net.h
#include linux/if_tun.h
#include linux/types.h
@@ -25,6 +26,7 @@
#include sys/ioctl.h
#include sys/types.h
#include sys/wait.h
+#include sys/eventfd.h
#define VIRTIO_NET_QUEUE_SIZE 128
#define VIRTIO_NET_NUM_QUEUES 2
@@ -57,6 +59,7 @@ struct net_dev {
pthread_mutex_t io_tx_lock;
pthread_cond_t io_tx_cond;
+ int vhost_fd;
int tap_fd;
chartap_name[IFNAMSIZ];
@@ -323,9 +326,12 @@ static void set_guest_features(struct kvm *kvm, void *dev,
u32 features)
static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
{
+ struct vhost_vring_state state = { .index = vq };
+ struct vhost_vring_addr addr;
struct net_dev *ndev = dev;
struct virt_queue *queue;
void *p;
+ int r;
compat__remove_message(compat_id);
@@ -335,9 +341,82 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32
pfn)
vring_init(queue-vring, VIRTIO_NET_QUEUE_SIZE, p,
VIRTIO_PCI_VRING_ALIGN);
+ if (ndev-vhost_fd == 0)
+ return 0;
+
+ state.num = queue-vring.num;
+ r = ioctl(ndev-vhost_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);
+ if (r 0)
+ die_perror(VHOST_SET_VRING_BASE failed);
+
+ addr = (struct vhost_vring_addr) {
+ .index = vq,
+ .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);
+ if (r 0)
+ die_perror(VHOST_SET_VRING_ADDR failed);
+
return 0;
}
+static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
+{
+ struct net_dev *ndev = dev;
+ struct kvm_irqfd irq;
+ struct vhost_vring_file file;
+ int r;
+
+ if (ndev-vhost_fd == 0)
+ return;
+
+ irq = (struct kvm_irqfd) {
+ .gsi= gsi,
+ .fd = eventfd(0, 0),
+ };
+ file = (struct vhost_vring_file) {
+ .index = vq,
+ .fd = irq.fd,
+ };
+
+ r = ioctl(kvm-vm_fd, KVM_IRQFD, irq);
+ if (r 0)
+ die_perror(KVM_IRQFD failed);
+
+ r = ioctl(ndev-vhost_fd, 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);
+ 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,
+ .fd = efd,
+ };
+ int r;
+
+ if (ndev-vhost_fd == 0)
+ return;
+
+ r = ioctl(ndev-vhost_fd,