Browse Source

[xen] Provide 18 4kB receive buffers to work around xen-netback bug

The Xen network backend (xen-netback) suffered from a regression
between upstream Linux kernels 3.18 and 4.2 inclusive, which would
cause packet reception to fail unless at least 18 receive buffers were
available.  This bug was fixed in kernel commit 1d5d485 ("xen-netback:
require fewer guest Rx slots when not using GSO").

Work around this bug in affected versions of xen-netback by providing
the requisite 18 receive buffers.

Reported-by: Taylor Schneider <tschneider@live.com>
Tested-by: Taylor Schneider <tschneider@live.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
7457bfc5b2
2 changed files with 41 additions and 15 deletions
  1. 10
    9
      src/drivers/net/netfront.c
  2. 31
    6
      src/drivers/net/netfront.h

+ 10
- 9
src/drivers/net/netfront.c View File

@@ -511,15 +511,12 @@ static void netfront_refill_rx ( struct net_device *netdev ) {
511 511
 	struct xen_device *xendev = netfront->xendev;
512 512
 	struct io_buffer *iobuf;
513 513
 	struct netif_rx_request *request;
514
+	unsigned int refilled = 0;
514 515
 	int notify;
515 516
 	int rc;
516 517
 
517
-	/* Do nothing if ring is already full */
518
-	if ( netfront_ring_is_full ( &netfront->rx ) )
519
-		return;
520
-
521 518
 	/* Refill ring */
522
-	do {
519
+	while ( netfront_ring_fill ( &netfront->rx ) < NETFRONT_RX_FILL ) {
523 520
 
524 521
 		/* Allocate I/O buffer */
525 522
 		iobuf = alloc_iob ( PAGE_SIZE );
@@ -543,13 +540,17 @@ static void netfront_refill_rx ( struct net_device *netdev ) {
543 540
 
544 541
 		/* Move to next descriptor */
545 542
 		netfront->rx_fring.req_prod_pvt++;
543
+		refilled++;
546 544
 
547
-	} while ( ! netfront_ring_is_full ( &netfront->rx ) );
545
+	}
548 546
 
549 547
 	/* Push new descriptors and notify backend if applicable */
550
-	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring, notify );
551
-	if ( notify )
552
-		netfront_send_event ( netfront );
548
+	if ( refilled ) {
549
+		RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring,
550
+						      notify );
551
+		if ( notify )
552
+			netfront_send_event ( netfront );
553
+	}
553 554
 }
554 555
 
555 556
 /**

+ 31
- 6
src/drivers/net/netfront.h View File

@@ -16,7 +16,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
16 16
 #define NETFRONT_NUM_TX_DESC 16
17 17
 
18 18
 /** Number of receive ring entries */
19
-#define NETFRONT_NUM_RX_DESC 8
19
+#define NETFRONT_NUM_RX_DESC 32
20
+
21
+/** Receive ring fill level
22
+ *
23
+ * The xen-netback driver from kernels 3.18 to 4.2 inclusive have a
24
+ * bug (CA-163395) which prevents packet reception if fewer than 18
25
+ * receive descriptors are available.  This was fixed in upstream
26
+ * kernel commit d5d4852 ("xen-netback: require fewer guest Rx slots
27
+ * when not using GSO").
28
+ *
29
+ * We provide 18 receive descriptors to avoid unpleasant silent
30
+ * failures on these kernel versions.
31
+ */
32
+#define NETFRONT_RX_FILL 18
20 33
 
21 34
 /** Grant reference indices */
22 35
 enum netfront_ref_index {
@@ -88,6 +101,21 @@ netfront_init_ring ( struct netfront_ring *ring, const char *ref_key,
88 101
 	ring->ids = ids;
89 102
 }
90 103
 
104
+/**
105
+ * Calculate descriptor ring fill level
106
+ *
107
+ * @v ring		Descriptor ring
108
+ * @v fill		Fill level
109
+ */
110
+static inline __attribute__ (( always_inline )) unsigned int
111
+netfront_ring_fill ( struct netfront_ring *ring ) {
112
+	unsigned int fill_level;
113
+
114
+	fill_level = ( ring->id_prod - ring->id_cons );
115
+	assert ( fill_level <= ring->count );
116
+	return fill_level;
117
+}
118
+
91 119
 /**
92 120
  * Check whether or not descriptor ring is full
93 121
  *
@@ -96,11 +124,8 @@ netfront_init_ring ( struct netfront_ring *ring, const char *ref_key,
96 124
  */
97 125
 static inline __attribute__ (( always_inline )) int
98 126
 netfront_ring_is_full ( struct netfront_ring *ring ) {
99
-	unsigned int fill_level;
100 127
 
101
-	fill_level = ( ring->id_prod - ring->id_cons );
102
-	assert ( fill_level <= ring->count );
103
-	return ( fill_level >= ring->count );
128
+	return ( netfront_ring_fill ( ring ) >= ring->count );
104 129
 }
105 130
 
106 131
 /**
@@ -112,7 +137,7 @@ netfront_ring_is_full ( struct netfront_ring *ring ) {
112 137
 static inline __attribute__ (( always_inline )) int
113 138
 netfront_ring_is_empty ( struct netfront_ring *ring ) {
114 139
 
115
-	return ( ring->id_prod == ring->id_cons );
140
+	return ( netfront_ring_fill ( ring ) == 0 );
116 141
 }
117 142
 
118 143
 /** A netfront NIC */

Loading…
Cancel
Save