On Fri, Dec 06, 2013 at 03:44:33PM +0100, Vincenzo Maffione wrote: > This patch extends the frontend-backend interface so that it is possible > to pass a new flag (QEMU_NET_PACKET_FLAG_MORE) when sending a packet to the > other peer. The new flag acts as a hint for the receiving peer, which can > accumulate a batch of packets before forwarding those packets (to the host > if the receiving peer is the backend or to the guest if the receiving peer > is the frontend). > > The patch also implements a batching mechanism for the netmap backend (on the > backend receive side) and for the e1000 and virtio frontends (on the frontend > transmit side). > > Measured improvement of a guest-to-guest UDP_STREAM netperf test (64 bytes > packets) with virtio-net frontends: > 820 Kpps ==> 1000 Kpps (+22%). > > Measured improvement of a guest-to-guest UDP test (64 bytes packets) with > e1000 frontends and netmap clients on the guests: > 1.8 Mpps ==> 3.1 Mpps (+72%). > > Signed-off-by: Vincenzo Maffione <v.maffi...@gmail.com>
So we are batching some more and this helps throughput. However I wonder what this does to a more bursty traffic, such as several TCP streams running in parallel. > --- > Experiment details: > - Processor: Intel i7-3770K CPU @ 3.50GHz (8 cores) > - Memory @ 1333 MHz > - Host O.S.: Archlinux with Linux 3.11 > - Guest O.S.: Archlinux with Linux 3.11 > > QEMU command line for the virtio experiment: > qemu-system-x86_64 archdisk.qcow -snapshot -enable-kvm -device > virtio-net-pci,ioeventfd=on,mac=00:AA:BB:CC:DD:01,netdev=mynet -netdev > netmap,ifname=vale0:01,id=mynet -smp 2 -vga std -m 3G > > QEMU command line for the e1000 experiment: > qemu-system-x86_64 archdisk.qcow -snapshot -enable-kvm -device > e1000,mitigation=off,mac=00:AA:BB:CC:DD:01,netdev=mynet -netdev > netmap,ifname=vale0:01,id=mynet -smp 2 -vga std -m 3G > > With the e1000 experiments, we don't use netperf on the guests, but netmap > clients (pkt-gen) > that run directly on the e1000 adapter, bypassing the O.S. stack. > > Other things: > - This patch is against the net-next tree > (https://github.com/stefanha/qemu.git) > because the first netmap patch is not in the qemu master (AFAIK). > - The batching can also be implemented on the backend transmit side and > frontend > receive side. We could do it in the future. > > hw/net/cadence_gem.c | 3 ++- > hw/net/dp8393x.c | 5 +++-- > hw/net/e1000.c | 21 ++++++++++++++++----- > hw/net/eepro100.c | 5 +++-- > hw/net/etraxfs_eth.c | 5 +++-- > hw/net/lan9118.c | 2 +- > hw/net/mcf_fec.c | 5 +++-- > hw/net/mipsnet.c | 6 ++++-- > hw/net/ne2000.c | 5 +++-- > hw/net/ne2000.h | 3 ++- > hw/net/opencores_eth.c | 2 +- > hw/net/pcnet.c | 8 +++++--- > hw/net/pcnet.h | 3 ++- > hw/net/rtl8139.c | 7 ++++--- > hw/net/smc91c111.c | 5 +++-- > hw/net/spapr_llan.c | 2 +- > hw/net/stellaris_enet.c | 3 ++- > hw/net/virtio-net.c | 10 ++++++++-- > hw/net/vmxnet3.c | 3 ++- > hw/net/vmxnet_tx_pkt.c | 4 ++-- > hw/net/xgmac.c | 2 +- > hw/net/xilinx_axienet.c | 2 +- > hw/usb/dev-network.c | 8 +++++--- > include/net/net.h | 20 +++++++++++++------- > include/net/queue.h | 1 + > net/dump.c | 3 ++- > net/hub.c | 10 ++++++---- > net/net.c | 39 +++++++++++++++++++++++---------------- > net/netmap.c | 17 ++++++++++++----- > net/slirp.c | 5 +++-- > net/socket.c | 10 ++++++---- > net/tap-win32.c | 2 +- > net/tap.c | 12 +++++++----- > net/vde.c | 5 +++-- > savevm.c | 2 +- > 35 files changed, 155 insertions(+), 90 deletions(-) > > diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c > index 4a355bb..432687a 100644 > --- a/hw/net/cadence_gem.c > +++ b/hw/net/cadence_gem.c > @@ -583,7 +583,8 @@ static int gem_mac_address_filter(GemState *s, const > uint8_t *packet) > * gem_receive: > * Fit a packet handed to us by QEMU into the receive descriptor ring. > */ > -static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t > size) > +static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t > size, > + unsigned flags) > { > unsigned desc[2]; > hwaddr packet_desc_addr, last_desc_addr; > diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c > index 789d385..d8c7da8 100644 > --- a/hw/net/dp8393x.c > +++ b/hw/net/dp8393x.c > @@ -415,7 +415,7 @@ static void do_transmit_packets(dp8393xState *s) > } > } else { > /* Transmit packet */ > - qemu_send_packet(nc, s->tx_buffer, tx_len); > + qemu_send_packet(nc, s->tx_buffer, tx_len, 0); > } > s->regs[SONIC_TCR] |= SONIC_TCR_PTX; > > @@ -723,7 +723,8 @@ static int receive_filter(dp8393xState *s, const uint8_t > * buf, int size) > return -1; > } > > -static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t > size) > +static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, > + size_t size, unsigned flags) > { > dp8393xState *s = qemu_get_nic_opaque(nc); > uint16_t data[10]; > diff --git a/hw/net/e1000.c b/hw/net/e1000.c > index ae63591..5294ec5 100644 > --- a/hw/net/e1000.c > +++ b/hw/net/e1000.c > @@ -570,10 +570,19 @@ static void > e1000_send_packet(E1000State *s, const uint8_t *buf, int size) > { > NetClientState *nc = qemu_get_queue(s->nic); > + uint32_t tdh = s->mac_reg[TDH]; > + unsigned flags = QEMU_NET_PACKET_FLAG_MORE; > + > if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) { > - nc->info->receive(nc, buf, size); > + nc->info->receive(nc, buf, size, 0); > } else { > - qemu_send_packet(nc, buf, size); > + if (++tdh * sizeof(struct e1000_tx_desc) >= s->mac_reg[TDLEN]) { > + tdh = 0; > + } > + if (tdh == s->mac_reg[TDT]) { > + flags = 0; > + } > + qemu_send_packet(nc, buf, size, flags); > } > } > > @@ -899,7 +908,8 @@ static uint64_t rx_desc_base(E1000State *s) > } > > static ssize_t > -e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) > +e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt, > + unsigned flags) > { > E1000State *s = qemu_get_nic_opaque(nc); > PCIDevice *d = PCI_DEVICE(s); > @@ -1054,14 +1064,15 @@ e1000_receive_iov(NetClientState *nc, const struct > iovec *iov, int iovcnt) > } > > static ssize_t > -e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) > +e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size, > + unsigned flags) > { > const struct iovec iov = { > .iov_base = (uint8_t *)buf, > .iov_len = size > }; > > - return e1000_receive_iov(nc, &iov, 1); > + return e1000_receive_iov(nc, &iov, 1, flags); > } > > static uint32_t > diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c > index 3b891ca..9763904 100644 > --- a/hw/net/eepro100.c > +++ b/hw/net/eepro100.c > @@ -828,7 +828,7 @@ static void tx_command(EEPRO100State *s) > } > } > TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, > nic_dump(buf, size))); > - qemu_send_packet(qemu_get_queue(s->nic), buf, size); > + qemu_send_packet(qemu_get_queue(s->nic), buf, size, 0); > s->statistics.tx_good_frames++; > /* Transmit with bad status would raise an CX/TNO interrupt. > * (82557 only). Emulation never has bad status. */ > @@ -1627,7 +1627,8 @@ static int nic_can_receive(NetClientState *nc) > #endif > } > > -static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t > size) > +static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, > + size_t size, unsigned flags) > { > /* TODO: > * - Magic packets should set bit 30 in power management driver register. > diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c > index 78ebbbc..6cba74e 100644 > --- a/hw/net/etraxfs_eth.c > +++ b/hw/net/etraxfs_eth.c > @@ -525,7 +525,8 @@ static int eth_can_receive(NetClientState *nc) > return 1; > } > > -static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t > size) > +static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t > size, > + unsigned flags) > { > unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; > ETRAXFSEthState *eth = qemu_get_nic_opaque(nc); > @@ -560,7 +561,7 @@ static int eth_tx_push(void *opaque, unsigned char *buf, > int len, bool eop) > ETRAXFSEthState *eth = opaque; > > D(printf("%s buf=%p len=%d\n", __func__, buf, len)); > - qemu_send_packet(qemu_get_queue(eth->nic), buf, len); > + qemu_send_packet(qemu_get_queue(eth->nic), buf, len, 0); > return len; > } > > diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c > index 2315f99..55e06a9 100644 > --- a/hw/net/lan9118.c > +++ b/hw/net/lan9118.c > @@ -664,7 +664,7 @@ static void do_tx_packet(lan9118_state *s) > /* This assumes the receive routine doesn't touch the VLANClient. */ > lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len); > } else { > - qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); > + qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len, > 0); > } > s->txp->fifo_used = 0; > > diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c > index 4bff3de..14ed0dd 100644 > --- a/hw/net/mcf_fec.c > +++ b/hw/net/mcf_fec.c > @@ -174,7 +174,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) > if (bd.flags & FEC_BD_L) { > /* Last buffer in frame. */ > DPRINTF("Sending packet\n"); > - qemu_send_packet(qemu_get_queue(s->nic), frame, len); > + qemu_send_packet(qemu_get_queue(s->nic), frame, len, 0); > ptr = frame; > frame_size = 0; > s->eir |= FEC_INT_TXF; > @@ -357,7 +357,8 @@ static int mcf_fec_can_receive(NetClientState *nc) > return s->rx_enabled; > } > > -static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > mcf_fec_state *s = qemu_get_nic_opaque(nc); > mcf_fec_bd bd; > diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c > index e421b86..7f5d4c4 100644 > --- a/hw/net/mipsnet.c > +++ b/hw/net/mipsnet.c > @@ -74,7 +74,8 @@ static int mipsnet_can_receive(NetClientState *nc) > return !mipsnet_buffer_full(s); > } > > -static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > MIPSnetState *s = qemu_get_nic_opaque(nc); > > @@ -176,7 +177,8 @@ static void mipsnet_ioport_write(void *opaque, hwaddr > addr, > if (s->tx_written == s->tx_count) { > /* Send buffer. */ > trace_mipsnet_send(s->tx_count); > - qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, > s->tx_count); > + qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, > + s->tx_count, 0); > s->tx_count = s->tx_written = 0; > s->intctl |= MIPSNET_INTCTL_TXDONE; > s->busy = 1; > diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c > index 4c32e9e..52af46a 100644 > --- a/hw/net/ne2000.c > +++ b/hw/net/ne2000.c > @@ -176,7 +176,8 @@ int ne2000_can_receive(NetClientState *nc) > > #define MIN_BUF_SIZE 60 > > -ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) > +ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_, > + unsigned flags) > { > NE2000State *s = qemu_get_nic_opaque(nc); > int size = size_; > @@ -301,7 +302,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t > addr, uint32_t val) > /* fail safe: check range on the transmitted length */ > if (index + s->tcnt <= NE2000_PMEM_END) { > qemu_send_packet(qemu_get_queue(s->nic), s->mem + index, > - s->tcnt); > + s->tcnt, 0); > } > /* signal end of transfer */ > s->tsr = ENTSR_PTX; > diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h > index e500306..b62a8f3 100644 > --- a/hw/net/ne2000.h > +++ b/hw/net/ne2000.h > @@ -35,6 +35,7 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, > unsigned size); > extern const VMStateDescription vmstate_ne2000; > void ne2000_reset(NE2000State *s); > int ne2000_can_receive(NetClientState *nc); > -ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_); > +ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_, > + unsigned flags); > > #endif > diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c > index 4118d54..b4328ea 100644 > --- a/hw/net/opencores_eth.c > +++ b/hw/net/opencores_eth.c > @@ -503,7 +503,7 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx) > if (tx_len > len) { > memset(buf + len, 0, tx_len - len); > } > - qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len); > + qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len, 0); > > if (tx->len_flags & TXD_WR) { > s->tx_desc = 0; > diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c > index 7cb47b3..707ac92 100644 > --- a/hw/net/pcnet.c > +++ b/hw/net/pcnet.c > @@ -1019,7 +1019,8 @@ int pcnet_can_receive(NetClientState *nc) > > #define MIN_BUF_SIZE 60 > > -ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) > +ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_, > + unsigned flags) > { > PCNetState *s = qemu_get_nic_opaque(nc); > int is_padr = 0, is_bcast = 0, is_ladr = 0; > @@ -1265,12 +1266,13 @@ static void pcnet_transmit(PCNetState *s) > if (BCR_SWSTYLE(s) == 1) > add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); > s->looptest = add_crc ? PCNET_LOOPTEST_CRC : > PCNET_LOOPTEST_NOCRC; > - pcnet_receive(qemu_get_queue(s->nic), s->buffer, > s->xmit_pos); > + pcnet_receive(qemu_get_queue(s->nic), s->buffer, > + s->xmit_pos, 0); > s->looptest = 0; > } else > if (s->nic) > qemu_send_packet(qemu_get_queue(s->nic), s->buffer, > - s->xmit_pos); > + s->xmit_pos, 0); > > s->csr[0] &= ~0x0008; /* clear TDMD */ > s->csr[4] |= 0x0004; /* set TXSTRT */ > diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h > index 9dee6f3..a26aacd 100644 > --- a/hw/net/pcnet.h > +++ b/hw/net/pcnet.h > @@ -61,7 +61,8 @@ void pcnet_ioport_writel(void *opaque, uint32_t addr, > uint32_t val); > uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr); > uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); > int pcnet_can_receive(NetClientState *nc); > -ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_); > +ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_, > + unsigned flags); > void pcnet_set_link_status(NetClientState *nc); > void pcnet_common_cleanup(PCNetState *d); > int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info); > diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c > index 7f2b4db..340331f 100644 > --- a/hw/net/rtl8139.c > +++ b/hw/net/rtl8139.c > @@ -1195,7 +1195,8 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, > const uint8_t *buf, size_t > return size_; > } > > -static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > return rtl8139_do_receive(nc, buf, size, 1); > } > @@ -1814,9 +1815,9 @@ static void rtl8139_transfer_frame(RTL8139State *s, > uint8_t *buf, int size, > else > { > if (iov) { > - qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3); > + qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3, 0); > } else { > - qemu_send_packet(qemu_get_queue(s->nic), buf, size); > + qemu_send_packet(qemu_get_queue(s->nic), buf, size, 0); > } > } > } > diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c > index a8e29b3..82289aa 100644 > --- a/hw/net/smc91c111.c > +++ b/hw/net/smc91c111.c > @@ -242,7 +242,7 @@ static void smc91c111_do_tx(smc91c111_state *s) > smc91c111_release_packet(s, packetnum); > else if (s->tx_fifo_done_len < NUM_PACKETS) > s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; > - qemu_send_packet(qemu_get_queue(s->nic), p, len); > + qemu_send_packet(qemu_get_queue(s->nic), p, len, 0); > } > s->tx_fifo_len = 0; > smc91c111_update(s); > @@ -647,7 +647,8 @@ static int smc91c111_can_receive(NetClientState *nc) > return 1; > } > > -static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > smc91c111_state *s = qemu_get_nic_opaque(nc); > int status; > diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c > index 1bd6f50..1a50bc1 100644 > --- a/hw/net/spapr_llan.c > +++ b/hw/net/spapr_llan.c > @@ -476,7 +476,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, > sPAPREnvironment *spapr, > p += VLAN_BD_LEN(bufs[i]); > } > > - qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len); > + qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len, 0); > > return H_SUCCESS; > } > diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c > index 9dd77f7..950b455 100644 > --- a/hw/net/stellaris_enet.c > +++ b/hw/net/stellaris_enet.c > @@ -83,7 +83,8 @@ static void stellaris_enet_update(stellaris_enet_state *s) > } > > /* TODO: Implement MAC address filtering. */ > -static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t > *buf, size_t size) > +static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > stellaris_enet_state *s = qemu_get_nic_opaque(nc); > int n; > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > index 513c168..b25bc4e 100644 > --- a/hw/net/virtio-net.c > +++ b/hw/net/virtio-net.c > @@ -938,7 +938,8 @@ static int receive_filter(VirtIONet *n, const uint8_t > *buf, int size) > return 0; > } > > -static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > VirtIONet *n = qemu_get_nic_opaque(nc); > VirtIONetQueue *q = virtio_net_get_subqueue(nc); > @@ -1079,6 +1080,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) > unsigned int out_num = elem.out_num; > struct iovec *out_sg = &elem.out_sg[0]; > struct iovec sg[VIRTQUEUE_MAX_SIZE]; > + unsigned flags = QEMU_NET_PACKET_FLAG_MORE; > > if (out_num < 1) { > error_report("virtio-net header not in first element"); > @@ -1104,8 +1106,12 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) > > len = n->guest_hdr_len; > > + if (num_packets + 1 >= n->tx_burst || virtio_queue_empty(q->tx_vq)) { > + flags = 0; > + } > ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index), > - out_sg, out_num, > virtio_net_tx_complete); > + out_sg, out_num, > virtio_net_tx_complete, > + flags); > if (ret == 0) { > virtio_queue_set_notification(q->tx_vq, 0); > q->async_tx.elem = elem; > diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c > index 19687aa..6bd59d0 100644 > --- a/hw/net/vmxnet3.c > +++ b/hw/net/vmxnet3.c > @@ -1817,7 +1817,8 @@ vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const > void *data, > } > > static ssize_t > -vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size) > +vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size, > + unsigned flags) > { > VMXNET3State *s = qemu_get_nic_opaque(nc); > size_t bytes_indicated; > diff --git a/hw/net/vmxnet_tx_pkt.c b/hw/net/vmxnet_tx_pkt.c > index f7344c4..12d842e 100644 > --- a/hw/net/vmxnet_tx_pkt.c > +++ b/hw/net/vmxnet_tx_pkt.c > @@ -526,7 +526,7 @@ static bool vmxnet_tx_pkt_do_sw_fragmentation(struct > VmxnetTxPkt *pkt, > > eth_fix_ip4_checksum(l3_iov_base, l3_iov_len); > > - qemu_sendv_packet(nc, fragment, dst_idx); > + qemu_sendv_packet(nc, fragment, dst_idx, 0); > > fragment_offset += fragment_len; > > @@ -559,7 +559,7 @@ bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, > NetClientState *nc) > if (pkt->has_virt_hdr || > pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) { > qemu_sendv_packet(nc, pkt->vec, > - pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG); > + pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG, 0); > return true; > } > > diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c > index 9384fa0..683a5ad 100644 > --- a/hw/net/xgmac.c > +++ b/hw/net/xgmac.c > @@ -239,7 +239,7 @@ static void xgmac_enet_send(XgmacState *s) > frame_size += len; > if (bd.ctl_stat & 0x20000000) { > /* Last buffer in frame. */ > - qemu_send_packet(qemu_get_queue(s->nic), frame, len); > + qemu_send_packet(qemu_get_queue(s->nic), frame, len, 0); > ptr = frame; > frame_size = 0; > s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS; > diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c > index 3eb7715..9dd44bf 100644 > --- a/hw/net/xilinx_axienet.c > +++ b/hw/net/xilinx_axienet.c > @@ -919,7 +919,7 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t > *buf, size_t size) > buf[write_off + 1] = csum & 0xff; > } > > - qemu_send_packet(qemu_get_queue(s->nic), buf, size); > + qemu_send_packet(qemu_get_queue(s->nic), buf, size, 0); > > s->stats.tx_bytes += size; > s->regs[R_IS] |= IS_TX_COMPLETE; > diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c > index 4c532b7..253878c 100644 > --- a/hw/usb/dev-network.c > +++ b/hw/usb/dev-network.c > @@ -1196,7 +1196,7 @@ static void usb_net_handle_dataout(USBNetState *s, > USBPacket *p) > > if (!is_rndis(s)) { > if (p->iov.size < 64) { > - qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr); > + qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr, > 0); > s->out_ptr = 0; > } > return; > @@ -1209,7 +1209,8 @@ static void usb_net_handle_dataout(USBNetState *s, > USBPacket *p) > uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); > uint32_t size = le32_to_cpu(msg->DataLength); > if (offs + size <= len) > - qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, > size); > + qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, > + size, 0); > } > s->out_ptr -= len; > memmove(s->out_buf, &s->out_buf[len], s->out_ptr); > @@ -1259,7 +1260,8 @@ static void usb_net_handle_data(USBDevice *dev, > USBPacket *p) > } > } > > -static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t > size) > +static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > USBNetState *s = qemu_get_nic_opaque(nc); > uint8_t *in_buf = s->in_buf; > diff --git a/include/net/net.h b/include/net/net.h > index 11e1468..d3f0ad6 100644 > --- a/include/net/net.h > +++ b/include/net/net.h > @@ -44,8 +44,10 @@ typedef struct NICConf { > > typedef void (NetPoll)(NetClientState *, bool enable); > typedef int (NetCanReceive)(NetClientState *); > -typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); > -typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); > +typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t, > + unsigned); > +typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int, > + unsigned); > typedef void (NetCleanup) (NetClientState *); > typedef void (LinkStatusChanged)(NetClientState *); > typedef void (NetClientDestructor)(NetClientState *); > @@ -110,13 +112,17 @@ typedef void (*qemu_nic_foreach)(NICState *nic, void > *opaque); > void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); > int qemu_can_send_packet(NetClientState *nc); > ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, > - int iovcnt); > + int iovcnt, unsigned flags); > ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov, > - int iovcnt, NetPacketSent *sent_cb); > -void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size); > -ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int > size); > + int iovcnt, NetPacketSent *sent_cb, > + unsigned flags); > +void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size, > + unsigned flags); > +ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int > size, > + unsigned flags); > ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, > - int size, NetPacketSent *sent_cb); > + int size, NetPacketSent *sent_cb, > + unsigned flags); > void qemu_purge_queued_packets(NetClientState *nc); > void qemu_flush_queued_packets(NetClientState *nc); > void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]); > diff --git a/include/net/queue.h b/include/net/queue.h > index fc02b33..1d136a6 100644 > --- a/include/net/queue.h > +++ b/include/net/queue.h > @@ -33,6 +33,7 @@ typedef void (NetPacketSent) (NetClientState *sender, > ssize_t ret); > > #define QEMU_NET_PACKET_FLAG_NONE 0 > #define QEMU_NET_PACKET_FLAG_RAW (1<<0) > +#define QEMU_NET_PACKET_FLAG_MORE (2<<0) > > NetQueue *qemu_new_net_queue(void *opaque); > > diff --git a/net/dump.c b/net/dump.c > index 9d3a09e..f718d5c 100644 > --- a/net/dump.c > +++ b/net/dump.c > @@ -57,7 +57,8 @@ struct pcap_sf_pkthdr { > uint32_t len; > }; > > -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t > size) > +static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > DumpState *s = DO_UPCAST(DumpState, nc, nc); > struct pcap_sf_pkthdr hdr; > diff --git a/net/hub.c b/net/hub.c > index 33a99c9..7adca5d 100644 > --- a/net/hub.c > +++ b/net/hub.c > @@ -52,7 +52,7 @@ static ssize_t net_hub_receive(NetHub *hub, NetHubPort > *source_port, > continue; > } > > - qemu_send_packet(&port->nc, buf, len); > + qemu_send_packet(&port->nc, buf, len, 0); > } > return len; > } > @@ -68,7 +68,7 @@ static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort > *source_port, > continue; > } > > - qemu_sendv_packet(&port->nc, iov, iovcnt); > + qemu_sendv_packet(&port->nc, iov, iovcnt, 0); > } > return len; > } > @@ -107,7 +107,8 @@ static int net_hub_port_can_receive(NetClientState *nc) > } > > static ssize_t net_hub_port_receive(NetClientState *nc, > - const uint8_t *buf, size_t len) > + const uint8_t *buf, size_t len, > + unsigned flags) > { > NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); > > @@ -115,7 +116,8 @@ static ssize_t net_hub_port_receive(NetClientState *nc, > } > > static ssize_t net_hub_port_receive_iov(NetClientState *nc, > - const struct iovec *iov, int iovcnt) > + const struct iovec *iov, int iovcnt, > + unsigned flags) > { > NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); > > diff --git a/net/net.c b/net/net.c > index 9db88cc..65cf5f1 100644 > --- a/net/net.c > +++ b/net/net.c > @@ -414,9 +414,10 @@ ssize_t qemu_deliver_packet(NetClientState *sender, > } > > if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { > - ret = nc->info->receive_raw(nc, data, size); > + ret = nc->info->receive_raw(nc, data, size, > + flags & ~QEMU_NET_PACKET_FLAG_RAW); > } else { > - ret = nc->info->receive(nc, data, size); > + ret = nc->info->receive(nc, data, size, flags); > } > > if (ret == 0) { > @@ -475,32 +476,36 @@ static ssize_t > qemu_send_packet_async_with_flags(NetClientState *sender, > > ssize_t qemu_send_packet_async(NetClientState *sender, > const uint8_t *buf, int size, > - NetPacketSent *sent_cb) > + NetPacketSent *sent_cb, unsigned flags) > { > - return qemu_send_packet_async_with_flags(sender, > QEMU_NET_PACKET_FLAG_NONE, > + return qemu_send_packet_async_with_flags(sender, > + flags | > QEMU_NET_PACKET_FLAG_NONE, > buf, size, sent_cb); > } > > -void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) > +void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size, > + unsigned flags) > { > - qemu_send_packet_async(nc, buf, size, NULL); > + qemu_send_packet_async(nc, buf, size, NULL, flags); > } > > -ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int > size) > +ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int > size, > + unsigned flags) > { > - return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, > + return qemu_send_packet_async_with_flags(nc, > + QEMU_NET_PACKET_FLAG_RAW | > flags, > buf, size, NULL); > } > > static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, > - int iovcnt) > + int iovcnt, unsigned flags) > { > uint8_t buffer[NET_BUFSIZE]; > size_t offset; > > offset = iov_to_buf(iov, iovcnt, 0, buffer, sizeof(buffer)); > > - return nc->info->receive(nc, buffer, offset); > + return nc->info->receive(nc, buffer, offset, flags); > } > > ssize_t qemu_deliver_packet_iov(NetClientState *sender, > @@ -521,9 +526,9 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, > } > > if (nc->info->receive_iov) { > - ret = nc->info->receive_iov(nc, iov, iovcnt); > + ret = nc->info->receive_iov(nc, iov, iovcnt, flags); > } else { > - ret = nc_sendv_compat(nc, iov, iovcnt); > + ret = nc_sendv_compat(nc, iov, iovcnt, flags); > } > > if (ret == 0) { > @@ -535,7 +540,8 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, > > ssize_t qemu_sendv_packet_async(NetClientState *sender, > const struct iovec *iov, int iovcnt, > - NetPacketSent *sent_cb) > + NetPacketSent *sent_cb, > + unsigned flags) > { > NetQueue *queue; > > @@ -546,14 +552,15 @@ ssize_t qemu_sendv_packet_async(NetClientState *sender, > queue = sender->peer->incoming_queue; > > return qemu_net_queue_send_iov(queue, sender, > - QEMU_NET_PACKET_FLAG_NONE, > + flags | QEMU_NET_PACKET_FLAG_NONE, > iov, iovcnt, sent_cb); > } > > ssize_t > -qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) > +qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt, > + unsigned flags) > { > - return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); > + return qemu_sendv_packet_async(nc, iov, iovcnt, NULL, flags); > } > > NetClientState *qemu_find_netdev(const char *id) > diff --git a/net/netmap.c b/net/netmap.c > index 0ccc497..0b982a0 100644 > --- a/net/netmap.c > +++ b/net/netmap.c > @@ -218,7 +218,8 @@ static void netmap_writable(void *opaque) > } > > static ssize_t netmap_receive(NetClientState *nc, > - const uint8_t *buf, size_t size) > + const uint8_t *buf, > + size_t size, unsigned flags) > { > NetmapState *s = DO_UPCAST(NetmapState, nc, nc); > struct netmap_ring *ring = s->me.tx; > @@ -252,13 +253,17 @@ static ssize_t netmap_receive(NetClientState *nc, > pkt_copy(buf, dst, size); > ring->cur = NETMAP_RING_NEXT(ring, i); > ring->avail--; > - ioctl(s->me.fd, NIOCTXSYNC, NULL); > + > + if (!(flags & QEMU_NET_PACKET_FLAG_MORE)) { > + ioctl(s->me.fd, NIOCTXSYNC, NULL); > + } > > return size; > } > > static ssize_t netmap_receive_iov(NetClientState *nc, > - const struct iovec *iov, int iovcnt) > + const struct iovec *iov, int iovcnt, > + unsigned flags) > { > NetmapState *s = DO_UPCAST(NetmapState, nc, nc); > struct netmap_ring *ring = s->me.tx; > @@ -322,7 +327,9 @@ static ssize_t netmap_receive_iov(NetClientState *nc, > ring->cur = i; > ring->avail = avail; > > - ioctl(s->me.fd, NIOCTXSYNC, NULL); > + if (!(flags & QEMU_NET_PACKET_FLAG_MORE)) { > + ioctl(s->me.fd, NIOCTXSYNC, NULL); > + } > > return iov_size(iov, iovcnt); > } > @@ -368,7 +375,7 @@ static void netmap_send(void *opaque) > } > > iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt, > - netmap_send_completed); > + netmap_send_completed, 0); > > if (iovsize == 0) { > /* The peer does not receive anymore. Packet is queued, stop > diff --git a/net/slirp.c b/net/slirp.c > index 124e953..a801638 100644 > --- a/net/slirp.c > +++ b/net/slirp.c > @@ -103,10 +103,11 @@ void slirp_output(void *opaque, const uint8_t *pkt, int > pkt_len) > { > SlirpState *s = opaque; > > - qemu_send_packet(&s->nc, pkt, pkt_len); > + qemu_send_packet(&s->nc, pkt, pkt_len, 0); > } > > -static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > SlirpState *s = DO_UPCAST(SlirpState, nc, nc); > > diff --git a/net/socket.c b/net/socket.c > index fb21e20..acc715a 100644 > --- a/net/socket.c > +++ b/net/socket.c > @@ -89,7 +89,8 @@ static void net_socket_writable(void *opaque) > qemu_flush_queued_packets(&s->nc); > } > > -static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); > uint32_t len = htonl(size); > @@ -124,7 +125,8 @@ static ssize_t net_socket_receive(NetClientState *nc, > const uint8_t *buf, size_t > return size; > } > > -static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t > *buf, size_t size) > +static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t > *buf, > + size_t size, unsigned flags) > { > NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); > ssize_t ret; > @@ -211,7 +213,7 @@ static void net_socket_send(void *opaque) > buf += l; > size -= l; > if (s->index >= s->packet_len) { > - qemu_send_packet(&s->nc, s->buf, s->packet_len); > + qemu_send_packet(&s->nc, s->buf, s->packet_len, 0); > s->index = 0; > s->state = 0; > } > @@ -234,7 +236,7 @@ static void net_socket_send_dgram(void *opaque) > net_socket_write_poll(s, false); > return; > } > - qemu_send_packet(&s->nc, s->buf, size); > + qemu_send_packet(&s->nc, s->buf, size, 0); > } > > static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct > in_addr *localaddr) > diff --git a/net/tap-win32.c b/net/tap-win32.c > index 91e9e84..2d86122 100644 > --- a/net/tap-win32.c > +++ b/net/tap-win32.c > @@ -664,7 +664,7 @@ static void tap_win32_send(void *opaque) > > size = tap_win32_read(s->handle, &buf, max_size); > if (size > 0) { > - qemu_send_packet(&s->nc, buf, size); > + qemu_send_packet(&s->nc, buf, size, 0); > tap_win32_free_buffer(s->handle, buf); > } > } > diff --git a/net/tap.c b/net/tap.c > index 39c1cda..6d7a02e 100644 > --- a/net/tap.c > +++ b/net/tap.c > @@ -112,7 +112,7 @@ static ssize_t tap_write_packet(TAPState *s, const struct > iovec *iov, int iovcnt > } > > static ssize_t tap_receive_iov(NetClientState *nc, const struct iovec *iov, > - int iovcnt) > + int iovcnt, unsigned flags) > { > TAPState *s = DO_UPCAST(TAPState, nc, nc); > const struct iovec *iovp = iov; > @@ -130,7 +130,8 @@ static ssize_t tap_receive_iov(NetClientState *nc, const > struct iovec *iov, > return tap_write_packet(s, iovp, iovcnt); > } > > -static ssize_t tap_receive_raw(NetClientState *nc, const uint8_t *buf, > size_t size) > +static ssize_t tap_receive_raw(NetClientState *nc, const uint8_t *buf, > + size_t size, unsigned flags) > { > TAPState *s = DO_UPCAST(TAPState, nc, nc); > struct iovec iov[2]; > @@ -150,13 +151,14 @@ static ssize_t tap_receive_raw(NetClientState *nc, > const uint8_t *buf, size_t si > return tap_write_packet(s, iov, iovcnt); > } > > -static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t > size) > +static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t > size, > + unsigned flags) > { > TAPState *s = DO_UPCAST(TAPState, nc, nc); > struct iovec iov[1]; > > if (s->host_vnet_hdr_len && !s->using_vnet_hdr) { > - return tap_receive_raw(nc, buf, size); > + return tap_receive_raw(nc, buf, size, flags); > } > > iov[0].iov_base = (char *)buf; > @@ -203,7 +205,7 @@ static void tap_send(void *opaque) > size -= s->host_vnet_hdr_len; > } > > - size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed); > + size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed, > 0); > if (size == 0) { > tap_read_poll(s, false); > } > diff --git a/net/vde.c b/net/vde.c > index 2a619fb..5629f58 100644 > --- a/net/vde.c > +++ b/net/vde.c > @@ -44,11 +44,12 @@ static void vde_to_qemu(void *opaque) > > size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0); > if (size > 0) { > - qemu_send_packet(&s->nc, buf, size); > + qemu_send_packet(&s->nc, buf, size, 0); > } > } > > -static ssize_t vde_receive(NetClientState *nc, const uint8_t *buf, size_t > size) > +static ssize_t vde_receive(NetClientState *nc, const uint8_t *buf, size_t > size, > + unsigned flags) > { > VDEState *s = DO_UPCAST(VDEState, nc, nc); > ssize_t ret; > diff --git a/savevm.c b/savevm.c > index 3f912dd..a8d5373 100644 > --- a/savevm.c > +++ b/savevm.c > @@ -84,7 +84,7 @@ static void qemu_announce_self_iter(NICState *nic, void > *opaque) > > len = announce_self_create(buf, nic->conf->macaddr.a); > > - qemu_send_packet_raw(qemu_get_queue(nic), buf, len); > + qemu_send_packet_raw(qemu_get_queue(nic), buf, len, 0); > } > > > -- > 1.8.4.2