Home | History | Annotate | Download | only in core
      1 /* Copyright 2004 Linux Networx */
      2 #ifdef PROTO_LACP
      3 #if 0
      4 #include "nic.h"
      5 #include "timer.h"
      6 #endif
      7 
      8 #define LACP_DEBUG 0
      9 
     10 /* Structure definitions originally taken from the linux bond_3ad driver */
     11 
     12 #define SLOW_DST_MAC "\x01\x80\xc2\x00\x00\x02"
     13 static const char slow_dest[] = SLOW_DST_MAC;
     14 
     15 
     16 #define SLOW_SUBTYPE_LACP 1
     17 #define SLOW_SUBTYPE_MARKER 2
     18 
     19 struct slow_header {
     20 	uint8_t subtype;
     21 };
     22 
     23 struct lacp_info {
     24 	uint16_t system_priority;
     25 	uint8_t  system[ETH_ALEN];
     26 	uint16_t key;
     27 	uint16_t port_priority;
     28 	uint16_t port;
     29 	uint8_t  state;
     30 	uint8_t  reserved[3];
     31 } PACKED;
     32 
     33 #define LACP_CMP_LEN (2 + 6 + 2 + 2 + 2)
     34 #define LACP_CP_LEN  (2 + 6 + 2 + 2 + 2 + 1)
     35 
     36 /* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
     37 struct slow_lacp {
     38 	uint8_t  subtype;		       /* = LACP(= 0x01) */
     39 	uint8_t  version_number;
     40 	uint8_t  tlv_type_actor_info;	       /* = actor information(type/length/value) */
     41 #define LACP_TLV_TERMINATOR 0
     42 #define LACP_TLV_ACTOR      1
     43 #define LACP_TLV_PARTNER    2
     44 #define LACP_TLV_COLLECTOR  3
     45 	uint8_t  actor_information_length;     /* = 20 */
     46 	struct lacp_info actor;
     47 	uint8_t  tlv_type_partner_info;        /* = partner information */
     48 	uint8_t  partner_information_length;   /* = 20 */
     49 	struct lacp_info partner;
     50 	uint8_t  tlv_type_collector_info;      /* = collector information */
     51 	uint8_t  collector_information_length; /* = 16 */
     52 	uint16_t collector_max_delay;
     53 	uint8_t  reserved_12[12];
     54 	uint8_t  tlv_type_terminator;	       /* = terminator */
     55 	uint8_t  terminator_length;	       /* = 0 */
     56 	uint8_t  reserved_50[50];	       /* = 0 */
     57 } PACKED;
     58 
     59 /* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
     60 struct slow_marker {
     61 	uint8_t  subtype;                      /* = 0x02  (marker PDU) */
     62 	uint8_t  version_number;	       /* = 0x01 */
     63 	uint8_t  tlv_type;
     64 #define MARKER_TLV_TERMINATOR 0                /* marker terminator */
     65 #define MARKER_TLV_INFO       1	               /* marker information */
     66 #define MARKER_TLV_RESPONSE   2	               /* marker response information */
     67 	uint8_t  marker_length;                /* = 0x16 */
     68 	uint16_t requester_port;	       /* The number assigned to the port by the requester */
     69 	uint8_t  requester_system[ETH_ALEN];   /* The requester's system id */
     70 	uint32_t requester_transaction_id;     /* The transaction id allocated by the requester, */
     71 	uint16_t pad;		               /* = 0 */
     72 	uint8_t  tlv_type_terminator;	       /* = 0x00 */
     73 	uint8_t  terminator_length;	       /* = 0x00 */
     74 	uint8_t  reserved_90[90];	       /* = 0 */
     75 } PACKED;
     76 
     77 union slow_union {
     78 	struct slow_header header;
     79 	struct slow_lacp lacp;
     80 	struct slow_marker marker;
     81 };
     82 
     83 #define FAST_PERIODIC_TIME   (1*TICKS_PER_SEC)
     84 #define SLOW_PERIODIC_TIME   (30*TICKS_PER_SEC)
     85 #define SHORT_TIMEOUT_TIME   (3*FAST_PERIODIC_TIME)
     86 #define LONG_TIMEOUT_TIME    (3*SLOW_PERIODIC_TIME)
     87 #define CHURN_DETECTION_TIME (60*TICKS_PER_SEC)
     88 #define AGGREGATE_WAIT_TIME  (2*TICKS_PER_SEC)
     89 
     90 #define LACP_ACTIVITY        (1 << 0)
     91 #define LACP_TIMEOUT         (1 << 1)
     92 #define LACP_AGGREGATION     (1 << 2)
     93 #define LACP_SYNCHRONIZATION (1 << 3)
     94 #define LACP_COLLECTING      (1 << 4)
     95 #define LACP_DISTRIBUTING    (1 << 5)
     96 #define LACP_DEFAULTED       (1 << 6)
     97 #define LACP_EXPIRED         (1 << 7)
     98 
     99 #define UNSELECTED 0
    100 #define STANDBY    1
    101 #define SELECTED   2
    102 
    103 
    104 struct lacp_state {
    105 	struct slow_lacp pkt;
    106 	unsigned long current_while_timer; /* Time when the LACP information expires */
    107 	unsigned long periodic_timer; /* Time when I need to send my partner an update */
    108 };
    109 
    110 static struct lacp_state lacp;
    111 
    112 
    113 #if LACP_DEBUG > 0
    114 static void print_lacp_state(uint8_t state)
    115 {
    116 	printf("%hhx", state);
    117 	if (state & LACP_ACTIVITY) {
    118 		printf(" Activity");
    119 	}
    120 	if (state & LACP_TIMEOUT) {
    121 		printf(" Timeout");
    122 	}
    123 	if (state & LACP_AGGREGATION) {
    124 		printf(" Aggregation");
    125 	}
    126 	if (state & LACP_SYNCHRONIZATION) {
    127 		printf(" Syncronization");
    128 	}
    129 	if (state & LACP_COLLECTING) {
    130 		printf(" Collecting");
    131 	}
    132 	if (state & LACP_DISTRIBUTING) {
    133 		printf(" Distributing");
    134 	}
    135 	if (state & LACP_DEFAULTED) {
    136 		printf(" Defaulted");
    137 	}
    138 	if (state & LACP_EXPIRED) {
    139 		printf(" Expired");
    140 	}
    141 	printf("\n");
    142 }
    143 
    144 static inline void print_lacpdu(struct slow_lacp *pkt)
    145 {
    146 	printf("subtype version:  %hhx %hhx\n",
    147 		pkt->subtype, pkt->version_number);
    148 	printf("actor_tlv %hhx", pkt->tlv_type_actor_info);
    149 	printf(" len: %hhx (\n", pkt->actor_information_length);
    150 	printf(" sys_pri: %hx", ntohs(pkt->actor.system_priority));
    151 	printf(" mac: %!", pkt->actor.system);
    152 	printf(" key: %hx", ntohs(pkt->actor.key));
    153 	printf(" port_pri: %hx", ntohs(pkt->actor.port_priority));
    154 	printf(" port: %hx\n", ntohs(pkt->actor.port));
    155 	printf(" state: ");
    156 	print_lacp_state(pkt->actor.state);
    157 #if LACP_DEBUG > 1
    158 	printf(" reserved:     %hhx %hhx %hhx\n",
    159 		pkt->actor.reserved[0], pkt->actor.reserved[1], pkt->actor.reserved[2]);
    160 #endif
    161 	printf(")\n");
    162 	printf("partner_tlv: %hhx", pkt->tlv_type_partner_info);
    163 	printf(" len: %hhx (\n", pkt->partner_information_length);
    164 	printf(" sys_pri: %hx", ntohs(pkt->partner.system_priority));
    165 	printf(" mac: %!", pkt->partner.system);
    166 	printf(" key: %hx", ntohs(pkt->partner.key));
    167 	printf(" port_pri: %hx", ntohs(pkt->partner.port_priority));
    168 	printf(" port: %hx\n", ntohs(pkt->partner.port));
    169 	printf(" state: ");
    170 	print_lacp_state(pkt->partner.state);
    171 #if LACP_DEBUG > 1
    172 	printf(" reserved:     %hhx %hhx %hhx\n",
    173 		pkt->partner.reserved[0], pkt->partner.reserved[1], pkt->partner.reserved[2]);
    174 #endif
    175 	printf(")\n");
    176 	printf("collector_tlv: %hhx ", pkt->tlv_type_collector_info);
    177 	printf(" len: %hhx (", pkt->collector_information_length);
    178 	printf(" max_delay: %hx", ntohs(pkt->collector_max_delay));
    179 #if LACP_DEBUG > 1
    180 	printf("reserved_12:      %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
    181 		pkt->reserved_12[0], pkt->reserved_12[1], pkt->reserved_12[2],
    182 		pkt->reserved_12[3], pkt->reserved_12[4], pkt->reserved_12[5],
    183 		pkt->reserved_12[6], pkt->reserved_12[7], pkt->reserved_12[8],
    184 		pkt->reserved_12[9], pkt->reserved_12[10], pkt->reserved_12[11]);
    185 #endif
    186 	printf(" )\n");
    187 	printf("terminator_tlv: %hhx", pkt->tlv_type_terminator);
    188 	printf(" len: %hhx ()\n", pkt->terminator_length);
    189 }
    190 
    191 static inline unsigned long lacp_timer_val(unsigned long now, unsigned long when)
    192 {
    193 	return when?(when - now)/TICKS_PER_SEC : 0;
    194 }
    195 static void print_lacp(const char *which, struct slow_lacp *pkt, unsigned long now)
    196 {
    197 	printf("%s\n", which);
    198 	print_lacpdu(pkt);
    199 	printf("timers: c %ds p %ds\n",
    200 		lacp_timer_val(now, lacp.current_while_timer),
    201 		lacp_timer_val(now, lacp.periodic_timer)
    202 		);
    203 	printf("\n");
    204 }
    205 #else /* LACP_DEBUG */
    206 #define print_lacp(which, pkt, now) do {} while(0)
    207 #endif /* LACP_DEBUG */
    208 
    209 static void lacp_init_state(const uint8_t *mac)
    210 {
    211 	memset(&lacp, 0, sizeof(lacp));
    212 
    213 	/* Initialize the packet constants */
    214 	lacp.pkt.subtype               = 1;
    215 	lacp.pkt.version_number        = 1;
    216 
    217 
    218 	/* The default state of my interface */
    219 	lacp.pkt.tlv_type_actor_info      = LACP_TLV_ACTOR;
    220 	lacp.pkt.actor_information_length = 0x14;
    221 	lacp.pkt.actor.system_priority    = htons(1);
    222 	memcpy(lacp.pkt.actor.system, mac, ETH_ALEN);
    223 	lacp.pkt.actor.key                = htons(1);
    224 	lacp.pkt.actor.port               = htons(1);
    225 	lacp.pkt.actor.port_priority      = htons(1);
    226 	lacp.pkt.actor.state =
    227 		LACP_SYNCHRONIZATION |
    228 		LACP_COLLECTING      |
    229 		LACP_DISTRIBUTING    |
    230 		LACP_DEFAULTED;
    231 
    232 	/* Set my partner defaults */
    233 	lacp.pkt.tlv_type_partner_info      = LACP_TLV_PARTNER;
    234 	lacp.pkt.partner_information_length = 0x14;
    235 	lacp.pkt.partner.system_priority    = htons(1);
    236 	/* memset(lacp.pkt.parnter_system, 0, ETH_ALEN); */
    237 	lacp.pkt.partner.key                = htons(1);
    238 	lacp.pkt.partner.port               = htons(1);
    239 	lacp.pkt.partner.port_priority      = htons(1);
    240 	lacp.pkt.partner.state =
    241 		LACP_ACTIVITY        |
    242 		LACP_SYNCHRONIZATION |
    243 		LACP_COLLECTING      |
    244 		LACP_DISTRIBUTING    |
    245 		LACP_DEFAULTED;
    246 
    247 	lacp.pkt.tlv_type_collector_info      = LACP_TLV_COLLECTOR;
    248 	lacp.pkt.collector_information_length = 0x10;
    249 	lacp.pkt.collector_max_delay          = htons(0x8000); /* ???? */
    250 
    251 	lacp.pkt.tlv_type_terminator          = LACP_TLV_TERMINATOR;
    252 	lacp.pkt.terminator_length            = 0;
    253 }
    254 
    255 #define LACP_NTT_MASK (LACP_ACTIVITY | LACP_TIMEOUT | \
    256 	LACP_SYNCHRONIZATION | LACP_AGGREGATION)
    257 
    258 static inline int lacp_update_ntt(struct slow_lacp *pkt)
    259 {
    260 	int ntt = 0;
    261 	if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) != 0) ||
    262 		((pkt->partner.state & LACP_NTT_MASK) !=
    263 			(lacp.pkt.actor.state & LACP_NTT_MASK)))
    264 	{
    265 		ntt = 1;
    266 	}
    267 	return ntt;
    268 }
    269 
    270 static inline void lacp_record_pdu(struct slow_lacp *pkt)
    271 {
    272 	memcpy(&lacp.pkt.partner, &pkt->actor, LACP_CP_LEN);
    273 
    274 	lacp.pkt.actor.state &= ~LACP_DEFAULTED;
    275 	lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
    276 	if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) == 0) &&
    277 		((pkt->partner.state & LACP_AGGREGATION) ==
    278 			(lacp.pkt.actor.state & LACP_AGGREGATION)))
    279 	{
    280 		lacp.pkt.partner.state  |= LACP_SYNCHRONIZATION;
    281 	}
    282 	if (!(pkt->actor.state & LACP_AGGREGATION)) {
    283 		lacp.pkt.partner.state |= LACP_SYNCHRONIZATION;
    284 	}
    285 
    286 	/* ACTIVITY? */
    287 }
    288 
    289 static inline int lacp_timer_expired(unsigned long now, unsigned long when)
    290 {
    291 	return when && (now > when);
    292 }
    293 
    294 static inline void lacp_start_periodic_timer(unsigned long now)
    295 {
    296 	if ((lacp.pkt.partner.state & LACP_ACTIVITY) ||
    297 		(lacp.pkt.actor.state & LACP_ACTIVITY)) {
    298 		lacp.periodic_timer = now +
    299 			(((lacp.pkt.partner.state & LACP_TIMEOUT)?
    300 				FAST_PERIODIC_TIME : SLOW_PERIODIC_TIME));
    301 	}
    302 }
    303 
    304 static inline void lacp_start_current_while_timer(unsigned long now)
    305 {
    306 	lacp.current_while_timer = now +
    307 		((lacp.pkt.actor.state & LACP_TIMEOUT) ?
    308 		SHORT_TIMEOUT_TIME : LONG_TIMEOUT_TIME);
    309 
    310 	lacp.pkt.actor.state &= ~LACP_EXPIRED;
    311 }
    312 
    313 static void send_lacp_reports(unsigned long now, int ntt)
    314 {
    315 	if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
    316 		lacp_init_state(nic.node_addr);
    317 	}
    318 	/* If the remote information has expired I need to take action */
    319 	if (lacp_timer_expired(now, lacp.current_while_timer)) {
    320 		if (!(lacp.pkt.actor.state & LACP_EXPIRED)) {
    321 			lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
    322 			lacp.pkt.partner.state |= LACP_TIMEOUT;
    323 			lacp.pkt.actor.state |= LACP_EXPIRED;
    324 			lacp.current_while_timer = now + SHORT_TIMEOUT_TIME;
    325 			ntt = 1;
    326 		}
    327 		else {
    328 			lacp_init_state(nic.node_addr);
    329 		}
    330 	}
    331 	/* If the periodic timer has expired I need to transmit */
    332 	if (lacp_timer_expired(now, lacp.periodic_timer)) {
    333 		ntt = 1;
    334 		/* Reset by lacp_start_periodic_timer */
    335 	}
    336 	if (ntt) {
    337 		eth_transmit(slow_dest, ETH_P_SLOW, sizeof(lacp.pkt), &lacp.pkt);
    338 
    339 		/* Restart the periodic timer */
    340 		lacp_start_periodic_timer(now);
    341 
    342 		print_lacp("Trasmitted", &lacp.pkt, now);
    343 	}
    344 }
    345 
    346 static inline void send_eth_slow_reports(unsigned long now)
    347 {
    348 	send_lacp_reports(now, 0);
    349 }
    350 
    351 static inline void process_eth_slow(unsigned short ptype, unsigned long now)
    352 {
    353 	union slow_union *pkt;
    354 	if ((ptype != ETH_P_SLOW) ||
    355 		(nic.packetlen < (ETH_HLEN + sizeof(pkt->header)))) {
    356 		return;
    357 	}
    358 	pkt = (union slow_union *)&nic.packet[ETH_HLEN];
    359 	if ((pkt->header.subtype == SLOW_SUBTYPE_LACP) &&
    360 		(nic.packetlen >= ETH_HLEN + sizeof(pkt->lacp))) {
    361 		int ntt;
    362 		if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
    363 			lacp_init_state(nic.node_addr);
    364 		}
    365 		/* As long as nic.packet is 2 byte aligned all is good */
    366 		print_lacp("Received", &pkt->lacp, now);
    367 		/* I don't actually implement the MUX or SELECT
    368 		 * machines.
    369 		 *
    370 		 * What logically happens when the client and I
    371 		 * disagree about an aggregator is the current
    372 		 * aggregtator is unselected.  The MUX machine places
    373 		 * me in DETACHED.  The SELECT machine runs and
    374 		 * reslects the same aggregator.  If I go through
    375 		 * these steps fast enough an outside observer can not
    376 		 * notice this.
    377 		 *
    378 		 * Since the process will not generate any noticeable
    379 		 * effect it does not need an implmenetation.  This
    380 		 * keeps the code simple and the code and binary
    381 		 * size down.
    382 		 */
    383 		/* lacp_update_selected(&pkt->lacp); */
    384 		ntt = lacp_update_ntt(&pkt->lacp);
    385 		lacp_record_pdu(&pkt->lacp);
    386 		lacp_start_current_while_timer(now);
    387 		send_lacp_reports(now, ntt);
    388 	}
    389 	/* If we receive a marker information packet return it */
    390 	else if ((pkt->header.subtype == SLOW_SUBTYPE_MARKER) &&
    391 		(nic.packetlen >= ETH_HLEN + sizeof(pkt->marker)) &&
    392 		(pkt->marker.tlv_type == MARKER_TLV_INFO) &&
    393 		(pkt->marker.marker_length == 0x16))
    394 	{
    395 		pkt->marker.tlv_type = MARKER_TLV_RESPONSE;
    396 		eth_transmit(slow_dest, ETH_P_SLOW,
    397 			sizeof(pkt->marker), &pkt->marker);
    398 	}
    399 
    400  }
    401 #else
    402 
    403 #define send_eth_slow_reports(now)    do {} while(0)
    404 #define process_eth_slow(ptype, now)  do {} while(0)
    405 
    406 #endif
    407