This is a patch based on Krishna Kumar's patch series which implements
multiple VQ support for virtio-net.
The patch was tested with ver3 of the patch.
Cc: Krishna Kumar <krkumar2 at in.ibm.com>
Cc: Michael S. Tsirkin <mst at redhat.com>
Cc: Rusty Russell <rusty at rustcorp.com.au>
Cc: virtualization at lists.linux-foundation.org
Cc: netdev at vger.kernel.org
Signed-off-by: Sasha Levin <levinsasha928 at gmail.com>
---
tools/kvm/include/kvm/virtio-pci.h | 2 +-
tools/kvm/virtio/net.c | 94 +++++++++++++++++++----------------
2 files changed, 52 insertions(+), 44 deletions(-)
diff --git a/tools/kvm/include/kvm/virtio-pci.h
b/tools/kvm/include/kvm/virtio-pci.h
index 2bbb271..94d20ee 100644
--- a/tools/kvm/include/kvm/virtio-pci.h
+++ b/tools/kvm/include/kvm/virtio-pci.h
@@ -6,7 +6,7 @@
#include <linux/types.h>
-#define VIRTIO_PCI_MAX_VQ 3
+#define VIRTIO_PCI_MAX_VQ 16
#define VIRTIO_PCI_MAX_CONFIG 1
struct kvm;
diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c
index cee2b5b..0754795 100644
--- a/tools/kvm/virtio/net.c
+++ b/tools/kvm/virtio/net.c
@@ -27,9 +27,8 @@
#include <sys/wait.h>
#define VIRTIO_NET_QUEUE_SIZE 128
-#define VIRTIO_NET_NUM_QUEUES 2
-#define VIRTIO_NET_RX_QUEUE 0
-#define VIRTIO_NET_TX_QUEUE 1
+#define VIRTIO_NET_NUM_QUEUES 16
+#define VIRTIO_NET_IS_RX_QUEUE(x) (((x) % 2) == 0)
struct net_dev;
@@ -49,14 +48,13 @@ struct net_dev {
struct virtio_net_config config;
u32 features;
- pthread_t io_rx_thread;
- pthread_mutex_t io_rx_lock;
- pthread_cond_t io_rx_cond;
-
- pthread_t io_tx_thread;
- pthread_mutex_t io_tx_lock;
- pthread_cond_t io_tx_cond;
+ pthread_t io_thread[VIRTIO_NET_NUM_QUEUES];
+ pthread_mutex_t io_lock[VIRTIO_NET_NUM_QUEUES];
+ pthread_cond_t io_cond[VIRTIO_NET_NUM_QUEUES];
+ int rx_vq_num;
+ int tx_vq_num;
+ int vq_num;
int tap_fd;
char tap_name[IFNAMSIZ];
@@ -78,17 +76,22 @@ static void *virtio_net_rx_thread(void *p)
struct net_dev *ndev = p;
u16 out, in;
u16 head;
- int len;
+ int len, queue_num;
+
+ mutex_lock(&ndev->mutex);
+ queue_num = ndev->rx_vq_num * 2;
+ ndev->tx_vq_num++;
+ mutex_unlock(&ndev->mutex);
kvm = ndev->kvm;
- vq = &ndev->vqs[VIRTIO_NET_RX_QUEUE];
+ vq = &ndev->vqs[queue_num];
while (1) {
- mutex_lock(&ndev->io_rx_lock);
+ mutex_lock(&ndev->io_lock[queue_num]);
if (!virt_queue__available(vq))
- pthread_cond_wait(&ndev->io_rx_cond, &ndev->io_rx_lock);
- mutex_unlock(&ndev->io_rx_lock);
+ pthread_cond_wait(&ndev->io_cond[queue_num],
&ndev->io_lock[queue_num]);
+ mutex_unlock(&ndev->io_lock[queue_num]);
while (virt_queue__available(vq)) {
@@ -99,7 +102,7 @@ static void *virtio_net_rx_thread(void *p)
virt_queue__set_used_elem(vq, head, len);
/* We should interrupt guest right now, otherwise latency is huge. */
- ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans,
VIRTIO_NET_RX_QUEUE);
+ ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans,
queue_num);
}
}
@@ -117,16 +120,21 @@ static void *virtio_net_tx_thread(void *p)
struct net_dev *ndev = p;
u16 out, in;
u16 head;
- int len;
+ int len, queue_num;
+
+ mutex_lock(&ndev->mutex);
+ queue_num = ndev->tx_vq_num * 2 + 1;
+ ndev->tx_vq_num++;
+ mutex_unlock(&ndev->mutex);
kvm = ndev->kvm;
- vq = &ndev->vqs[VIRTIO_NET_TX_QUEUE];
+ vq = &ndev->vqs[queue_num];
while (1) {
- mutex_lock(&ndev->io_tx_lock);
+ mutex_lock(&ndev->io_lock[queue_num]);
if (!virt_queue__available(vq))
- pthread_cond_wait(&ndev->io_tx_cond, &ndev->io_tx_lock);
- mutex_unlock(&ndev->io_tx_lock);
+ pthread_cond_wait(&ndev->io_cond[queue_num],
&ndev->io_lock[queue_num]);
+ mutex_unlock(&ndev->io_lock[queue_num]);
while (virt_queue__available(vq)) {
@@ -137,7 +145,7 @@ static void *virtio_net_tx_thread(void *p)
virt_queue__set_used_elem(vq, head, len);
}
- ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans,
VIRTIO_NET_TX_QUEUE);
+ ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans,
queue_num);
}
pthread_exit(NULL);
@@ -148,20 +156,9 @@ static void *virtio_net_tx_thread(void *p)
static void virtio_net_handle_callback(struct kvm *kvm, struct net_dev *ndev,
int queue)
{
- switch (queue) {
- case VIRTIO_NET_TX_QUEUE:
- mutex_lock(&ndev->io_tx_lock);
- pthread_cond_signal(&ndev->io_tx_cond);
- mutex_unlock(&ndev->io_tx_lock);
- break;
- case VIRTIO_NET_RX_QUEUE:
- mutex_lock(&ndev->io_rx_lock);
- pthread_cond_signal(&ndev->io_rx_cond);
- mutex_unlock(&ndev->io_rx_lock);
- break;
- default:
- pr_warning("Unknown queue index %u", queue);
- }
+ mutex_lock(&ndev->io_lock[queue]);
+ pthread_cond_signal(&ndev->io_cond[queue]);
+ mutex_unlock(&ndev->io_lock[queue]);
}
static bool virtio_net__tap_init(const struct virtio_net_params *params,
@@ -248,14 +245,17 @@ fail:
static void virtio_net__io_thread_init(struct kvm *kvm, struct net_dev *ndev)
{
- pthread_mutex_init(&ndev->io_tx_lock, NULL);
- pthread_mutex_init(&ndev->io_rx_lock, NULL);
+ int i;
- pthread_cond_init(&ndev->io_tx_cond, NULL);
- pthread_cond_init(&ndev->io_rx_cond, NULL);
+ for (i = 0; i < ndev->vq_num; i++) {
+ pthread_mutex_init(&ndev->io_lock[i], NULL);
+ pthread_cond_init(&ndev->io_cond[i], NULL);
+ }
- pthread_create(&ndev->io_tx_thread, NULL, virtio_net_tx_thread, ndev);
- pthread_create(&ndev->io_rx_thread, NULL, virtio_net_rx_thread, ndev);
+ for (i = 0; i < ndev->vq_num; i += 2) {
+ pthread_create(&ndev->io_thread[i], NULL, virtio_net_tx_thread, ndev);
+ pthread_create(&ndev->io_thread[i + 1], NULL, virtio_net_rx_thread,
ndev);
+ }
}
static inline int tap_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
@@ -311,13 +311,19 @@ static u32 get_host_features(struct kvm *kvm, void *dev)
| 1UL << VIRTIO_NET_F_HOST_TSO6
| 1UL << VIRTIO_NET_F_GUEST_UFO
| 1UL << VIRTIO_NET_F_GUEST_TSO4
- | 1UL << VIRTIO_NET_F_GUEST_TSO6;
+ | 1UL << VIRTIO_NET_F_GUEST_TSO6
+ | 1UL << VIRTIO_NET_F_MULTIQUEUE;
}
static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
{
struct net_dev *ndev = dev;
+ if (features & (1UL << VIRTIO_NET_F_MULTIQUEUE))
+ ndev->vq_num = ndev->config.num_queues;
+ else
+ ndev->vq_num = 2;
+
ndev->features = features;
}
@@ -395,6 +401,8 @@ void virtio_net__init(const struct virtio_net_params
*params)
ndev->info.host_mac.addr[i] = params->host_mac[i];
}
+ ndev->config.num_queues = VIRTIO_NET_NUM_QUEUES;
+
ndev->mode = params->mode;
if (ndev->mode == NET_MODE_TAP) {
if (!virtio_net__tap_init(params, ndev))
--
1.7.7.2
Michael S. Tsirkin
2011-Nov-13 10:24 UTC
[RFC] kvm tools: Implement multiple VQ for virtio-net
On Sat, Nov 12, 2011 at 12:12:01AM +0200, Sasha Levin wrote:> This is a patch based on Krishna Kumar's patch series which implements > multiple VQ support for virtio-net. > > The patch was tested with ver3 of the patch. > > Cc: Krishna Kumar <krkumar2 at in.ibm.com> > Cc: Michael S. Tsirkin <mst at redhat.com> > Cc: Rusty Russell <rusty at rustcorp.com.au> > Cc: virtualization at lists.linux-foundation.org > Cc: netdev at vger.kernel.org > Signed-off-by: Sasha Levin <levinsasha928 at gmail.com>Any performance numbers?> --- > tools/kvm/include/kvm/virtio-pci.h | 2 +- > tools/kvm/virtio/net.c | 94 +++++++++++++++++++---------------- > 2 files changed, 52 insertions(+), 44 deletions(-) > > diff --git a/tools/kvm/include/kvm/virtio-pci.h b/tools/kvm/include/kvm/virtio-pci.h > index 2bbb271..94d20ee 100644 > --- a/tools/kvm/include/kvm/virtio-pci.h > +++ b/tools/kvm/include/kvm/virtio-pci.h > @@ -6,7 +6,7 @@ > > #include <linux/types.h> > > -#define VIRTIO_PCI_MAX_VQ 3 > +#define VIRTIO_PCI_MAX_VQ 16 > #define VIRTIO_PCI_MAX_CONFIG 1 > > struct kvm; > diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c > index cee2b5b..0754795 100644 > --- a/tools/kvm/virtio/net.c > +++ b/tools/kvm/virtio/net.c > @@ -27,9 +27,8 @@ > #include <sys/wait.h> > > #define VIRTIO_NET_QUEUE_SIZE 128 > -#define VIRTIO_NET_NUM_QUEUES 2 > -#define VIRTIO_NET_RX_QUEUE 0 > -#define VIRTIO_NET_TX_QUEUE 1 > +#define VIRTIO_NET_NUM_QUEUES 16 > +#define VIRTIO_NET_IS_RX_QUEUE(x) (((x) % 2) == 0) > > struct net_dev; > > @@ -49,14 +48,13 @@ struct net_dev { > struct virtio_net_config config; > u32 features; > > - pthread_t io_rx_thread; > - pthread_mutex_t io_rx_lock; > - pthread_cond_t io_rx_cond; > - > - pthread_t io_tx_thread; > - pthread_mutex_t io_tx_lock; > - pthread_cond_t io_tx_cond; > + pthread_t io_thread[VIRTIO_NET_NUM_QUEUES]; > + pthread_mutex_t io_lock[VIRTIO_NET_NUM_QUEUES]; > + pthread_cond_t io_cond[VIRTIO_NET_NUM_QUEUES]; > > + int rx_vq_num; > + int tx_vq_num; > + int vq_num; > int tap_fd; > char tap_name[IFNAMSIZ]; > > @@ -78,17 +76,22 @@ static void *virtio_net_rx_thread(void *p) > struct net_dev *ndev = p; > u16 out, in; > u16 head; > - int len; > + int len, queue_num; > + > + mutex_lock(&ndev->mutex); > + queue_num = ndev->rx_vq_num * 2; > + ndev->tx_vq_num++; > + mutex_unlock(&ndev->mutex); > > kvm = ndev->kvm; > - vq = &ndev->vqs[VIRTIO_NET_RX_QUEUE]; > + vq = &ndev->vqs[queue_num]; > > while (1) { > > - mutex_lock(&ndev->io_rx_lock); > + mutex_lock(&ndev->io_lock[queue_num]); > if (!virt_queue__available(vq)) > - pthread_cond_wait(&ndev->io_rx_cond, &ndev->io_rx_lock); > - mutex_unlock(&ndev->io_rx_lock); > + pthread_cond_wait(&ndev->io_cond[queue_num], &ndev->io_lock[queue_num]); > + mutex_unlock(&ndev->io_lock[queue_num]); > > while (virt_queue__available(vq)) { > > @@ -99,7 +102,7 @@ static void *virtio_net_rx_thread(void *p) > virt_queue__set_used_elem(vq, head, len); > > /* We should interrupt guest right now, otherwise latency is huge. */ > - ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans, VIRTIO_NET_RX_QUEUE); > + ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans, queue_num); > } > > } > @@ -117,16 +120,21 @@ static void *virtio_net_tx_thread(void *p) > struct net_dev *ndev = p; > u16 out, in; > u16 head; > - int len; > + int len, queue_num; > + > + mutex_lock(&ndev->mutex); > + queue_num = ndev->tx_vq_num * 2 + 1; > + ndev->tx_vq_num++; > + mutex_unlock(&ndev->mutex); > > kvm = ndev->kvm; > - vq = &ndev->vqs[VIRTIO_NET_TX_QUEUE]; > + vq = &ndev->vqs[queue_num]; > > while (1) { > - mutex_lock(&ndev->io_tx_lock); > + mutex_lock(&ndev->io_lock[queue_num]); > if (!virt_queue__available(vq)) > - pthread_cond_wait(&ndev->io_tx_cond, &ndev->io_tx_lock); > - mutex_unlock(&ndev->io_tx_lock); > + pthread_cond_wait(&ndev->io_cond[queue_num], &ndev->io_lock[queue_num]); > + mutex_unlock(&ndev->io_lock[queue_num]); > > while (virt_queue__available(vq)) { > > @@ -137,7 +145,7 @@ static void *virtio_net_tx_thread(void *p) > virt_queue__set_used_elem(vq, head, len); > } > > - ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans, VIRTIO_NET_TX_QUEUE); > + ndev->vtrans.trans_ops->signal_vq(kvm, &ndev->vtrans, queue_num); > } > > pthread_exit(NULL); > @@ -148,20 +156,9 @@ static void *virtio_net_tx_thread(void *p) > > static void virtio_net_handle_callback(struct kvm *kvm, struct net_dev *ndev, int queue) > { > - switch (queue) { > - case VIRTIO_NET_TX_QUEUE: > - mutex_lock(&ndev->io_tx_lock); > - pthread_cond_signal(&ndev->io_tx_cond); > - mutex_unlock(&ndev->io_tx_lock); > - break; > - case VIRTIO_NET_RX_QUEUE: > - mutex_lock(&ndev->io_rx_lock); > - pthread_cond_signal(&ndev->io_rx_cond); > - mutex_unlock(&ndev->io_rx_lock); > - break; > - default: > - pr_warning("Unknown queue index %u", queue); > - } > + mutex_lock(&ndev->io_lock[queue]); > + pthread_cond_signal(&ndev->io_cond[queue]); > + mutex_unlock(&ndev->io_lock[queue]); > } > > static bool virtio_net__tap_init(const struct virtio_net_params *params, > @@ -248,14 +245,17 @@ fail: > > static void virtio_net__io_thread_init(struct kvm *kvm, struct net_dev *ndev) > { > - pthread_mutex_init(&ndev->io_tx_lock, NULL); > - pthread_mutex_init(&ndev->io_rx_lock, NULL); > + int i; > > - pthread_cond_init(&ndev->io_tx_cond, NULL); > - pthread_cond_init(&ndev->io_rx_cond, NULL); > + for (i = 0; i < ndev->vq_num; i++) { > + pthread_mutex_init(&ndev->io_lock[i], NULL); > + pthread_cond_init(&ndev->io_cond[i], NULL); > + } > > - pthread_create(&ndev->io_tx_thread, NULL, virtio_net_tx_thread, ndev); > - pthread_create(&ndev->io_rx_thread, NULL, virtio_net_rx_thread, ndev); > + for (i = 0; i < ndev->vq_num; i += 2) { > + pthread_create(&ndev->io_thread[i], NULL, virtio_net_tx_thread, ndev); > + pthread_create(&ndev->io_thread[i + 1], NULL, virtio_net_rx_thread, ndev); > + } > } > > static inline int tap_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev) > @@ -311,13 +311,19 @@ static u32 get_host_features(struct kvm *kvm, void *dev) > | 1UL << VIRTIO_NET_F_HOST_TSO6 > | 1UL << VIRTIO_NET_F_GUEST_UFO > | 1UL << VIRTIO_NET_F_GUEST_TSO4 > - | 1UL << VIRTIO_NET_F_GUEST_TSO6; > + | 1UL << VIRTIO_NET_F_GUEST_TSO6 > + | 1UL << VIRTIO_NET_F_MULTIQUEUE; > } > > static void set_guest_features(struct kvm *kvm, void *dev, u32 features) > { > struct net_dev *ndev = dev; > > + if (features & (1UL << VIRTIO_NET_F_MULTIQUEUE)) > + ndev->vq_num = ndev->config.num_queues; > + else > + ndev->vq_num = 2; > + > ndev->features = features; > } > > @@ -395,6 +401,8 @@ void virtio_net__init(const struct virtio_net_params *params) > ndev->info.host_mac.addr[i] = params->host_mac[i]; > } > > + ndev->config.num_queues = VIRTIO_NET_NUM_QUEUES; > + > ndev->mode = params->mode; > if (ndev->mode == NET_MODE_TAP) { > if (!virtio_net__tap_init(params, ndev)) > -- > 1.7.7.2
Reasonably Related Threads
- [RFC] kvm tools: Implement multiple VQ for virtio-net
- [RFC] kvm tools: Add support for virtio-mmio
- [RFC] kvm tools: Add support for virtio-mmio
- [PATCH 2/2] virtio-serial: setup_port_vq when adding port
- [PATCH 2/2] virtio-serial: setup_port_vq when adding port