b29fd25
From e670b85a691a6e39bce4b69f2175e0bfebc93f51 Mon Sep 17 00:00:00 2001
b29fd25
From: Mark McLoughlin <markmc@redhat.com>
b29fd25
Date: Thu, 29 Oct 2009 11:34:17 +0000
b29fd25
Subject: [PATCH] net: disable draining tap queue in one go
b29fd25
b29fd25
If qemu_send_packet_async() returns zero, it means the packet has been
b29fd25
queued and the sent callback will be invoked once it has been flushed.
b29fd25
b29fd25
This is only possible where the NIC's receive() handler returns zero
b29fd25
and promises to notify the networking core that room is available in its
b29fd25
queue again.
b29fd25
b29fd25
In the case where the receive handler does not have this capability
b29fd25
(and its queue fills up) it returns -1 and the networking core does not
b29fd25
queue up the packet. This condition is indicated by a -1 return from
b29fd25
qemu_send_packet_async().
b29fd25
b29fd25
Currently, tap handles this condition simply by dropping the packet. It
b29fd25
should do its best to avoid getting into this situation by checking such
b29fd25
NIC's have room for a packet before copying the packet from the tap
b29fd25
interface.
b29fd25
b29fd25
tap_send() used to achieve this by only reading a single packet before
b29fd25
returning to the mainloop. That way, tap_can_send() is called before
b29fd25
reading each packet.
b29fd25
b29fd25
tap_send() was changed to completely drain the tap interface queue
b29fd25
without taking into account the situation where the NIC returns an
b29fd25
error and the packet is not queued. Let's start fixing this by
b29fd25
reverting to the previous behaviour of reading one packet at a time.
b29fd25
b29fd25
Reported-by: Scott Tsai <scottt.tw@gmail.com>
b29fd25
Tested-by: Sven Rudolph <Sven_Rudolph@drewag.de>
b29fd25
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
b29fd25
b29fd25
Fedora-patch: qemu-fix-dropped-packets-with-non-virtio-nics.patch
b29fd25
---
b29fd25
 net.c |   29 +++++++++++++----------------
b29fd25
 1 files changed, 13 insertions(+), 16 deletions(-)
b29fd25
b29fd25
diff --git a/net.c b/net.c
b29fd25
index 3572c48..3abab95 100644
b29fd25
--- a/net.c
b29fd25
+++ b/net.c
b29fd25
@@ -1453,27 +1453,24 @@ static void tap_send(void *opaque)
b29fd25
 {
b29fd25
     TAPState *s = opaque;
b29fd25
     int size;
b29fd25
+    uint8_t *buf = s->buf;
b29fd25
 
b29fd25
-    do {
b29fd25
-        uint8_t *buf = s->buf;
b29fd25
-
b29fd25
-        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
b29fd25
-        if (size <= 0) {
b29fd25
-            break;
b29fd25
-        }
b29fd25
+    size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
b29fd25
+    if (size <= 0) {
b29fd25
+        break;
b29fd25
+    }
b29fd25
 
b29fd25
 #ifdef IFF_VNET_HDR
b29fd25
-        if (s->has_vnet_hdr && !s->using_vnet_hdr) {
b29fd25
-            buf += sizeof(struct virtio_net_hdr);
b29fd25
-            size -= sizeof(struct virtio_net_hdr);
b29fd25
-        }
b29fd25
+    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
b29fd25
+        buf += sizeof(struct virtio_net_hdr);
b29fd25
+        size -= sizeof(struct virtio_net_hdr);
b29fd25
+    }
b29fd25
 #endif
b29fd25
 
b29fd25
-        size = qemu_send_packet_async(s->vc, buf, size, tap_send_completed);
b29fd25
-        if (size == 0) {
b29fd25
-            tap_read_poll(s, 0);
b29fd25
-        }
b29fd25
-    } while (size > 0);
b29fd25
+    size = qemu_send_packet_async(s->vc, buf, size, tap_send_completed);
b29fd25
+    if (size == 0) {
b29fd25
+        tap_read_poll(s, 0);
b29fd25
+    }
b29fd25
 }
b29fd25
 
b29fd25
 #ifdef TUNSETSNDBUF
b29fd25
-- 
b29fd25
1.6.2.5
b29fd25