|
|
1.1 root 1: /*
2: * Copyright (C) 2010 Michael Brown <[email protected]>.
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 __net_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 = ð_slow->lacp;
112:
113: DBGC ( netdev,
114: "SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
115: netdev->name, 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 %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
123: netdev->name, 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 %s %s LACP collector %04x (%d us)\n",
130: netdev->name, label, ntohs ( lacp->collector.max_delay ),
131: ( ntohs ( lacp->collector.max_delay ) * 10 ) );
132: DBGC2_HDA ( netdev, 0, iobuf->data, 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 = ð_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, ð_slow_protocol, eth_slow_address,
178: netdev->ll_addr );
179: }
180:
181: /**
182: * Dump marker packet
183: *
184: * @v iobuf I/O buffer
185: * @v netdev Network device
186: * @v label "RX" or "TX"
187: */
188: static void eth_slow_marker_dump ( struct io_buffer *iobuf,
189: struct net_device *netdev,
190: const char *label ) {
191: union eth_slow_packet *eth_slow = iobuf->data;
192: struct eth_slow_marker *marker = ð_slow->marker;
193:
194: DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n",
195: netdev->name, label,
196: eth_slow_marker_tlv_name ( marker->marker.tlv.type ),
197: ntohs ( marker->marker.port ),
198: eth_ntoa ( marker->marker.system ),
199: ntohl ( marker->marker.xact ) );
200: DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
201: }
202:
203: /**
204: * Process incoming marker packet
205: *
206: * @v iobuf I/O buffer
207: * @v netdev Network device
208: * @ret rc Return status code
209: */
210: static int eth_slow_marker_rx ( struct io_buffer *iobuf,
211: struct net_device *netdev ) {
212: union eth_slow_packet *eth_slow = iobuf->data;
213: struct eth_slow_marker *marker = ð_slow->marker;
214:
215: eth_slow_marker_dump ( iobuf, netdev, "RX" );
216:
217: if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) {
218: /* Send marker response */
219: marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE;
220: eth_slow_marker_dump ( iobuf, netdev, "TX" );
221: return net_tx ( iobuf, netdev, ð_slow_protocol,
222: eth_slow_address, netdev->ll_addr );
223: } else {
224: /* Discard all other marker packets */
225: free_iob ( iobuf );
226: return -EINVAL;
227: }
228: }
229:
230: /**
231: * Process incoming slow packet
232: *
233: * @v iobuf I/O buffer
234: * @v netdev Network device
235: * @v ll_dest Link-layer destination address
236: * @v ll_source Link-layer source address
237: * @ret rc Return status code
238: */
239: static int eth_slow_rx ( struct io_buffer *iobuf,
240: struct net_device *netdev,
241: const void *ll_dest __unused,
242: const void *ll_source __unused ) {
243: union eth_slow_packet *eth_slow = iobuf->data;
244:
245: /* Sanity checks */
246: if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
247: free_iob ( iobuf );
248: return -EINVAL;
249: }
250:
251: /* Handle according to subtype */
252: switch ( eth_slow->header.subtype ) {
253: case ETH_SLOW_SUBTYPE_LACP:
254: return eth_slow_lacp_rx ( iobuf, netdev );
255: case ETH_SLOW_SUBTYPE_MARKER:
256: return eth_slow_marker_rx ( iobuf, netdev );
257: default:
258: DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n",
259: netdev->name, eth_slow->header.subtype );
260: free_iob ( iobuf );
261: return -EINVAL;
262: }
263: }
264:
265: /** Slow protocol */
266: struct net_protocol eth_slow_protocol __net_protocol = {
267: .name = "Slow",
268: .net_proto = htons ( ETH_P_SLOW ),
269: .rx = eth_slow_rx,
270: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.