These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / 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 };