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