Browse Source

Add RX quotas to the net device poll() method. This avoids the problem

of alloc_pkb() exhaustion when e.g. an iSCSI-booted DOS session is left
idle for a long time at the C:\ prompt and builds up a huge packet
backlog.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
c65fae2475

+ 35
- 16
src/arch/i386/drivers/net/undinet.c View File

@@ -364,7 +364,8 @@ static int undinet_transmit ( struct net_device *netdev,
364 364
 /** 
365 365
  * Poll for received packets
366 366
  *
367
- * @v netdev	Network device
367
+ * @v netdev		Network device
368
+ * @v rx_quota		Maximum number of packets to receive
368 369
  *
369 370
  * Fun, fun, fun.  UNDI drivers don't use polling; they use
370 371
  * interrupts.  We therefore cheat and pretend that an interrupt has
@@ -382,7 +383,7 @@ static int undinet_transmit ( struct net_device *netdev,
382 383
  * of installing a genuine interrupt service routine and dealing with
383 384
  * the wonderful 8259 Programmable Interrupt Controller.  Joy.
384 385
  */
385
-static void undinet_poll ( struct net_device *netdev ) {
386
+static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
386 387
 	struct undi_nic *undinic = netdev->priv;
387 388
 	struct s_PXENV_UNDI_ISR undi_isr;
388 389
 	struct pk_buff *pkb = NULL;
@@ -416,7 +417,7 @@ static void undinet_poll ( struct net_device *netdev ) {
416 417
 	}
417 418
 
418 419
 	/* Run through the ISR loop */
419
-	while ( 1 ) {
420
+	while ( rx_quota ) {
420 421
 		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
421 422
 					   sizeof ( undi_isr ) ) ) != 0 )
422 423
 			break;
@@ -448,6 +449,7 @@ static void undinet_poll ( struct net_device *netdev ) {
448 449
 			if ( pkb_len ( pkb ) == len ) {
449 450
 				netdev_rx ( netdev, pkb );
450 451
 				pkb = NULL;
452
+				--rx_quota;
451 453
 			}
452 454
 			break;
453 455
 		case PXENV_UNDI_ISR_OUT_DONE:
@@ -480,8 +482,8 @@ static void undinet_poll ( struct net_device *netdev ) {
480 482
  */
481 483
 static int undinet_open ( struct net_device *netdev ) {
482 484
 	struct undi_nic *undinic = netdev->priv;
483
-	struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address;
484
-	struct s_PXENV_UNDI_OPEN open;
485
+	struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
486
+	struct s_PXENV_UNDI_OPEN undi_open;
485 487
 	int rc;
486 488
 
487 489
 	/* Hook interrupt service routine and enable interrupt */
@@ -494,16 +496,16 @@ static int undinet_open ( struct net_device *netdev ) {
494 496
 	 * use it to set the MAC address to the card's permanent value
495 497
 	 * anyway.
496 498
 	 */
497
-	memcpy ( set_address.StationAddress, netdev->ll_addr,
498
-		 sizeof ( set_address.StationAddress ) );
499
+	memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
500
+		 sizeof ( undi_set_address.StationAddress ) );
499 501
 	undinet_call ( undinic, PXENV_UNDI_SET_STATION_ADDRESS,
500
-		       &set_address, sizeof ( set_address ) );
502
+		       &undi_set_address, sizeof ( undi_set_address ) );
501 503
 
502 504
 	/* Open NIC */
503
-	memset ( &open, 0, sizeof ( open ) );
504
-	open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
505
-	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &open,
506
-				   sizeof ( open ) ) ) != 0 )
505
+	memset ( &undi_open, 0, sizeof ( undi_open ) );
506
+	undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
507
+	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open,
508
+				   sizeof ( undi_open ) ) ) != 0 )
507 509
 		goto err;
508 510
 
509 511
 	return 0;
@@ -520,14 +522,31 @@ static int undinet_open ( struct net_device *netdev ) {
520 522
  */
521 523
 static void undinet_close ( struct net_device *netdev ) {
522 524
 	struct undi_nic *undinic = netdev->priv;
523
-	struct s_PXENV_UNDI_CLOSE close;
525
+	struct s_PXENV_UNDI_ISR undi_isr;
526
+	struct s_PXENV_UNDI_CLOSE undi_close;
527
+	int rc;
524 528
 
525 529
 	/* Ensure ISR has exited cleanly */
526
-	while ( undinic->isr_processing )
527
-		undinet_poll ( netdev );
530
+	while ( undinic->isr_processing ) {
531
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
532
+		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
533
+					   sizeof ( undi_isr ) ) ) != 0 )
534
+			break;
535
+		switch ( undi_isr.FuncFlag ) {
536
+		case PXENV_UNDI_ISR_OUT_TRANSMIT:
537
+		case PXENV_UNDI_ISR_OUT_RECEIVE:
538
+			/* Continue draining */
539
+			break;
540
+		default:
541
+			/* Stop processing */
542
+			undinic->isr_processing = 0;
543
+			break;
544
+		}
545
+	}
528 546
 
529 547
 	/* Close NIC */
530
-	undinet_call ( undinic, PXENV_UNDI_CLOSE, &close, sizeof ( close ) );
548
+	undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close,
549
+		       sizeof ( undi_close ) );
531 550
 
532 551
 	/* Disable interrupt and unhook ISR */
533 552
 	disable_irq ( undinic->irq );

+ 4
- 1
src/drivers/net/legacy.c View File

@@ -38,10 +38,13 @@ static int legacy_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
38 38
 	return 0;
39 39
 }
40 40
 
41
-static void legacy_poll ( struct net_device *netdev ) {
41
+static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) {
42 42
 	struct nic *nic = netdev->priv;
43 43
 	struct pk_buff *pkb;
44 44
 
45
+	if ( ! rx_quota )
46
+		return;
47
+
45 48
 	pkb = alloc_pkb ( ETH_FRAME_LEN );
46 49
 	if ( ! pkb )
47 50
 		return;

+ 3
- 2
src/drivers/net/pnic.c View File

@@ -112,14 +112,14 @@ static int pnic_api_check ( uint16_t api_version ) {
112 112
 /**************************************************************************
113 113
 POLL - Wait for a frame
114 114
 ***************************************************************************/
115
-static void pnic_poll ( struct net_device *netdev ) {
115
+static void pnic_poll ( struct net_device *netdev, unsigned int rx_quota ) {
116 116
 	struct pnic *pnic = netdev->priv;
117 117
 	struct pk_buff *pkb;
118 118
 	uint16_t length;
119 119
 	uint16_t qlen;
120 120
 
121 121
 	/* Fetch all available packets */
122
-	while ( 1 ) {
122
+	while ( rx_quota ) {
123 123
 		if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
124 124
 				    &qlen, sizeof ( qlen ), NULL )
125 125
 		     != PNIC_STATUS_OK )
@@ -139,6 +139,7 @@ static void pnic_poll ( struct net_device *netdev ) {
139 139
 		}
140 140
 		pkb_put ( pkb, length );
141 141
 		netdev_rx ( netdev, pkb );
142
+		--rx_quota;
142 143
 	}
143 144
 }
144 145
 

+ 3
- 2
src/drivers/net/rtl8139.c View File

@@ -413,8 +413,9 @@ static int rtl_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
413 413
  * Poll for received packets
414 414
  *
415 415
  * @v netdev	Network device
416
+ * @v rx_quota	Maximum number of packets to receive
416 417
  */
417
-static void rtl_poll ( struct net_device *netdev ) {
418
+static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) {
418 419
 	struct rtl8139_nic *rtl = netdev->priv;
419 420
 	unsigned int status;
420 421
 	unsigned int tsad;
@@ -441,7 +442,7 @@ static void rtl_poll ( struct net_device *netdev ) {
441 442
 	}
442 443
 
443 444
 	/* Handle received packets */
444
-	while ( ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) {
445
+	while ( rx_quota && ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ){
445 446
 		rx_status = * ( ( uint16_t * )
446 447
 				( rtl->rx.ring + rtl->rx.offset ) );
447 448
 		rx_len = * ( ( uint16_t * )

+ 4
- 3
src/include/gpxe/netdevice.h View File

@@ -181,15 +181,16 @@ struct net_device {
181 181
 	/** Poll for received packet
182 182
 	 *
183 183
 	 * @v netdev	Network device
184
+	 * @v rx_quota	Maximum number of packets to receive
184 185
 	 *
185 186
 	 * This method should cause the hardware to check for received
186 187
 	 * packets.  Any received packets should be delivered via
187
-	 * netdev_rx().
188
+	 * netdev_rx(), up to a maximum of @c rx_quota packets.
188 189
 	 *
189 190
 	 * This method is guaranteed to be called only when the device
190 191
 	 * is open.
191 192
 	 */
192
-	void ( * poll ) ( struct net_device *netdev );
193
+	void ( * poll ) ( struct net_device *netdev, unsigned int rx_quota );
193 194
 
194 195
 	/** Link-layer protocol */
195 196
 	struct ll_protocol *ll_protocol;
@@ -238,7 +239,7 @@ extern int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb );
238 239
 void netdev_tx_complete ( struct net_device *netdev, struct pk_buff *pkb );
239 240
 void netdev_tx_complete_next ( struct net_device *netdev );
240 241
 extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
241
-extern int netdev_poll ( struct net_device *netdev );
242
+extern int netdev_poll ( struct net_device *netdev, unsigned int rx_quota );
242 243
 extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev );
243 244
 extern struct net_device * alloc_netdev ( size_t priv_size );
244 245
 extern int register_netdev ( struct net_device *netdev );

+ 27
- 13
src/net/netdevice.c View File

@@ -126,16 +126,17 @@ void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
126 126
  * Poll for packet on network device
127 127
  *
128 128
  * @v netdev		Network device
129
+ * @v rx_quota		Maximum number of packets to receive
129 130
  * @ret True		There are packets present in the receive queue
130 131
  * @ret False		There are no packets present in the receive queue
131 132
  *
132 133
  * Polls the network device for received packets.  Any received
133 134
  * packets will be added to the RX packet queue via netdev_rx().
134 135
  */
135
-int netdev_poll ( struct net_device *netdev ) {
136
+int netdev_poll ( struct net_device *netdev, unsigned int rx_quota ) {
136 137
 
137 138
 	if ( netdev->state & NETDEV_OPEN )
138
-		netdev->poll ( netdev );
139
+		netdev->poll ( netdev, rx_quota );
139 140
 
140 141
 	return ( ! list_empty ( &netdev->rx_queue ) );
141 142
 }
@@ -351,14 +352,9 @@ int net_rx ( struct pk_buff *pkb, struct net_device *netdev,
351 352
  *
352 353
  * @v process		Network stack process
353 354
  *
354
- * This polls all interfaces for any received packets, and processes
355
- * at most one packet from the RX queue.
355
+ * This polls all interfaces for received packets, and processes
356
+ * packets from the RX queue.
356 357
  *
357
- * We avoid processing all received packets, because processing the
358
- * received packet can trigger transmission of a new packet (e.g. an
359
- * ARP response).  Since TX completions will be processed as part of
360
- * the poll operation, it is easy to overflow small TX queues if
361
- * multiple packets are processed per poll.
362 358
  */
363 359
 static void net_step ( struct process *process ) {
364 360
 	struct net_device *netdev;
@@ -367,10 +363,28 @@ static void net_step ( struct process *process ) {
367 363
 	/* Poll and process each network device */
368 364
 	list_for_each_entry ( netdev, &net_devices, list ) {
369 365
 
370
-		/* Poll for new packets */
371
-		netdev_poll ( netdev );
372
-
373
-		/* Handle at most one received packet per poll */
366
+		/* Poll for new packets.  Limit RX queue size to a
367
+		 * single packet, because otherwise most drivers are
368
+		 * in serious danger of running out of memory and
369
+		 * having to drop packets.
370
+		 *
371
+		 * This limitation isn't relevant to devices that
372
+		 * preallocate packet buffers (i.e. devices with
373
+		 * descriptor-based RX datapaths).  We might at some
374
+		 * point want to relax the quota for such devices.
375
+		 */
376
+		netdev_poll ( netdev,
377
+			      ( list_empty ( &netdev->rx_queue ) ? 1 : 0 ) );
378
+
379
+		/* Handle at most one received packet per poll.  We
380
+		 * avoid processing more than one packet per call to
381
+		 * netdev_poll(), because processing the received
382
+		 * packet can trigger transmission of a new packet
383
+		 * (e.g. an ARP response).  Since TX completions will
384
+		 * be processed as part of the poll operation, it is
385
+		 * easy to overflow small TX queues if multiple
386
+		 * packets are processed per poll.
387
+		 */
374 388
 		if ( ( pkb = netdev_rx_dequeue ( netdev ) ) ) {
375 389
 			DBGC ( netdev, "NETDEV %p processing %p\n",
376 390
 			       netdev, pkb );

Loading…
Cancel
Save