Browse Source

[netdevice] Add a generic concept of a "blocked link"

When Spanning Tree Protocol (STP) is used, there may be a substantial
delay (tens of seconds) from the time that the link goes up to the
time that the port starts forwarding packets.

Add a generic concept of a "blocked link" (i.e. a link which is up but
which is not expected to communicate successfully), and allow "ifstat"
to indicate when a link is blocked.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
f3812395a2
3 changed files with 70 additions and 2 deletions
  1. 17
    0
      src/include/ipxe/netdevice.h
  2. 51
    1
      src/net/netdevice.c
  3. 2
    1
      src/usr/ifmgmt.c

+ 17
- 0
src/include/ipxe/netdevice.h View File

15
 #include <ipxe/refcnt.h>
15
 #include <ipxe/refcnt.h>
16
 #include <ipxe/settings.h>
16
 #include <ipxe/settings.h>
17
 #include <ipxe/interface.h>
17
 #include <ipxe/interface.h>
18
+#include <ipxe/retry.h>
18
 
19
 
19
 struct io_buffer;
20
 struct io_buffer;
20
 struct net_device;
21
 struct net_device;
392
 	 * indicates the error preventing link-up.
393
 	 * indicates the error preventing link-up.
393
 	 */
394
 	 */
394
 	int link_rc;
395
 	int link_rc;
396
+	/** Link block timer */
397
+	struct retry_timer link_block;
395
 	/** Maximum packet length
398
 	/** Maximum packet length
396
 	 *
399
 	 *
397
 	 * This length includes any link-layer headers.
400
 	 * This length includes any link-layer headers.
613
 	return ( netdev->link_rc == 0 );
616
 	return ( netdev->link_rc == 0 );
614
 }
617
 }
615
 
618
 
619
+/**
620
+ * Check link block state of network device
621
+ *
622
+ * @v netdev		Network device
623
+ * @ret link_blocked	Link is blocked
624
+ */
625
+static inline __attribute__ (( always_inline )) int
626
+netdev_link_blocked ( struct net_device *netdev ) {
627
+	return ( timer_running ( &netdev->link_block ) );
628
+}
629
+
616
 /**
630
 /**
617
  * Check whether or not network device is open
631
  * Check whether or not network device is open
618
  *
632
  *
661
 extern void netdev_rx_unfreeze ( struct net_device *netdev );
675
 extern void netdev_rx_unfreeze ( struct net_device *netdev );
662
 extern void netdev_link_err ( struct net_device *netdev, int rc );
676
 extern void netdev_link_err ( struct net_device *netdev, int rc );
663
 extern void netdev_link_down ( struct net_device *netdev );
677
 extern void netdev_link_down ( struct net_device *netdev );
678
+extern void netdev_link_block ( struct net_device *netdev,
679
+				unsigned long timeout );
680
+extern void netdev_link_unblock ( struct net_device *netdev );
664
 extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
681
 extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
665
 extern void netdev_tx_defer ( struct net_device *netdev,
682
 extern void netdev_tx_defer ( struct net_device *netdev,
666
 			      struct io_buffer *iobuf );
683
 			      struct io_buffer *iobuf );

+ 51
- 1
src/net/netdevice.c View File

161
  */
161
  */
162
 void netdev_link_err ( struct net_device *netdev, int rc ) {
162
 void netdev_link_err ( struct net_device *netdev, int rc ) {
163
 
163
 
164
+	/* Stop link block timer */
165
+	stop_timer ( &netdev->link_block );
166
+
164
 	/* Record link state */
167
 	/* Record link state */
165
 	netdev->link_rc = rc;
168
 	netdev->link_rc = rc;
166
 	if ( netdev->link_rc == 0 ) {
169
 	if ( netdev->link_rc == 0 ) {
190
 	}
193
 	}
191
 }
194
 }
192
 
195
 
196
+/**
197
+ * Mark network device link as being blocked
198
+ *
199
+ * @v netdev		Network device
200
+ * @v timeout		Timeout (in ticks)
201
+ */
202
+void netdev_link_block ( struct net_device *netdev, unsigned long timeout ) {
203
+
204
+	/* Start link block timer */
205
+	if ( ! netdev_link_blocked ( netdev ) ) {
206
+		DBGC ( netdev, "NETDEV %s link blocked for %ld ticks\n",
207
+		       netdev->name, timeout );
208
+	}
209
+	start_timer_fixed ( &netdev->link_block, timeout );
210
+}
211
+
212
+/**
213
+ * Mark network device link as being unblocked
214
+ *
215
+ * @v netdev		Network device
216
+ */
217
+void netdev_link_unblock ( struct net_device *netdev ) {
218
+
219
+	/* Stop link block timer */
220
+	if ( netdev_link_blocked ( netdev ) )
221
+		DBGC ( netdev, "NETDEV %s link unblocked\n", netdev->name );
222
+	stop_timer ( &netdev->link_block );
223
+}
224
+
225
+/**
226
+ * Handle network device link block timer expiry
227
+ *
228
+ * @v timer		Link block timer
229
+ * @v fail		Failure indicator
230
+ */
231
+static void netdev_link_block_expired ( struct retry_timer *timer,
232
+					int fail __unused ) {
233
+	struct net_device *netdev =
234
+		container_of ( timer, struct net_device, link_block );
235
+
236
+	/* Assume link is no longer blocked */
237
+	DBGC ( netdev, "NETDEV %s link block expired\n", netdev->name );
238
+}
239
+
193
 /**
240
 /**
194
  * Record network device statistic
241
  * Record network device statistic
195
  *
242
  *
545
 static void free_netdev ( struct refcnt *refcnt ) {
592
 static void free_netdev ( struct refcnt *refcnt ) {
546
 	struct net_device *netdev =
593
 	struct net_device *netdev =
547
 		container_of ( refcnt, struct net_device, refcnt );
594
 		container_of ( refcnt, struct net_device, refcnt );
548
-	
595
+
596
+	stop_timer ( &netdev->link_block );
549
 	netdev_tx_flush ( netdev );
597
 	netdev_tx_flush ( netdev );
550
 	netdev_rx_flush ( netdev );
598
 	netdev_rx_flush ( netdev );
551
 	clear_settings ( netdev_settings ( netdev ) );
599
 	clear_settings ( netdev_settings ( netdev ) );
575
 	if ( netdev ) {
623
 	if ( netdev ) {
576
 		ref_init ( &netdev->refcnt, free_netdev );
624
 		ref_init ( &netdev->refcnt, free_netdev );
577
 		netdev->link_rc = -EUNKNOWN_LINK_STATUS;
625
 		netdev->link_rc = -EUNKNOWN_LINK_STATUS;
626
+		timer_init ( &netdev->link_block, netdev_link_block_expired,
627
+			     &netdev->refcnt );
578
 		INIT_LIST_HEAD ( &netdev->tx_queue );
628
 		INIT_LIST_HEAD ( &netdev->tx_queue );
579
 		INIT_LIST_HEAD ( &netdev->tx_deferred );
629
 		INIT_LIST_HEAD ( &netdev->tx_deferred );
580
 		INIT_LIST_HEAD ( &netdev->rx_queue );
630
 		INIT_LIST_HEAD ( &netdev->rx_queue );

+ 2
- 1
src/usr/ifmgmt.c View File

103
  */
103
  */
104
 void ifstat ( struct net_device *netdev ) {
104
 void ifstat ( struct net_device *netdev ) {
105
 	printf ( "%s: %s using %s on %s (%s)\n"
105
 	printf ( "%s: %s using %s on %s (%s)\n"
106
-		 "  [Link:%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
106
+		 "  [Link:%s%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
107
 		 netdev->name, netdev_addr ( netdev ),
107
 		 netdev->name, netdev_addr ( netdev ),
108
 		 netdev->dev->driver_name, netdev->dev->name,
108
 		 netdev->dev->driver_name, netdev->dev->name,
109
 		 ( netdev_is_open ( netdev ) ? "open" : "closed" ),
109
 		 ( netdev_is_open ( netdev ) ? "open" : "closed" ),
110
 		 ( netdev_link_ok ( netdev ) ? "up" : "down" ),
110
 		 ( netdev_link_ok ( netdev ) ? "up" : "down" ),
111
+		 ( netdev_link_blocked ( netdev ) ? " (blocked)" : "" ),
111
 		 netdev->tx_stats.good, netdev->tx_stats.bad,
112
 		 netdev->tx_stats.good, netdev->tx_stats.bad,
112
 		 netdev->rx_stats.good, netdev->rx_stats.bad );
113
 		 netdev->rx_stats.good, netdev->rx_stats.bad );
113
 	if ( ! netdev_link_ok ( netdev ) ) {
114
 	if ( ! netdev_link_ok ( netdev ) ) {

Loading…
Cancel
Save