diff --git a/src/include/ipxe/eth_slow.h b/src/include/ipxe/eth_slow.h index f6d731b3b..754ea6e1f 100644 --- a/src/include/ipxe/eth_slow.h +++ b/src/include/ipxe/eth_slow.h @@ -190,6 +190,12 @@ struct eth_slow_lacp_entity_tlv { */ #define LACP_STATE_EXPIRED 0x80 +/** LACP fast interval (1 second) */ +#define LACP_INTERVAL_FAST 1 + +/** LACP slow interval (30 seconds) */ +#define LACP_INTERVAL_SLOW 30 + /** LACP collector TLV */ struct eth_slow_lacp_collector_tlv { /** TLV header */ diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c index 049c26cb3..41ce79fe0 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 #include #include +#include #include #include #include @@ -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 = ð_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 ) );