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