소스 검색

[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 년 전
부모
커밋
7457bfc5b2
2개의 변경된 파일41개의 추가작업 그리고 15개의 파일을 삭제
  1. 10
    9
      src/drivers/net/netfront.c
  2. 31
    6
      src/drivers/net/netfront.h

+ 10
- 9
src/drivers/net/netfront.c 파일 보기

511
 	struct xen_device *xendev = netfront->xendev;
511
 	struct xen_device *xendev = netfront->xendev;
512
 	struct io_buffer *iobuf;
512
 	struct io_buffer *iobuf;
513
 	struct netif_rx_request *request;
513
 	struct netif_rx_request *request;
514
+	unsigned int refilled = 0;
514
 	int notify;
515
 	int notify;
515
 	int rc;
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
 	/* Refill ring */
518
 	/* Refill ring */
522
-	do {
519
+	while ( netfront_ring_fill ( &netfront->rx ) < NETFRONT_RX_FILL ) {
523
 
520
 
524
 		/* Allocate I/O buffer */
521
 		/* Allocate I/O buffer */
525
 		iobuf = alloc_iob ( PAGE_SIZE );
522
 		iobuf = alloc_iob ( PAGE_SIZE );
543
 
540
 
544
 		/* Move to next descriptor */
541
 		/* Move to next descriptor */
545
 		netfront->rx_fring.req_prod_pvt++;
542
 		netfront->rx_fring.req_prod_pvt++;
543
+		refilled++;
546
 
544
 
547
-	} while ( ! netfront_ring_is_full ( &netfront->rx ) );
545
+	}
548
 
546
 
549
 	/* Push new descriptors and notify backend if applicable */
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 파일 보기

16
 #define NETFRONT_NUM_TX_DESC 16
16
 #define NETFRONT_NUM_TX_DESC 16
17
 
17
 
18
 /** Number of receive ring entries */
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
 /** Grant reference indices */
34
 /** Grant reference indices */
22
 enum netfront_ref_index {
35
 enum netfront_ref_index {
88
 	ring->ids = ids;
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
  * Check whether or not descriptor ring is full
120
  * Check whether or not descriptor ring is full
93
  *
121
  *
96
  */
124
  */
97
 static inline __attribute__ (( always_inline )) int
125
 static inline __attribute__ (( always_inline )) int
98
 netfront_ring_is_full ( struct netfront_ring *ring ) {
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
 static inline __attribute__ (( always_inline )) int
137
 static inline __attribute__ (( always_inline )) int
113
 netfront_ring_is_empty ( struct netfront_ring *ring ) {
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
 /** A netfront NIC */
143
 /** A netfront NIC */

Loading…
취소
저장