176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Copyright 2004 Linux Networx */ 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef PROTO_LACP 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "nic.h" 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "timer.h" 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_DEBUG 0 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Structure definitions originally taken from the linux bond_3ad driver */ 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_DST_MAC "\x01\x80\xc2\x00\x00\x02" 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char slow_dest[] = SLOW_DST_MAC; 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_SUBTYPE_LACP 1 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_SUBTYPE_MARKER 2 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct slow_header { 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t subtype; 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct lacp_info { 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t system_priority; 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t system[ETH_ALEN]; 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t key; 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t port_priority; 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t port; 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t state; 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t reserved[3]; 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACKED; 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_CMP_LEN (2 + 6 + 2 + 2 + 2) 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_CP_LEN (2 + 6 + 2 + 2 + 2 + 1) 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */ 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct slow_lacp { 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t subtype; /* = LACP(= 0x01) */ 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t version_number; 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t tlv_type_actor_info; /* = actor information(type/length/value) */ 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_TERMINATOR 0 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_ACTOR 1 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_PARTNER 2 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_COLLECTOR 3 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t actor_information_length; /* = 20 */ 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct lacp_info actor; 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t tlv_type_partner_info; /* = partner information */ 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t partner_information_length; /* = 20 */ 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct lacp_info partner; 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t tlv_type_collector_info; /* = collector information */ 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t collector_information_length; /* = 16 */ 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t collector_max_delay; 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t reserved_12[12]; 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t tlv_type_terminator; /* = terminator */ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t terminator_length; /* = 0 */ 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t reserved_50[50]; /* = 0 */ 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACKED; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */ 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct slow_marker { 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t subtype; /* = 0x02 (marker PDU) */ 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t version_number; /* = 0x01 */ 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t tlv_type; 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARKER_TLV_TERMINATOR 0 /* marker terminator */ 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARKER_TLV_INFO 1 /* marker information */ 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARKER_TLV_RESPONSE 2 /* marker response information */ 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t marker_length; /* = 0x16 */ 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t requester_port; /* The number assigned to the port by the requester */ 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t requester_system[ETH_ALEN]; /* The requester's system id */ 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t requester_transaction_id; /* The transaction id allocated by the requester, */ 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t pad; /* = 0 */ 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t tlv_type_terminator; /* = 0x00 */ 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t terminator_length; /* = 0x00 */ 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t reserved_90[90]; /* = 0 */ 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACKED; 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanunion slow_union { 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct slow_header header; 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct slow_lacp lacp; 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct slow_marker marker; 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define FAST_PERIODIC_TIME (1*TICKS_PER_SEC) 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_PERIODIC_TIME (30*TICKS_PER_SEC) 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SHORT_TIMEOUT_TIME (3*FAST_PERIODIC_TIME) 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LONG_TIMEOUT_TIME (3*SLOW_PERIODIC_TIME) 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define CHURN_DETECTION_TIME (60*TICKS_PER_SEC) 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define AGGREGATE_WAIT_TIME (2*TICKS_PER_SEC) 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_ACTIVITY (1 << 0) 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TIMEOUT (1 << 1) 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_AGGREGATION (1 << 2) 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_SYNCHRONIZATION (1 << 3) 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_COLLECTING (1 << 4) 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_DISTRIBUTING (1 << 5) 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_DEFAULTED (1 << 6) 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_EXPIRED (1 << 7) 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UNSELECTED 0 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define STANDBY 1 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SELECTED 2 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct lacp_state { 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct slow_lacp pkt; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long current_while_timer; /* Time when the LACP information expires */ 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long periodic_timer; /* Time when I need to send my partner an update */ 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct lacp_state lacp; 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 0 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void print_lacp_state(uint8_t state) 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("%hhx", state); 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_ACTIVITY) { 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Activity"); 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_TIMEOUT) { 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Timeout"); 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_AGGREGATION) { 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Aggregation"); 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_SYNCHRONIZATION) { 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Syncronization"); 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_COLLECTING) { 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Collecting"); 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_DISTRIBUTING) { 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Distributing"); 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_DEFAULTED) { 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Defaulted"); 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (state & LACP_EXPIRED) { 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" Expired"); 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("\n"); 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void print_lacpdu(struct slow_lacp *pkt) 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("subtype version: %hhx %hhx\n", 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->subtype, pkt->version_number); 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("actor_tlv %hhx", pkt->tlv_type_actor_info); 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" len: %hhx (\n", pkt->actor_information_length); 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" sys_pri: %hx", ntohs(pkt->actor.system_priority)); 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" mac: %!", pkt->actor.system); 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" key: %hx", ntohs(pkt->actor.key)); 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" port_pri: %hx", ntohs(pkt->actor.port_priority)); 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" port: %hx\n", ntohs(pkt->actor.port)); 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" state: "); 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman print_lacp_state(pkt->actor.state); 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 1 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" reserved: %hhx %hhx %hhx\n", 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->actor.reserved[0], pkt->actor.reserved[1], pkt->actor.reserved[2]); 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(")\n"); 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("partner_tlv: %hhx", pkt->tlv_type_partner_info); 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" len: %hhx (\n", pkt->partner_information_length); 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" sys_pri: %hx", ntohs(pkt->partner.system_priority)); 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" mac: %!", pkt->partner.system); 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" key: %hx", ntohs(pkt->partner.key)); 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" port_pri: %hx", ntohs(pkt->partner.port_priority)); 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" port: %hx\n", ntohs(pkt->partner.port)); 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" state: "); 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman print_lacp_state(pkt->partner.state); 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 1 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" reserved: %hhx %hhx %hhx\n", 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->partner.reserved[0], pkt->partner.reserved[1], pkt->partner.reserved[2]); 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(")\n"); 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("collector_tlv: %hhx ", pkt->tlv_type_collector_info); 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" len: %hhx (", pkt->collector_information_length); 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" max_delay: %hx", ntohs(pkt->collector_max_delay)); 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 1 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("reserved_12: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->reserved_12[0], pkt->reserved_12[1], pkt->reserved_12[2], 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->reserved_12[3], pkt->reserved_12[4], pkt->reserved_12[5], 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->reserved_12[6], pkt->reserved_12[7], pkt->reserved_12[8], 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->reserved_12[9], pkt->reserved_12[10], pkt->reserved_12[11]); 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" )\n"); 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("terminator_tlv: %hhx", pkt->tlv_type_terminator); 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf(" len: %hhx ()\n", pkt->terminator_length); 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline unsigned long lacp_timer_val(unsigned long now, unsigned long when) 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return when?(when - now)/TICKS_PER_SEC : 0; 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void print_lacp(const char *which, struct slow_lacp *pkt, unsigned long now) 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("%s\n", which); 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman print_lacpdu(pkt); 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("timers: c %ds p %ds\n", 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_timer_val(now, lacp.current_while_timer), 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_timer_val(now, lacp.periodic_timer) 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ); 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("\n"); 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LACP_DEBUG */ 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define print_lacp(which, pkt, now) do {} while(0) 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LACP_DEBUG */ 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void lacp_init_state(const uint8_t *mac) 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(&lacp, 0, sizeof(lacp)); 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize the packet constants */ 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.subtype = 1; 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.version_number = 1; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* The default state of my interface */ 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.tlv_type_actor_info = LACP_TLV_ACTOR; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor_information_length = 0x14; 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.system_priority = htons(1); 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(lacp.pkt.actor.system, mac, ETH_ALEN); 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.key = htons(1); 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.port = htons(1); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.port_priority = htons(1); 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.state = 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_SYNCHRONIZATION | 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_COLLECTING | 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_DISTRIBUTING | 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_DEFAULTED; 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set my partner defaults */ 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.tlv_type_partner_info = LACP_TLV_PARTNER; 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner_information_length = 0x14; 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.system_priority = htons(1); 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* memset(lacp.pkt.parnter_system, 0, ETH_ALEN); */ 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.key = htons(1); 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.port = htons(1); 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.port_priority = htons(1); 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.state = 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_ACTIVITY | 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_SYNCHRONIZATION | 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_COLLECTING | 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_DISTRIBUTING | 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_DEFAULTED; 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.tlv_type_collector_info = LACP_TLV_COLLECTOR; 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.collector_information_length = 0x10; 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.collector_max_delay = htons(0x8000); /* ???? */ 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.tlv_type_terminator = LACP_TLV_TERMINATOR; 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.terminator_length = 0; 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_NTT_MASK (LACP_ACTIVITY | LACP_TIMEOUT | \ 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LACP_SYNCHRONIZATION | LACP_AGGREGATION) 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int lacp_update_ntt(struct slow_lacp *pkt) 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ntt = 0; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) != 0) || 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((pkt->partner.state & LACP_NTT_MASK) != 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (lacp.pkt.actor.state & LACP_NTT_MASK))) 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntt = 1; 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ntt; 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void lacp_record_pdu(struct slow_lacp *pkt) 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(&lacp.pkt.partner, &pkt->actor, LACP_CP_LEN); 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.state &= ~LACP_DEFAULTED; 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION; 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) == 0) && 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((pkt->partner.state & LACP_AGGREGATION) == 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (lacp.pkt.actor.state & LACP_AGGREGATION))) 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.state |= LACP_SYNCHRONIZATION; 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(pkt->actor.state & LACP_AGGREGATION)) { 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.state |= LACP_SYNCHRONIZATION; 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* ACTIVITY? */ 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int lacp_timer_expired(unsigned long now, unsigned long when) 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return when && (now > when); 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void lacp_start_periodic_timer(unsigned long now) 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((lacp.pkt.partner.state & LACP_ACTIVITY) || 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (lacp.pkt.actor.state & LACP_ACTIVITY)) { 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.periodic_timer = now + 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (((lacp.pkt.partner.state & LACP_TIMEOUT)? 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman FAST_PERIODIC_TIME : SLOW_PERIODIC_TIME)); 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void lacp_start_current_while_timer(unsigned long now) 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.current_while_timer = now + 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((lacp.pkt.actor.state & LACP_TIMEOUT) ? 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman SHORT_TIMEOUT_TIME : LONG_TIMEOUT_TIME); 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.state &= ~LACP_EXPIRED; 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void send_lacp_reports(unsigned long now, int ntt) 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) { 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_init_state(nic.node_addr); 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If the remote information has expired I need to take action */ 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lacp_timer_expired(now, lacp.current_while_timer)) { 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(lacp.pkt.actor.state & LACP_EXPIRED)) { 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION; 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.partner.state |= LACP_TIMEOUT; 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.pkt.actor.state |= LACP_EXPIRED; 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp.current_while_timer = now + SHORT_TIMEOUT_TIME; 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntt = 1; 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_init_state(nic.node_addr); 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If the periodic timer has expired I need to transmit */ 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lacp_timer_expired(now, lacp.periodic_timer)) { 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntt = 1; 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset by lacp_start_periodic_timer */ 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ntt) { 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eth_transmit(slow_dest, ETH_P_SLOW, sizeof(lacp.pkt), &lacp.pkt); 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Restart the periodic timer */ 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_start_periodic_timer(now); 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman print_lacp("Trasmitted", &lacp.pkt, now); 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void send_eth_slow_reports(unsigned long now) 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman send_lacp_reports(now, 0); 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void process_eth_slow(unsigned short ptype, unsigned long now) 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman union slow_union *pkt; 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((ptype != ETH_P_SLOW) || 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (nic.packetlen < (ETH_HLEN + sizeof(pkt->header)))) { 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt = (union slow_union *)&nic.packet[ETH_HLEN]; 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((pkt->header.subtype == SLOW_SUBTYPE_LACP) && 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (nic.packetlen >= ETH_HLEN + sizeof(pkt->lacp))) { 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ntt; 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) { 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_init_state(nic.node_addr); 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* As long as nic.packet is 2 byte aligned all is good */ 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman print_lacp("Received", &pkt->lacp, now); 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* I don't actually implement the MUX or SELECT 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * machines. 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * What logically happens when the client and I 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * disagree about an aggregator is the current 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * aggregtator is unselected. The MUX machine places 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * me in DETACHED. The SELECT machine runs and 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * reslects the same aggregator. If I go through 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * these steps fast enough an outside observer can not 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * notice this. 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Since the process will not generate any noticeable 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * effect it does not need an implmenetation. This 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * keeps the code simple and the code and binary 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * size down. 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* lacp_update_selected(&pkt->lacp); */ 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntt = lacp_update_ntt(&pkt->lacp); 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_record_pdu(&pkt->lacp); 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lacp_start_current_while_timer(now); 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman send_lacp_reports(now, ntt); 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If we receive a marker information packet return it */ 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if ((pkt->header.subtype == SLOW_SUBTYPE_MARKER) && 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (nic.packetlen >= ETH_HLEN + sizeof(pkt->marker)) && 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (pkt->marker.tlv_type == MARKER_TLV_INFO) && 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (pkt->marker.marker_length == 0x16)) 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pkt->marker.tlv_type = MARKER_TLV_RESPONSE; 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eth_transmit(slow_dest, ETH_P_SLOW, 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sizeof(pkt->marker), &pkt->marker); 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define send_eth_slow_reports(now) do {} while(0) 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define process_eth_slow(ptype, now) do {} while(0) 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 407