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