From 987a9b4800003567b1a47a379255e886a77d57ea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Aug 2012 16:45:55 +0200 Subject: net: notify iothread after flushing queue virtio-net has code to flush the queue and notify the iothread whenever new receive buffers are added by the guest. That is fine, and indeed we need to do the same in all other drivers. However, notifying the iothread should be work for the network subsystem. And since we are at it we can add a little smartness: if some of the queued packets already could not be delivered, there is no need to notify the iothread. Reported-by: Luigi Rizzo Cc: Stefan Hajnoczi Cc: Jan Kiszka Signed-off-by: Paolo Bonzini Reviewed-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- hw/virtio-net.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'hw') diff --git a/hw/virtio-net.c b/hw/virtio-net.c index b1998b27d3..6490743290 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = to_virtio_net(vdev); qemu_flush_queued_packets(&n->nic->nc); - - /* We now have RX buffers, signal to the IO thread to break out of the - * select to re-poll the tap file descriptor */ - qemu_notify_event(); } static int virtio_net_can_receive(NetClientState *nc) -- cgit v1.2.3 From e8b4c680b41bd960ecccd9ff076b7b058e0afcd4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Aug 2012 16:45:56 +0200 Subject: e1000: flush queue whenever can_receive can go from false to true When the guests replenish the receive ring buffer, the network device should flush its queue of pending packets. This is done with qemu_flush_queued_packets. e1000's can_receive can go from false to true when RCTL or RDT are modified. Reported-by: Luigi Rizzo Cc: Stefan Hajnoczi Cc: Jan Kiszka Signed-off-by: Paolo Bonzini Reviewed-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- hw/e1000.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'hw') diff --git a/hw/e1000.c b/hw/e1000.c index ae8a6c5523..ec3a7c4ecc 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], s->mac_reg[RCTL]); + qemu_flush_queued_packets(&s->nic->nc); } static void @@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val) { s->check_rxov = 0; s->mac_reg[index] = val & 0xffff; + if (e1000_has_rxbufs(s, 1)) { + qemu_flush_queued_packets(&s->nic->nc); + } } static void -- cgit v1.2.3 From a98b140223d3a627eab7ee3ddec645bab630d756 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Aug 2012 16:45:57 +0200 Subject: xen: flush queue when getting an event xen does not have a register that, when written, will cause can_receive to go from false to true. However, flushing the queue can be attempted whenever the front-end raises its side of the Xen event channel. There is a single event channel for tx and rx. Cc: Stefano Stabellini Cc: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Reviewed-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- hw/xen_nic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw') diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 8b79bfb73e..cf7d5591b3 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -415,6 +415,7 @@ static void net_event(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); net_tx_packets(netdev); + qemu_flush_queued_packets(&netdev->nic->nc); } static int net_free(struct XenDevice *xendev) -- cgit v1.2.3 From 1069985fb132cd4324fc02d371f1e61492a1823f Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Wed, 29 Aug 2012 19:26:11 +0800 Subject: eepro100: Fix network hang when rx buffers run out This is reported by QA. When installing os with pxe, after the initial kernel and initrd are loaded, the procedure tries to copy files from install server to local harddisk, the network becomes stall because of running out of receive descriptor. [Whitespace fixes and removed qemu_notify_event() because Paolo's earlier net patches have moved it into qemu_flush_queued_packets(). Additional info: I can reproduce the network hang with a tap device doing a iPXE HTTP boot as follows: $ qemu -enable-kvm -m 1024 \ -netdev tap,id=netdev0,script=no,downscript=no \ -device i82559er,netdev=netdev0,romfile=80861209.rom \ -drive if=virtio,cache=none,file=test.img iPXE> ifopen net0 iPXE> config # set static network configuration iPXE> kernel http://mirror.bytemark.co.uk/fedora/linux/releases/17/Fedora/x86_64/os/images/pxeboot/vmlinuz I needed a vanilla iPXE ROM to get to the iPXE prompt. I think the boot prompt has been disabled in the ROMs that ship with QEMU to reduce boot time. During the vmlinuz HTTP download there is a network hang. hw/eepro100.c has reached the end of the rx descriptor list. When the iPXE driver replenishes the rx descriptor list we don't kick the QEMU net subsystem and event loop, thereby leaving the tap netdev without its file descriptor in select(2). Stefan Hajnoczi ] Signed-off-by: Bo Yang Signed-off-by: Stefan Hajnoczi --- hw/eepro100.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/eepro100.c b/hw/eepro100.c index 50d117e35e..5b231163d8 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val) } set_ru_state(s, ru_ready); s->ru_offset = e100_read_reg4(s, SCBPointer); + qemu_flush_queued_packets(&s->nic->nc); TRACE(OTHER, logout("val=0x%02x (rx start)\n", val)); break; case RX_RESUME: @@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) if (rfd_command & COMMAND_EL) { /* EL bit is set, so this was the last frame. */ logout("receive: Running out of frames\n"); - set_ru_state(s, ru_suspended); + set_ru_state(s, ru_no_resources); + eepro100_rnr_interrupt(s); } if (rfd_command & COMMAND_S) { /* S bit is set. */ -- cgit v1.2.3 From f237ddbb89142c6948a2257c459e49dee7500a7c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 24 Aug 2012 13:32:16 +0100 Subject: net: clean up usbnet_receive() The USB network interface has two code paths depending on whether or not RNDIS mode is enabled. Refactor usbnet_receive() so that there is a common path throughout the function instead of duplicating everything across if (is_rndis(s)) ... else ... code paths. Clean up coding style and 80 character line wrap along the way. Signed-off-by: Stefan Hajnoczi --- hw/usb/dev-network.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index c84892c98d..0b5cb71f98 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1250,20 +1250,27 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - struct rndis_packet_msg_type *msg; + uint8_t *in_buf = s->in_buf; + size_t total_size = size; if (is_rndis(s)) { - msg = (struct rndis_packet_msg_type *) s->in_buf; if (s->rndis_state != RNDIS_DATA_INITIALIZED) { return -1; } - if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) - return -1; + total_size += sizeof(struct rndis_packet_msg_type); + } + if (total_size > sizeof(s->in_buf)) { + return -1; + } + if (is_rndis(s)) { + struct rndis_packet_msg_type *msg; + + msg = (struct rndis_packet_msg_type *)in_buf; memset(msg, 0, sizeof(struct rndis_packet_msg_type)); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); - msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type)); - msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8); + msg->MessageLength = cpu_to_le32(size + sizeof(*msg)); + msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8); msg->DataLength = cpu_to_le32(size); /* msg->OOBDataOffset; * msg->OOBDataLength; @@ -1273,14 +1280,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz * msg->VcHandle; * msg->Reserved; */ - memcpy(msg + 1, buf, size); - s->in_len = size + sizeof(struct rndis_packet_msg_type); - } else { - if (size > sizeof(s->in_buf)) - return -1; - memcpy(s->in_buf, buf, size); - s->in_len = size; + in_buf += sizeof(*msg); } + + memcpy(in_buf, buf, size); + s->in_len = total_size; s->in_ptr = 0; return size; } -- cgit v1.2.3 From 190563f9a90c9df8ad32fc7f3e4b166deda949a6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 24 Aug 2012 13:37:29 +0100 Subject: net: fix usbnet_receive() packet drops The USB network interface has a single buffer which the guest reads from. This patch prevents multiple calls to usbnet_receive() from clobbering the input buffer. Instead we queue packets until buffer space becomes available again. This is inspired by virtio-net and e1000 rxbuf handling. Signed-off-by: Stefan Hajnoczi --- hw/usb/dev-network.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 0b5cb71f98..e4a43599b5 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s, return 0; } +/* Prepare to receive the next packet */ +static void usb_net_reset_in_buf(USBNetState *s) +{ + s->in_ptr = s->in_len = 0; + qemu_flush_queued_packets(&s->nic->nc); +} + static int rndis_parse(USBNetState *s, uint8_t *data, int length) { uint32_t msg_type; @@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length) case RNDIS_RESET_MSG: rndis_clear_responsequeue(s); - s->out_ptr = s->in_ptr = s->in_len = 0; + s->out_ptr = 0; + usb_net_reset_in_buf(s); return rndis_reset_response(s, (rndis_reset_msg_type *) data); case RNDIS_KEEPALIVE_MSG: @@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) int ret = USB_RET_NAK; if (s->in_ptr > s->in_len) { - s->in_ptr = s->in_len = 0; + usb_net_reset_in_buf(s); ret = USB_RET_NAK; return ret; } @@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) if (s->in_ptr >= s->in_len && (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { /* no short packet necessary */ - s->in_ptr = s->in_len = 0; + usb_net_reset_in_buf(s); } #ifdef TRAFFIC_DEBUG @@ -1263,6 +1271,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz return -1; } + /* Only accept packet if input buffer is empty */ + if (s->in_len > 0) { + return 0; + } + if (is_rndis(s)) { struct rndis_packet_msg_type *msg; -- cgit v1.2.3