func: static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
  
  {
  
      VirtQueueElement elem;
  
  
  
      if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
  
          return;
  
  
  
      if (n->async_tx.elem.out_num) {
  
          virtio_queue_set_notification(n->tx_vq, 0);
  
          return;
  
      }
  
  
  
      while (virtqueue_pop(vq, &elem)) {
  
          ssize_t ret, len = 0;
  
          unsigned int out_num = elem.out_num;
  
          struct iovec *out_sg = &elem.out_sg[0];
  
          unsigned hdr_len;
  
  
  
          /* hdr_len refers to the header received from the guest */
  
          hdr_len = n->mergeable_rx_bufs ?
  
              sizeof(struct virtio_net_hdr_mrg_rxbuf) :
  
              sizeof(struct virtio_net_hdr);
  
  
  
          if (out_num < 1 || out_sg->iov_len != hdr_len) {
  
              fprintf(stderr, "virtio-net header not in first element\n");
  
              exit(1);
  
          }
  
  
  
          /* ignore the header if GSO is not supported */
  
          if (!n->has_vnet_hdr) {
  
              out_num--;
  
              out_sg++;
  
              len += hdr_len;
  
          } else if (n->mergeable_rx_bufs) {
  
              /* tapfd expects a struct virtio_net_hdr */
  
              hdr_len -= sizeof(struct virtio_net_hdr);
  
              out_sg->iov_len -= hdr_len;
  
              len += hdr_len;
  
          }
  
  
  
          ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num,
  
                                        virtio_net_tx_complete);
  
          if (ret == 0) {
  
              virtio_queue_set_notification(n->tx_vq, 0);
  
              n->async_tx.elem = elem;
  
              n->async_tx.len  = len;
  
              return;
  
          }
  
  
  
          len += ret;
  
  
  
          virtqueue_push(vq, &elem, len);
  
          virtio_notify(&n->vdev, vq);
  
      }
  
  }
  