All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support
@ 2011-02-15 16:27 Michael S. Tsirkin
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 1/3] " Michael S. Tsirkin
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Michael S. Tsirkin @ 2011-02-15 16:27 UTC (permalink / raw)
  To: qemu-devel, Anthony Liguori
  Cc: kwolf, Jes.Sorensen, Alex Williamson, agraf, stefanha

e1000 supports multi-buffer packets larger than rxbuf_size.

This fixes the following (on linux):
- in guest: ifconfig eth1 mtu 16110
- in host: ifconfig tap0 mtu 16110
           ping -s 16082 <guest-ip>

Red Hat bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=602205

Changes from v1:
	fix buffer overflow reported by Kevin
	added a patch to fix EOP spec violation reported by Juan
	added a patch to fix spec violation noted by myself


Michael S. Tsirkin (3):
  e1000: multi-buffer packet support
  e1000: clear EOP for multi-buffer descriptors
  e1000: verify we have buffers, upfront

 hw/e1000.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 48 insertions(+), 13 deletions(-)

-- 
1.7.3.2.91.g446ac

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCHv2 1/3] e1000: multi-buffer packet support
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
@ 2011-02-15 16:27 ` Michael S. Tsirkin
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 2/3] e1000: clear EOP for multi-buffer descriptors Michael S. Tsirkin
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Michael S. Tsirkin @ 2011-02-15 16:27 UTC (permalink / raw)
  To: qemu-devel, Anthony Liguori
  Cc: kwolf, Jes.Sorensen, Alex Williamson, agraf, stefanha

e1000 supports multi-buffer packets larger than rxbuf_size.

This fixes the following (on linux):
- in guest: ifconfig eth1 mtu 16110
- in host: ifconfig tap0 mtu 16110
           ping -s 16082 <guest-ip>

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 hw/e1000.c |   39 ++++++++++++++++++++++++++++-----------
 1 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/hw/e1000.c b/hw/e1000.c
index af101bd..050ce02 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -642,6 +642,9 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
     uint16_t vlan_special = 0;
     uint8_t vlan_status = 0, vlan_offset = 0;
     uint8_t min_buf[MIN_BUF_SIZE];
+    size_t desc_offset;
+    size_t desc_size;
+    size_t total_size;
 
     if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
         return -1;
@@ -654,12 +657,6 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
         size = sizeof(min_buf);
     }
 
-    if (size > s->rxbuf_size) {
-        DBGOUT(RX, "packet too large for buffers (%lu > %d)\n",
-               (unsigned long)size, s->rxbuf_size);
-        return -1;
-    }
-
     if (!receive_filter(s, buf, size))
         return size;
 
@@ -672,8 +669,16 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
     }
 
     rdh_start = s->mac_reg[RDH];
+    desc_offset = 0;
+    total_size = size + fcs_len(s);
     do {
+        desc_size = total_size - desc_offset;
+        if (desc_size > s->rxbuf_size) {
+            desc_size = s->rxbuf_size;
+        }
         if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
+            /* Discard all data written so far */
+            s->mac_reg[RDH] = rdh_start;
             set_ics(s, 0, E1000_ICS_RXO);
             return -1;
         }
@@ -683,10 +688,22 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
         desc.special = vlan_special;
         desc.status |= (vlan_status | E1000_RXD_STAT_DD);
         if (desc.buffer_addr) {
-            cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
-                                      (void *)(buf + vlan_offset), size);
-            desc.length = cpu_to_le16(size + fcs_len(s));
-            desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
+            if (desc_offset < size) {
+                size_t copy_size = size - desc_offset;
+                if (copy_size > s->rxbuf_size) {
+                    copy_size = s->rxbuf_size;
+                }
+                cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr),
+                                          (void *)(buf + desc_offset + vlan_offset),
+                                          copy_size);
+            }
+            desc_offset += desc_size;
+            if (desc_offset >= total_size) {
+                desc.length = cpu_to_le16(desc_size);
+                desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
+            } else {
+                desc.length = cpu_to_le16(desc_size);
+            }
         } else { // as per intel docs; skip descriptors with null buf addr
             DBGOUT(RX, "Null RX descriptor!!\n");
         }
@@ -702,7 +719,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
             set_ics(s, 0, E1000_ICS_RXO);
             return -1;
         }
-    } while (desc.buffer_addr == 0);
+    } while (desc_offset < total_size);
 
     s->mac_reg[GPRC]++;
     s->mac_reg[TPR]++;
-- 
1.7.3.2.91.g446ac

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCHv2 2/3] e1000: clear EOP for multi-buffer descriptors
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 1/3] " Michael S. Tsirkin
@ 2011-02-15 16:27 ` Michael S. Tsirkin
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 3/3] e1000: verify we have buffers, upfront Michael S. Tsirkin
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Michael S. Tsirkin @ 2011-02-15 16:27 UTC (permalink / raw)
  To: qemu-devel, Anthony Liguori
  Cc: kwolf, Jes.Sorensen, Alex Williamson, agraf, stefanha

The e1000 spec says: if software statically allocates
buffers, and uses memory read to check for completed descriptors, it
simply has to zero the status byte in the descriptor to make it ready
for reuse by hardware. This is not a hardware requirement (moving the
hardware tail pointer is), but is necessary for performing an in–memory
scan.

Thus the guest does not have to clear the status byte.  In case it
doesn't we need to clear EOP for all descriptors
except the last.  While I don't know of any such guests,
it's probably a good idea to stick to the spec.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reported-by: Juan Quintela <quintela@redhat.com>
---
 hw/e1000.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/e1000.c b/hw/e1000.c
index 050ce02..2943a1a 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -698,11 +698,13 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
                                           copy_size);
             }
             desc_offset += desc_size;
+            desc.length = cpu_to_le16(desc_size);
             if (desc_offset >= total_size) {
-                desc.length = cpu_to_le16(desc_size);
                 desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
             } else {
-                desc.length = cpu_to_le16(desc_size);
+                /* Guest zeroing out status is not a hardware requirement.
+                   Clear EOP in case guest didn't do it. */
+                desc.status &= ~E1000_RXD_STAT_EOP;
             }
         } else { // as per intel docs; skip descriptors with null buf addr
             DBGOUT(RX, "Null RX descriptor!!\n");
-- 
1.7.3.2.91.g446ac

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCHv2 3/3] e1000: verify we have buffers, upfront
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 1/3] " Michael S. Tsirkin
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 2/3] e1000: clear EOP for multi-buffer descriptors Michael S. Tsirkin
@ 2011-02-15 16:27 ` Michael S. Tsirkin
  2011-02-16 11:37 ` [Qemu-devel] Re: [PATCHv2 0/3] e1000: multi-buffer packet support Stefan Hajnoczi
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Michael S. Tsirkin @ 2011-02-15 16:27 UTC (permalink / raw)
  To: qemu-devel, Anthony Liguori
  Cc: kwolf, Jes.Sorensen, Alex Williamson, agraf, stefanha

The spec says: Any descriptor with a non-zero status byte has been
processed by the hardware, and is ready to be handled by the software.

Thus, once we change a descriptor status to non-zero we should
never move the head backwards and try to reuse this
descriptor from hardware.

This actually happened with a multibuffer packet
that arrives when we don't have enough buffers.

Fix by checking that we have enough buffers upfront
so we never need to discard the packet midway through.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/e1000.c |   28 ++++++++++++++++++++++------
 1 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/hw/e1000.c b/hw/e1000.c
index 2943a1a..0a4574c 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -631,6 +631,24 @@ e1000_can_receive(VLANClientState *nc)
     return (s->mac_reg[RCTL] & E1000_RCTL_EN);
 }
 
+static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
+{
+    int bufs;
+    /* Fast-path short packets */
+    if (total_size <= s->rxbuf_size) {
+        return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov;
+    }
+    if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
+        bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) {
+        bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
+            s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else {
+        return false;
+    }
+    return total_size <= bufs * s->rxbuf_size;
+}
+
 static ssize_t
 e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 {
@@ -671,17 +689,15 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
     rdh_start = s->mac_reg[RDH];
     desc_offset = 0;
     total_size = size + fcs_len(s);
+    if (!e1000_has_rxbufs(s, total_size)) {
+            set_ics(s, 0, E1000_ICS_RXO);
+            return -1;
+    }
     do {
         desc_size = total_size - desc_offset;
         if (desc_size > s->rxbuf_size) {
             desc_size = s->rxbuf_size;
         }
-        if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
-            /* Discard all data written so far */
-            s->mac_reg[RDH] = rdh_start;
-            set_ics(s, 0, E1000_ICS_RXO);
-            return -1;
-        }
         base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
                sizeof(desc) * s->mac_reg[RDH];
         cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
-- 
1.7.3.2.91.g446ac

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] Re: [PATCHv2 0/3] e1000: multi-buffer packet support
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
                   ` (2 preceding siblings ...)
  2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 3/3] e1000: verify we have buffers, upfront Michael S. Tsirkin
@ 2011-02-16 11:37 ` Stefan Hajnoczi
  2011-02-17  0:05 ` [Qemu-devel] " Alex Williamson
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Stefan Hajnoczi @ 2011-02-16 11:37 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: kwolf, Jes.Sorensen, qemu-devel, agraf, Alex Williamson

On Tue, Feb 15, 2011 at 06:27:44PM +0200, Michael S. Tsirkin wrote:
> e1000 supports multi-buffer packets larger than rxbuf_size.
> 
> This fixes the following (on linux):
> - in guest: ifconfig eth1 mtu 16110
> - in host: ifconfig tap0 mtu 16110
>            ping -s 16082 <guest-ip>
> 
> Red Hat bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=602205
> 
> Changes from v1:
> 	fix buffer overflow reported by Kevin
> 	added a patch to fix EOP spec violation reported by Juan
> 	added a patch to fix spec violation noted by myself
> 
> 
> Michael S. Tsirkin (3):
>   e1000: multi-buffer packet support
>   e1000: clear EOP for multi-buffer descriptors
>   e1000: verify we have buffers, upfront
> 
>  hw/e1000.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++------------
>  1 files changed, 48 insertions(+), 13 deletions(-)

Took a quick look, looks good.

Stefan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
                   ` (3 preceding siblings ...)
  2011-02-16 11:37 ` [Qemu-devel] Re: [PATCHv2 0/3] e1000: multi-buffer packet support Stefan Hajnoczi
@ 2011-02-17  0:05 ` Alex Williamson
  2011-02-17 12:04 ` [Qemu-devel] " Kevin Wolf
  2011-02-20 14:29 ` [Qemu-devel] " Aurelien Jarno
  6 siblings, 0 replies; 8+ messages in thread
From: Alex Williamson @ 2011-02-17  0:05 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: kwolf, stefanha, Jes.Sorensen, qemu-devel, agraf

On Tue, 2011-02-15 at 18:27 +0200, Michael S. Tsirkin wrote:
> e1000 supports multi-buffer packets larger than rxbuf_size.
> 
> This fixes the following (on linux):
> - in guest: ifconfig eth1 mtu 16110
> - in host: ifconfig tap0 mtu 16110
>            ping -s 16082 <guest-ip>
> 
> Red Hat bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=602205
> 
> Changes from v1:
> 	fix buffer overflow reported by Kevin
> 	added a patch to fix EOP spec violation reported by Juan
> 	added a patch to fix spec violation noted by myself
> 
> 
> Michael S. Tsirkin (3):
>   e1000: multi-buffer packet support
>   e1000: clear EOP for multi-buffer descriptors
>   e1000: verify we have buffers, upfront
> 
>  hw/e1000.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++------------
>  1 files changed, 48 insertions(+), 13 deletions(-)
> 

Acked-by: Alex Williamson <alex.williamson@redhat.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] Re: [PATCHv2 0/3] e1000: multi-buffer packet support
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
                   ` (4 preceding siblings ...)
  2011-02-17  0:05 ` [Qemu-devel] " Alex Williamson
@ 2011-02-17 12:04 ` Kevin Wolf
  2011-02-20 14:29 ` [Qemu-devel] " Aurelien Jarno
  6 siblings, 0 replies; 8+ messages in thread
From: Kevin Wolf @ 2011-02-17 12:04 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: stefanha, Jes.Sorensen, qemu-devel, agraf, Alex Williamson

Am 15.02.2011 17:27, schrieb Michael S. Tsirkin:
> e1000 supports multi-buffer packets larger than rxbuf_size.
> 
> This fixes the following (on linux):
> - in guest: ifconfig eth1 mtu 16110
> - in host: ifconfig tap0 mtu 16110
>            ping -s 16082 <guest-ip>
> 
> Red Hat bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=602205
> 
> Changes from v1:
> 	fix buffer overflow reported by Kevin
> 	added a patch to fix EOP spec violation reported by Juan
> 	added a patch to fix spec violation noted by myself
> 
> 
> Michael S. Tsirkin (3):
>   e1000: multi-buffer packet support
>   e1000: clear EOP for multi-buffer descriptors
>   e1000: verify we have buffers, upfront
> 
>  hw/e1000.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++------------
>  1 files changed, 48 insertions(+), 13 deletions(-)

I found patch 3 to be not that easy to understand (especially the
s->check_rxov part), but after thinking a while about it, it seems to
make sense.

Acked-by: Kevin Wolf <kwolf@redhat.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support
  2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
                   ` (5 preceding siblings ...)
  2011-02-17 12:04 ` [Qemu-devel] " Kevin Wolf
@ 2011-02-20 14:29 ` Aurelien Jarno
  6 siblings, 0 replies; 8+ messages in thread
From: Aurelien Jarno @ 2011-02-20 14:29 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: kwolf, stefanha, Jes.Sorensen, qemu-devel, agraf, Alex Williamson

On Tue, Feb 15, 2011 at 06:27:44PM +0200, Michael S. Tsirkin wrote:
> e1000 supports multi-buffer packets larger than rxbuf_size.
> 
> This fixes the following (on linux):
> - in guest: ifconfig eth1 mtu 16110
> - in host: ifconfig tap0 mtu 16110
>            ping -s 16082 <guest-ip>
> 
> Red Hat bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=602205
> 
> Changes from v1:
> 	fix buffer overflow reported by Kevin
> 	added a patch to fix EOP spec violation reported by Juan
> 	added a patch to fix spec violation noted by myself
> 
> 
> Michael S. Tsirkin (3):
>   e1000: multi-buffer packet support
>   e1000: clear EOP for multi-buffer descriptors
>   e1000: verify we have buffers, upfront
> 
>  hw/e1000.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++------------
>  1 files changed, 48 insertions(+), 13 deletions(-)
> 
> -- 
> 1.7.3.2.91.g446ac
> 

Thanks, all applied.

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-02-20 14:29 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-15 16:27 [Qemu-devel] [PATCHv2 0/3] e1000: multi-buffer packet support Michael S. Tsirkin
2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 1/3] " Michael S. Tsirkin
2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 2/3] e1000: clear EOP for multi-buffer descriptors Michael S. Tsirkin
2011-02-15 16:27 ` [Qemu-devel] [PATCHv2 3/3] e1000: verify we have buffers, upfront Michael S. Tsirkin
2011-02-16 11:37 ` [Qemu-devel] Re: [PATCHv2 0/3] e1000: multi-buffer packet support Stefan Hajnoczi
2011-02-17  0:05 ` [Qemu-devel] " Alex Williamson
2011-02-17 12:04 ` [Qemu-devel] " Kevin Wolf
2011-02-20 14:29 ` [Qemu-devel] " Aurelien Jarno

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.