Browse Source

[lacp] Add simple LACP implementation

Some switch configurations will refuse to enable our port unless we
can speak LACP to inform the switch that we are alive.  Add a very
simple passive LACP implementation that is sufficient to convince at
least Linux's bonding driver (when tested using qemu attached to a tap
device enslaved to a bond device configured as "mode=802.3ad").

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
84996b7b09
5 changed files with 526 additions and 406 deletions
  1. 0
    406
      src/core/proto_eth_slow.c
  2. 1
    0
      src/include/ipxe/errfile.h
  3. 255
    0
      src/include/ipxe/eth_slow.h
  4. 267
    0
      src/net/eth_slow.c
  5. 3
    0
      src/net/ethernet.c

+ 0
- 406
src/core/proto_eth_slow.c View File

@@ -1,406 +0,0 @@
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 

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -171,6 +171,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
171 171
 #define ERRFILE_wpa_psk			( ERRFILE_NET | 0x00270000 )
172 172
 #define ERRFILE_wpa_tkip		( ERRFILE_NET | 0x00280000 )
173 173
 #define ERRFILE_wpa_ccmp		( ERRFILE_NET | 0x00290000 )
174
+#define ERRFILE_eth_slow		( ERRFILE_NET | 0x002a0000 )
174 175
 
175 176
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
176 177
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 255
- 0
src/include/ipxe/eth_slow.h View File

@@ -0,0 +1,255 @@
1
+#ifndef _IPXE_ETH_SLOW_H
2
+#define _IPXE_ETH_SLOW_H
3
+
4
+/** @file
5
+ *
6
+ * Ethernet slow protocols
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+/** Slow protocols header */
13
+struct eth_slow_header {
14
+	/** Slow protocols subtype */
15
+	uint8_t subtype;
16
+	/** Subtype version number */
17
+	uint8_t version;
18
+} __attribute__ (( packed ));
19
+
20
+/** LACP subtype */
21
+#define ETH_SLOW_SUBTYPE_LACP 1
22
+
23
+/** LACP version number */
24
+#define ETH_SLOW_LACP_VERSION 1
25
+
26
+/** Marker subtype */
27
+#define ETH_SLOW_SUBTYPE_MARKER 2
28
+
29
+/** Marker version number */
30
+#define ETH_SLOW_MARKER_VERSION 1
31
+
32
+/** TLV (type, length, value) header */
33
+struct eth_slow_tlv_header {
34
+	/** Type
35
+	 *
36
+	 * This is an ETH_SLOW_TLV_XXX constant.
37
+	 */
38
+	uint8_t type;
39
+	/** Length
40
+	 *
41
+	 * The length includes the TLV header (except for a TLV
42
+	 * terminator, which has a length of zero).
43
+	 */
44
+	uint8_t length;
45
+} __attribute__ (( packed ));
46
+
47
+/** Terminator type */
48
+#define ETH_SLOW_TLV_TERMINATOR 0
49
+
50
+/** Terminator length */
51
+#define ETH_SLOW_TLV_TERMINATOR_LEN 0
52
+
53
+/** LACP actor type */
54
+#define ETH_SLOW_TLV_LACP_ACTOR 1
55
+
56
+/** LACP actor length */
57
+#define ETH_SLOW_TLV_LACP_ACTOR_LEN \
58
+	( sizeof ( struct eth_slow_lacp_entity_tlv ) )
59
+
60
+/** LACP partner type */
61
+#define ETH_SLOW_TLV_LACP_PARTNER 2
62
+
63
+/** LACP partner length */
64
+#define ETH_SLOW_TLV_LACP_PARTNER_LEN \
65
+	( sizeof ( struct eth_slow_lacp_entity_tlv ) )
66
+
67
+/** LACP collector type */
68
+#define ETH_SLOW_TLV_LACP_COLLECTOR 3
69
+
70
+/** LACP collector length */
71
+#define ETH_SLOW_TLV_LACP_COLLECTOR_LEN \
72
+	( sizeof ( struct eth_slow_lacp_collector_tlv ) )
73
+
74
+/** Marker request type */
75
+#define ETH_SLOW_TLV_MARKER_REQUEST 1
76
+
77
+/** Marker request length */
78
+#define ETH_SLOW_TLV_MARKER_REQUEST_LEN \
79
+	( sizeof ( struct eth_slow_marker_tlv ) )
80
+
81
+/** Marker response type */
82
+#define ETH_SLOW_TLV_MARKER_RESPONSE 2
83
+
84
+/** Marker response length */
85
+#define ETH_SLOW_TLV_MARKER_RESPONSE_LEN \
86
+	( sizeof ( struct eth_slow_marker_tlv ) )
87
+
88
+/** Terminator TLV */
89
+struct eth_slow_terminator_tlv {
90
+	/** TLV header */
91
+	struct eth_slow_tlv_header tlv;
92
+} __attribute__ (( packed ));
93
+
94
+/** LACP entity (actor or partner) TLV */
95
+struct eth_slow_lacp_entity_tlv {
96
+	/** TLV header */
97
+	struct eth_slow_tlv_header tlv;
98
+	/** System priority
99
+	 *
100
+	 * Used to determine the order in which ports are selected for
101
+	 * aggregation.
102
+	 */
103
+	uint16_t system_priority;
104
+	/** System identifier
105
+	 *
106
+	 * Used to uniquely identify the system (i.e. the entity with
107
+	 * potentially multiple ports).
108
+	 */
109
+	uint8_t system[ETH_ALEN];
110
+	/** Key
111
+	 *
112
+	 * Used to uniquely identify a group of aggregatable ports
113
+	 * within a system.
114
+	 */
115
+	uint16_t key;
116
+	/** Port priority
117
+	 *
118
+	 * Used to determine the order in which ports are selected for
119
+	 * aggregation.
120
+	 */
121
+	uint16_t port_priority;
122
+	/** Port identifier
123
+	 *
124
+	 * Used to uniquely identify a port within a system.
125
+	 */
126
+	uint16_t port;
127
+	/** State
128
+	 *
129
+	 * This is the bitwise OR of zero or more LACP_STATE_XXX
130
+	 * constants.
131
+	 */
132
+	uint8_t state;
133
+	/** Reserved */
134
+	uint8_t reserved[3];
135
+} __attribute__ (( packed ));
136
+
137
+/** Maximum system priority */
138
+#define LACP_SYSTEM_PRIORITY_MAX 0xffff
139
+
140
+/** Maximum port priority */
141
+#define LACP_PORT_PRIORITY_MAX 0xff
142
+
143
+/** LACP entity is active
144
+ *
145
+ * Represented by the state character "A"/"a"
146
+ */
147
+#define LACP_STATE_ACTIVE 0x01
148
+
149
+/** LACP timeout is short
150
+ *
151
+ * Short timeout is one second, long timeout is 30s
152
+ *
153
+ * Represented by the state character "F"/"f"
154
+ */
155
+#define LACP_STATE_FAST 0x02
156
+
157
+/** LACP link is aggregateable
158
+ *
159
+ * Represented by the state characters "G"/"g"
160
+ */
161
+#define LACP_STATE_AGGREGATABLE 0x04
162
+
163
+/** LACP link is in synchronisation
164
+ *
165
+ * Represented by the state characters "S"/"s"
166
+ */
167
+#define LACP_STATE_IN_SYNC 0x08
168
+
169
+/** LACP link is collecting (receiving)
170
+ *
171
+ * Represented by the state characters "C"/"c"
172
+ */
173
+#define LACP_STATE_COLLECTING 0x10
174
+
175
+/** LACP link is distributing (transmitting)
176
+ *
177
+ * Represented by the state characters "D"/"d"
178
+ */
179
+#define LACP_STATE_DISTRIBUTING 0x20
180
+
181
+/** LACP entity is using defaulted partner information
182
+ *
183
+ * Represented by the state characters "L"/"l"
184
+ */
185
+#define LACP_STATE_DEFAULTED 0x40
186
+
187
+/** LACP entity receive state machine is in EXPIRED
188
+ *
189
+ * Represented by the state characters "X"/"x"
190
+ */
191
+#define LACP_STATE_EXPIRED 0x80
192
+
193
+/** LACP collector TLV */
194
+struct eth_slow_lacp_collector_tlv {
195
+	/** TLV header */
196
+	struct eth_slow_tlv_header tlv;
197
+	/** Maximum delay (in 10us increments) */
198
+	uint16_t max_delay;
199
+	/** Reserved */
200
+	uint8_t reserved[12];
201
+} __attribute__ (( packed ));
202
+
203
+/** Marker TLV */
204
+struct eth_slow_marker_tlv {
205
+	/** TLV header */
206
+	struct eth_slow_tlv_header tlv;
207
+	/** Requester port */
208
+	uint16_t port;
209
+	/** Requester system */
210
+	uint8_t system[ETH_ALEN];
211
+	/** Requester transaction ID */
212
+	uint32_t xact;
213
+	/** Padding */
214
+	uint16_t pad;
215
+} __attribute__ (( packed ));
216
+
217
+/** LACP packet */
218
+struct eth_slow_lacp {
219
+	/** Slow protocols header */
220
+	struct eth_slow_header header;
221
+	/** Actor information */
222
+	struct eth_slow_lacp_entity_tlv actor;
223
+	/** Partner information */
224
+	struct eth_slow_lacp_entity_tlv partner;
225
+	/** Collector information */
226
+	struct eth_slow_lacp_collector_tlv collector;
227
+	/** Terminator */
228
+	struct eth_slow_terminator_tlv terminator;
229
+	/** Reserved */
230
+	uint8_t reserved[50];
231
+} __attribute__ (( packed ));
232
+
233
+/** Marker packet */
234
+struct eth_slow_marker {
235
+	/** Slow protocols header */
236
+	struct eth_slow_header header;
237
+	/** Marker information */
238
+	struct eth_slow_marker_tlv marker;
239
+	/** Terminator */
240
+	struct eth_slow_terminator_tlv terminator;
241
+	/** Reserved */
242
+	uint8_t reserved[90];
243
+} __attribute__ (( packed ));
244
+
245
+/** Slow protocols packet */
246
+union eth_slow_packet {
247
+	/** Slow protocols header */
248
+	struct eth_slow_header header;
249
+	/** LACP packet */
250
+	struct eth_slow_lacp lacp;
251
+	/** Marker packet */
252
+	struct eth_slow_marker marker;
253
+} __attribute__ (( packed ));
254
+
255
+#endif /* _IPXE_ETH_SLOW_H */

+ 267
- 0
src/net/eth_slow.c View File

@@ -0,0 +1,267 @@
1
+/*
2
+ * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdlib.h>
22
+#include <string.h>
23
+#include <byteswap.h>
24
+#include <errno.h>
25
+#include <ipxe/iobuf.h>
26
+#include <ipxe/netdevice.h>
27
+#include <ipxe/if_ether.h>
28
+#include <ipxe/ethernet.h>
29
+#include <ipxe/eth_slow.h>
30
+
31
+/** @file
32
+ *
33
+ * Ethernet slow protocols
34
+ *
35
+ * We implement a very simple passive LACP entity, that pretends that
36
+ * each port is the only port on an individual system.  We avoid the
37
+ * need for timeout logic (and retaining local state about our
38
+ * partner) by requesting the same timeout period (1s or 30s) as our
39
+ * partner requests, and then simply responding to every packet the
40
+ * partner sends us.
41
+ */
42
+
43
+struct net_protocol eth_slow_protocol;
44
+
45
+/** Slow protocols multicast address */
46
+static const uint8_t eth_slow_address[ETH_ALEN] =
47
+	{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
48
+
49
+/**
50
+ * Name LACP TLV type
51
+ *
52
+ * @v type		LACP TLV type
53
+ * @ret name		Name of LACP TLV type
54
+ */
55
+static inline __attribute__ (( always_inline )) const char *
56
+eth_slow_lacp_tlv_name ( uint8_t type ) {
57
+	switch ( type ) {
58
+	case ETH_SLOW_TLV_TERMINATOR:		return "terminator";
59
+	case ETH_SLOW_TLV_LACP_ACTOR:		return "actor";
60
+	case ETH_SLOW_TLV_LACP_PARTNER:		return "partner";
61
+	case ETH_SLOW_TLV_LACP_COLLECTOR:	return "collector";
62
+	default:				return "<invalid>";
63
+	}
64
+}
65
+
66
+/**
67
+ * Name marker TLV type
68
+ *
69
+ * @v type		Marker TLV type
70
+ * @ret name		Name of marker TLV type
71
+ */
72
+static inline __attribute__ (( always_inline )) const char *
73
+eth_slow_marker_tlv_name ( uint8_t type ) {
74
+	switch ( type ) {
75
+	case ETH_SLOW_TLV_TERMINATOR:		return "terminator";
76
+	case ETH_SLOW_TLV_MARKER_REQUEST:	return "request";
77
+	case ETH_SLOW_TLV_MARKER_RESPONSE:	return "response";
78
+	default:				return "<invalid>";
79
+	}
80
+}
81
+
82
+/**
83
+ * Name LACP state
84
+ *
85
+ * @v state		LACP state
86
+ * @ret name		LACP state name
87
+ */
88
+static const char * eth_slow_lacp_state_name ( uint8_t state ) {
89
+	static char state_chars[] = "AFGSRTLX";
90
+	unsigned int i;
91
+
92
+	for ( i = 0 ; i < 8 ; i++ ) {
93
+		state_chars[i] |= 0x20;
94
+		if ( state & ( 1 << i ) )
95
+			state_chars[i] &= ~0x20;
96
+	}
97
+	return state_chars;
98
+}
99
+
100
+/**
101
+ * Dump LACP packet
102
+ *
103
+ * @v iobuf		I/O buffer
104
+ * @v netdev		Network device
105
+ * @v label		"RX" or "TX"
106
+ */
107
+static void eth_slow_lacp_dump ( struct io_buffer *iobuf,
108
+				 struct net_device *netdev,
109
+				 const char *label ) {
110
+	union eth_slow_packet *eth_slow = iobuf->data;
111
+	struct eth_slow_lacp *lacp = &eth_slow->lacp;
112
+
113
+	DBGC ( netdev,
114
+	       "SLOW %p %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
115
+	       netdev, label, ntohs ( lacp->actor.system_priority ),
116
+	       eth_ntoa ( lacp->actor.system ),
117
+	       ntohs ( lacp->actor.key ),
118
+	       ntohs ( lacp->actor.port_priority ),
119
+	       ntohs ( lacp->actor.port ),
120
+	       eth_slow_lacp_state_name ( lacp->actor.state ) );
121
+	DBGC ( netdev,
122
+	       "SLOW %p %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
123
+	       netdev, label, ntohs ( lacp->partner.system_priority ),
124
+	       eth_ntoa ( lacp->partner.system ),
125
+	       ntohs ( lacp->partner.key ),
126
+	       ntohs ( lacp->partner.port_priority ),
127
+	       ntohs ( lacp->partner.port ),
128
+	       eth_slow_lacp_state_name ( lacp->partner.state ) );
129
+	DBGC ( netdev, "SLOW %p %s LACP collector %04x (%d us)\n",
130
+	       netdev, label, ntohs ( lacp->collector.max_delay ),
131
+	       ( ntohs ( lacp->collector.max_delay ) * 10 ) );
132
+	DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) );
133
+}
134
+
135
+/**
136
+ * Process incoming LACP packet
137
+ *
138
+ * @v iobuf		I/O buffer
139
+ * @v netdev		Network device
140
+ * @ret rc		Return status code
141
+ */
142
+static int eth_slow_lacp_rx ( struct io_buffer *iobuf,
143
+			      struct net_device *netdev ) {
144
+	union eth_slow_packet *eth_slow = iobuf->data;
145
+	struct eth_slow_lacp *lacp = &eth_slow->lacp;
146
+
147
+	eth_slow_lacp_dump ( iobuf, netdev, "RX" );
148
+
149
+	/* Build response */
150
+	memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) );
151
+	memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) );
152
+	memset ( &lacp->collector, 0, sizeof ( lacp->collector ) );
153
+	lacp->collector.tlv.type = ETH_SLOW_TLV_LACP_COLLECTOR;
154
+	lacp->collector.tlv.length = ETH_SLOW_TLV_LACP_COLLECTOR_LEN;
155
+	memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) );
156
+	lacp->partner.tlv.type = ETH_SLOW_TLV_LACP_PARTNER;
157
+	lacp->partner.tlv.length = ETH_SLOW_TLV_LACP_PARTNER_LEN;
158
+	memset ( &lacp->partner.reserved, 0,
159
+		 sizeof ( lacp->partner.reserved ) );
160
+	memset ( &lacp->actor, 0, sizeof ( lacp->actor ) );
161
+	lacp->actor.tlv.type = ETH_SLOW_TLV_LACP_ACTOR;
162
+	lacp->actor.tlv.length = ETH_SLOW_TLV_LACP_ACTOR_LEN;
163
+	lacp->actor.system_priority = htons ( LACP_SYSTEM_PRIORITY_MAX );
164
+	memcpy ( lacp->actor.system, netdev->ll_addr,
165
+		 sizeof ( lacp->actor.system ) );
166
+	lacp->actor.key = htons ( 1 );
167
+	lacp->actor.port_priority = htons ( LACP_PORT_PRIORITY_MAX );
168
+	lacp->actor.port = htons ( 1 );
169
+	lacp->actor.state = ( LACP_STATE_IN_SYNC |
170
+			      LACP_STATE_COLLECTING |
171
+			      LACP_STATE_DISTRIBUTING |
172
+			      ( lacp->partner.state & LACP_STATE_FAST ) );
173
+	lacp->header.version = ETH_SLOW_LACP_VERSION;
174
+
175
+	/* Send response */
176
+	eth_slow_lacp_dump ( iobuf, netdev, "TX" );
177
+	return net_tx ( iobuf, netdev, &eth_slow_protocol, eth_slow_address );
178
+}
179
+
180
+/**
181
+ * Dump marker packet
182
+ *
183
+ * @v iobuf		I/O buffer
184
+ * @v netdev		Network device
185
+ * @v label		"RX" or "TX"
186
+ */
187
+static void eth_slow_marker_dump ( struct io_buffer *iobuf,
188
+				   struct net_device *netdev,
189
+				   const char *label ) {
190
+	union eth_slow_packet *eth_slow = iobuf->data;
191
+	struct eth_slow_marker *marker = &eth_slow->marker;
192
+
193
+	DBGC ( netdev, "SLOW %p %s marker %s port %04x system %s xact %08x\n",
194
+	       netdev, label,
195
+	       eth_slow_marker_tlv_name ( marker->marker.tlv.type ),
196
+	       ntohs ( marker->marker.port ),
197
+	       eth_ntoa ( marker->marker.system ),
198
+	       ntohl ( marker->marker.xact ) );
199
+	DBGC2_HDA ( netdev, 0, iobuf, iob_len ( iobuf ) );
200
+}
201
+
202
+/**
203
+ * Process incoming marker packet
204
+ *
205
+ * @v iobuf		I/O buffer
206
+ * @v netdev		Network device
207
+ * @ret rc		Return status code
208
+ */
209
+static int eth_slow_marker_rx ( struct io_buffer *iobuf,
210
+				struct net_device *netdev ) {
211
+	union eth_slow_packet *eth_slow = iobuf->data;
212
+	struct eth_slow_marker *marker = &eth_slow->marker;
213
+
214
+	eth_slow_marker_dump ( iobuf, netdev, "RX" );
215
+
216
+	if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) {
217
+		/* Send marker response */
218
+		marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE;
219
+		eth_slow_marker_dump ( iobuf, netdev, "TX" );
220
+		return net_tx ( iobuf, netdev, &eth_slow_protocol,
221
+				eth_slow_address );
222
+	} else {
223
+		/* Discard all other marker packets */
224
+		free_iob ( iobuf );
225
+		return -EINVAL;
226
+	}
227
+}
228
+
229
+/**
230
+ * Process incoming slow packet
231
+ *
232
+ * @v iobuf		I/O buffer
233
+ * @v netdev		Network device
234
+ * @v ll_source		Link-layer source address
235
+ * @ret rc		Return status code
236
+ */
237
+static int eth_slow_rx ( struct io_buffer *iobuf,
238
+			 struct net_device *netdev,
239
+			 const void *ll_source __unused ) {
240
+	union eth_slow_packet *eth_slow = iobuf->data;
241
+
242
+	/* Sanity checks */
243
+	if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
244
+		free_iob ( iobuf );
245
+		return -EINVAL;
246
+	}
247
+
248
+	/* Handle according to subtype */
249
+	switch ( eth_slow->header.subtype ) {
250
+	case ETH_SLOW_SUBTYPE_LACP:
251
+		return eth_slow_lacp_rx ( iobuf, netdev );
252
+	case ETH_SLOW_SUBTYPE_MARKER:
253
+		return eth_slow_marker_rx ( iobuf, netdev );
254
+	default:
255
+		DBGC ( netdev, "SLOW %p RX unknown subtype %02x\n",
256
+		       netdev, eth_slow->header.subtype );
257
+		free_iob ( iobuf );
258
+		return -EINVAL;
259
+	}
260
+}
261
+
262
+/** Slow protocol */
263
+struct net_protocol eth_slow_protocol __net_protocol = {
264
+	.name = "Slow",
265
+	.net_proto = htons ( ETH_P_SLOW ),
266
+	.rx = eth_slow_rx,
267
+};

+ 3
- 0
src/net/ethernet.c View File

@@ -191,3 +191,6 @@ struct net_device * alloc_etherdev ( size_t priv_size ) {
191 191
 	}
192 192
 	return netdev;
193 193
 }
194
+
195
+/* Drag in Ethernet slow protocols */
196
+REQUIRE_OBJECT ( eth_slow );

Loading…
Cancel
Save