Commit 6243375f9bba12d8871ac611ca8ce947c3e16c67

Authored by Mark McLoughlin
Committed by Anthony Liguori
1 parent 783527a9

virtio-net: implement async packet sending

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing 1 changed file with 37 additions and 2 deletions
hw/virtio-net.c
... ... @@ -32,6 +32,10 @@ typedef struct VirtIONet
32 32 VLANClientState *vc;
33 33 QEMUTimer *tx_timer;
34 34 int tx_timer_active;
  35 + struct {
  36 + VirtQueueElement elem;
  37 + ssize_t len;
  38 + } async_tx;
35 39 int mergeable_rx_bufs;
36 40 uint8_t promisc;
37 41 uint8_t allmulti;
... ... @@ -483,6 +487,21 @@ static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_
483 487 return size;
484 488 }
485 489  
  490 +static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq);
  491 +
  492 +static void virtio_net_tx_complete(VLANClientState *vc, ssize_t len)
  493 +{
  494 + VirtIONet *n = vc->opaque;
  495 +
  496 + virtqueue_push(n->tx_vq, &n->async_tx.elem, n->async_tx.len);
  497 + virtio_notify(&n->vdev, n->tx_vq);
  498 +
  499 + n->async_tx.elem.out_num = n->async_tx.len = 0;
  500 +
  501 + virtio_queue_set_notification(n->tx_vq, 1);
  502 + virtio_net_flush_tx(n, n->tx_vq);
  503 +}
  504 +
486 505 /* TX */
487 506 static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
488 507 {
... ... @@ -492,8 +511,13 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
492 511 if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
493 512 return;
494 513  
  514 + if (n->async_tx.elem.out_num) {
  515 + virtio_queue_set_notification(n->tx_vq, 0);
  516 + return;
  517 + }
  518 +
495 519 while (virtqueue_pop(vq, &elem)) {
496   - ssize_t len = 0;
  520 + ssize_t ret, len = 0;
497 521 unsigned int out_num = elem.out_num;
498 522 struct iovec *out_sg = &elem.out_sg[0];
499 523 unsigned hdr_len;
... ... @@ -520,7 +544,16 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
520 544 len += hdr_len;
521 545 }
522 546  
523   - len += qemu_sendv_packet(n->vc, out_sg, out_num);
  547 + ret = qemu_sendv_packet_async(n->vc, out_sg, out_num,
  548 + virtio_net_tx_complete);
  549 + if (ret == 0) {
  550 + virtio_queue_set_notification(n->tx_vq, 0);
  551 + n->async_tx.elem = elem;
  552 + n->async_tx.len = len;
  553 + return;
  554 + }
  555 +
  556 + len += ret;
524 557  
525 558 virtqueue_push(vq, &elem, len);
526 559 virtio_notify(&n->vdev, vq);
... ... @@ -663,6 +696,8 @@ static void virtio_net_cleanup(VLANClientState *vc)
663 696 {
664 697 VirtIONet *n = vc->opaque;
665 698  
  699 + qemu_purge_queued_packets(vc);
  700 +
666 701 unregister_savevm("virtio-net", n);
667 702  
668 703 qemu_free(n->mac_table.macs);
... ...