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