summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/ipxe/eth_slow.h6
-rw-r--r--src/net/eth_slow.c22
2 files changed, 28 insertions, 0 deletions
diff --git a/src/include/ipxe/eth_slow.h b/src/include/ipxe/eth_slow.h
index f6d731b3..754ea6e1 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 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 ) );