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@xxxxxxxxxx> > Cc: Michael S. Tsirkin <mst@xxxxxxxxxx> > Cc: Rusty Russell <rusty@xxxxxxxxxxxxxxx> > Cc: virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx > Cc: netdev@xxxxxxxxxxxxxxx > Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> 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 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html