1 /* Copyright 2004 Linux Networx */
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
25 uint16_t system_priority
;
26 uint8_t system
[ETH_ALEN
];
28 uint16_t port_priority
;
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) */
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 */
60 /* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
62 uint8_t subtype
; /* = 0x02 (marker PDU) */
63 uint8_t version_number
; /* = 0x01 */
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 */
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)
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
;
115 static void print_lacp_state(uint8_t state
)
117 printf("%hhx", state
);
118 if (state
& LACP_ACTIVITY
) {
121 if (state
& LACP_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
) {
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
));
157 print_lacp_state(pkt
->actor
.state
);
159 printf(" reserved: %hhx %hhx %hhx\n",
160 pkt
->actor
.reserved
[0], pkt
->actor
.reserved
[1], pkt
->actor
.reserved
[2]);
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
));
171 print_lacp_state(pkt
->partner
.state
);
173 printf(" reserved: %hhx %hhx %hhx\n",
174 pkt
->partner
.reserved
[0], pkt
->partner
.reserved
[1], pkt
->partner
.reserved
[2]);
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
));
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]);
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
);
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
)
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
|
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
=
243 LACP_SYNCHRONIZATION
|
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
)
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
)))
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
;
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
;
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
)) {
335 /* Reset by lacp_start_periodic_timer */
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
)))) {
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
))) {
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
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
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
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
);
404 #define send_eth_slow_reports(now) do {} while(0)
405 #define process_eth_slow(ptype, now) do {} while(0)