static void virtio_net_tx_lazy(struct vmm_netport *port, void *arg, int budget) { u16 head = 0; u32 iov_cnt = 0, pkt_len = 0, total_len = 0; struct virtio_net_dev *ndev = arg; struct virtio_device *dev = ndev->vdev; struct virtio_queue *vq = &ndev->vqs[VIRTIO_NET_TX_QUEUE]; struct virtio_iovec *iov = ndev->tx_iov; struct vmm_mbuf *mb; while ((budget > 0) && virtio_queue_available(vq)) { head = virtio_queue_get_iovec(vq, iov, &iov_cnt, &total_len); /* iov[0] is offload info */ pkt_len = total_len - iov[0].len; if (pkt_len <= VIRTIO_NET_MTU) { MGETHDR(mb, 0, 0); MEXTMALLOC(mb, pkt_len, M_WAIT); virtio_iovec_to_buf_read(dev, &iov[1], iov_cnt - 1, M_BUFADDR(mb), pkt_len); mb->m_len = mb->m_pktlen = pkt_len; vmm_port2switch_xfer_mbuf(ndev->port, mb); } virtio_queue_set_used_elem(vq, head, total_len); budget--; } if (virtio_queue_should_signal(vq)) { dev->tra->notify(dev, VIRTIO_NET_TX_QUEUE); } }
static err_t lwip_netstack_output(struct netif *netif, struct pbuf *p) { struct vmm_mbuf *mbuf, *mbuf_head, *mbuf_cur; struct pbuf *q; struct lwip_netstack *lns = netif->state; if (!p || !p->payload || !p->len) { return ERR_OK; } if (p->tot_len > MAX_FRAME_LEN) { /* Frame too long, drop it */ return ERR_MEM; } /* Increase reference to the pbuf as we reuse the same buffers */ pbuf_ref(p); /* Create the first mbuf in the chain */ MGETHDR(mbuf_head, 0, 0); MEXTADD(mbuf_head, p->payload, p->len, lwip_netstack_mbuf_free, p); mbuf_cur = mbuf_head; /* Create next mbufs in chain from the pbuf chain */ q = p->next; while (q != NULL) { MGET(mbuf, 0, M_EXT_DONTFREE); MEXTADD(mbuf, q->payload, q->len, NULL, NULL); mbuf_cur->m_next = mbuf; mbuf_cur = mbuf; q = q->next; } /* Setup mbuf len */ mbuf_head->m_len = mbuf_head->m_pktlen = p->tot_len; /* Send mbuf to the netswitch */ vmm_port2switch_xfer_mbuf(lns->port, mbuf_head); /* Return success */ return ERR_OK; }