*/
#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 */
#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>
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 ) );