summaryrefslogtreecommitdiffstats
path: root/src/net/eth_slow.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/eth_slow.c')
-rw-r--r--src/net/eth_slow.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c
index 049c26cb..41ce79fe 100644
--- a/src/net/eth_slow.c
+++ b/src/net/eth_slow.c
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <byteswap.h>
#include <errno.h>
+#include <ipxe/timer.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include <ipxe/if_ether.h>
@@ -148,9 +149,30 @@ static int eth_slow_lacp_rx ( struct io_buffer *iobuf,
struct net_device *netdev ) {
union eth_slow_packet *eth_slow = iobuf->data;
struct eth_slow_lacp *lacp = &eth_slow->lacp;
+ unsigned int interval;
eth_slow_lacp_dump ( iobuf, netdev, "RX" );
+ /* If partner is not in sync, collecting, and distributing,
+ * then block the link until after the next expected LACP
+ * packet.
+ */
+ if ( ~lacp->partner.state & ( LACP_STATE_IN_SYNC |
+ LACP_STATE_COLLECTING |
+ LACP_STATE_DISTRIBUTING ) ) {
+ DBGC ( netdev, "SLOW %s LACP partner is down\n", netdev->name );
+ interval = ( ( lacp->partner.state & LACP_STATE_FAST ) ?
+ ( ( LACP_INTERVAL_FAST + 1 ) * TICKS_PER_SEC ) :
+ ( ( LACP_INTERVAL_SLOW + 1 ) * TICKS_PER_SEC ) );
+ netdev_link_block ( netdev, interval );
+ } else {
+ if ( netdev_link_blocked ( netdev ) ) {
+ DBGC ( netdev, "SLOW %s LACP partner is up\n",
+ netdev->name );
+ }
+ netdev_link_unblock ( netdev );
+ }
+
/* Build response */
memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) );
memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) );