iPXE
eth_slow.c
Go to the documentation of this file.
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 FILE_SECBOOT ( PERMITTED );
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <byteswap.h>
30 #include <errno.h>
31 #include <ipxe/timer.h>
32 #include <ipxe/iobuf.h>
33 #include <ipxe/netdevice.h>
34 #include <ipxe/if_ether.h>
35 #include <ipxe/ethernet.h>
36 #include <ipxe/eth_slow.h>
37 
38 /** @file
39  *
40  * Ethernet slow protocols
41  *
42  * We implement a very simple passive LACP entity, that pretends that
43  * each port is the only port on an individual system. We avoid the
44  * need for timeout logic (and retaining local state about our
45  * partner) by requesting the same timeout period (1s or 30s) as our
46  * partner requests, and then simply responding to every packet the
47  * partner sends us.
48  */
49 
50 struct net_protocol eth_slow_protocol __net_protocol;
51 
52 /** Slow protocols multicast address */
54  { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
55 
56 /**
57  * Name LACP TLV type
58  *
59  * @v type LACP TLV type
60  * @ret name Name of LACP TLV type
61  */
62 static inline __attribute__ (( always_inline )) const char *
64  switch ( type ) {
65  case ETH_SLOW_TLV_TERMINATOR: return "terminator";
66  case ETH_SLOW_TLV_LACP_ACTOR: return "actor";
67  case ETH_SLOW_TLV_LACP_PARTNER: return "partner";
68  case ETH_SLOW_TLV_LACP_COLLECTOR: return "collector";
69  default: return "<invalid>";
70  }
71 }
72 
73 /**
74  * Name marker TLV type
75  *
76  * @v type Marker TLV type
77  * @ret name Name of marker TLV type
78  */
79 static inline __attribute__ (( always_inline )) const char *
81  switch ( type ) {
82  case ETH_SLOW_TLV_TERMINATOR: return "terminator";
83  case ETH_SLOW_TLV_MARKER_REQUEST: return "request";
84  case ETH_SLOW_TLV_MARKER_RESPONSE: return "response";
85  default: return "<invalid>";
86  }
87 }
88 
89 /**
90  * Name LACP state
91  *
92  * @v state LACP state
93  * @ret name LACP state name
94  */
95 static const char * eth_slow_lacp_state_name ( uint8_t state ) {
96  static char state_chars[] = "AFGSCDLX";
97  unsigned int i;
98 
99  for ( i = 0 ; i < 8 ; i++ ) {
100  state_chars[i] |= 0x20;
101  if ( state & ( 1 << i ) )
102  state_chars[i] &= ~0x20;
103  }
104  return state_chars;
105 }
106 
107 /**
108  * Dump LACP packet
109  *
110  * @v iobuf I/O buffer
111  * @v netdev Network device
112  * @v label "RX" or "TX"
113  */
114 static void eth_slow_lacp_dump ( struct io_buffer *iobuf,
115  struct net_device *netdev,
116  const char *label ) {
117  union eth_slow_packet *eth_slow = iobuf->data;
118  struct eth_slow_lacp *lacp = &eth_slow->lacp;
119 
120  DBGC ( netdev,
121  "SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
123  eth_ntoa ( lacp->actor.system ),
124  ntohs ( lacp->actor.key ),
126  ntohs ( lacp->actor.port ),
128  DBGC ( netdev,
129  "SLOW %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
132  ntohs ( lacp->partner.key ),
134  ntohs ( lacp->partner.port ),
136  DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n",
138  ( ntohs ( lacp->collector.max_delay ) * 10 ) );
139  DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
140 }
141 
142 /**
143  * Process incoming LACP packet
144  *
145  * @v iobuf I/O buffer
146  * @v netdev Network device
147  * @ret rc Return status code
148  */
149 static int eth_slow_lacp_rx ( struct io_buffer *iobuf,
150  struct net_device *netdev ) {
151  union eth_slow_packet *eth_slow = iobuf->data;
152  struct eth_slow_lacp *lacp = &eth_slow->lacp;
153  unsigned int interval;
154 
155  eth_slow_lacp_dump ( iobuf, netdev, "RX" );
156 
157  /* Check for looped-back packets */
158  if ( memcmp ( lacp->actor.system, netdev->ll_addr,
159  sizeof ( lacp->actor.system ) ) == 0 ) {
160  DBGC ( netdev, "SLOW %s RX loopback detected\n",
161  netdev->name );
162  return -ELOOP;
163  }
164 
165  /* If partner is not in sync, collecting, and distributing,
166  * then block the link until after the next expected LACP
167  * packet.
168  */
169  if ( ~lacp->actor.state & ( LACP_STATE_IN_SYNC |
172  DBGC ( netdev, "SLOW %s LACP partner is down\n", netdev->name );
173  interval = ( ( lacp->actor.state & LACP_STATE_FAST ) ?
174  ( ( LACP_INTERVAL_FAST + 1 ) * TICKS_PER_SEC ) :
175  ( ( LACP_INTERVAL_SLOW + 1 ) * TICKS_PER_SEC ) );
176  netdev_link_block ( netdev, interval );
177  } else {
178  if ( netdev_link_blocked ( netdev ) ) {
179  DBGC ( netdev, "SLOW %s LACP partner is up\n",
180  netdev->name );
181  }
183  }
184 
185  /* Build response */
186  memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) );
187  memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) );
188  memset ( &lacp->collector, 0, sizeof ( lacp->collector ) );
191  memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) );
194  memset ( &lacp->partner.reserved, 0,
195  sizeof ( lacp->partner.reserved ) );
196  memset ( &lacp->actor, 0, sizeof ( lacp->actor ) );
201  sizeof ( lacp->actor.system ) );
202  lacp->actor.key = htons ( 1 );
204  lacp->actor.port = htons ( 1 );
211 
212  /* Send response */
213  eth_slow_lacp_dump ( iobuf, netdev, "TX" );
214  return net_tx ( iobuf, netdev, &eth_slow_protocol, eth_slow_address,
215  netdev->ll_addr );
216 }
217 
218 /**
219  * Dump marker packet
220  *
221  * @v iobuf I/O buffer
222  * @v netdev Network device
223  * @v label "RX" or "TX"
224  */
225 static void eth_slow_marker_dump ( struct io_buffer *iobuf,
226  struct net_device *netdev,
227  const char *label ) {
228  union eth_slow_packet *eth_slow = iobuf->data;
229  struct eth_slow_marker *marker = &eth_slow->marker;
230 
231  DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n",
232  netdev->name, label,
234  ntohs ( marker->marker.port ),
235  eth_ntoa ( marker->marker.system ),
236  ntohl ( marker->marker.xact ) );
237  DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
238 }
239 
240 /**
241  * Process incoming marker packet
242  *
243  * @v iobuf I/O buffer
244  * @v netdev Network device
245  * @ret rc Return status code
246  */
247 static int eth_slow_marker_rx ( struct io_buffer *iobuf,
248  struct net_device *netdev ) {
249  union eth_slow_packet *eth_slow = iobuf->data;
250  struct eth_slow_marker *marker = &eth_slow->marker;
251 
252  eth_slow_marker_dump ( iobuf, netdev, "RX" );
253 
254  if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) {
255  /* Send marker response */
257  eth_slow_marker_dump ( iobuf, netdev, "TX" );
258  return net_tx ( iobuf, netdev, &eth_slow_protocol,
260  } else {
261  /* Discard all other marker packets */
262  free_iob ( iobuf );
263  return -EINVAL;
264  }
265 }
266 
267 /**
268  * Process incoming slow packet
269  *
270  * @v iobuf I/O buffer
271  * @v netdev Network device
272  * @v ll_dest Link-layer destination address
273  * @v ll_source Link-layer source address
274  * @v flags Packet flags
275  * @ret rc Return status code
276  */
277 static int eth_slow_rx ( struct io_buffer *iobuf,
278  struct net_device *netdev,
279  const void *ll_dest __unused,
280  const void *ll_source __unused,
281  unsigned int flags __unused ) {
282  union eth_slow_packet *eth_slow = iobuf->data;
283 
284  /* Sanity checks */
285  if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
286  free_iob ( iobuf );
287  return -EINVAL;
288  }
289 
290  /* Strip any trailing padding */
291  iob_unput ( iobuf, ( sizeof ( *eth_slow ) - iob_len ( iobuf ) ) );
292 
293  /* Handle according to subtype */
294  switch ( eth_slow->header.subtype ) {
296  return eth_slow_lacp_rx ( iobuf, netdev );
298  return eth_slow_marker_rx ( iobuf, netdev );
299  default:
300  DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n",
301  netdev->name, eth_slow->header.subtype );
302  free_iob ( iobuf );
303  return -EINVAL;
304  }
305 }
306 
307 /** Slow protocol */
308 struct net_protocol eth_slow_protocol __net_protocol = {
309  .name = "Slow",
310  .net_proto = htons ( ETH_P_SLOW ),
311  .rx = eth_slow_rx,
312 };
#define __attribute__(x)
Definition: compiler.h:10
#define EINVAL
Invalid argument.
Definition: errno.h:429
const char * name
Protocol name.
Definition: netdevice.h:67
A text label widget.
Definition: label.h:16
#define TICKS_PER_SEC
Number of ticks per second.
Definition: timer.h:16
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
struct eth_slow_lacp lacp
LACP packet.
Definition: eth_slow.h:257
uint8_t reserved[3]
Reserved.
Definition: eth_slow.h:135
#define ETH_SLOW_LACP_VERSION
LACP version number.
Definition: eth_slow.h:25
uint8_t state
State.
Definition: eth_slow.h:48
static int eth_slow_lacp_rx(struct io_buffer *iobuf, struct net_device *netdev)
Process incoming LACP packet.
Definition: eth_slow.c:149
uint8_t system[ETH_ALEN]
Requester system.
Definition: eth_slow.h:217
Error codes.
struct eth_slow_terminator_tlv terminator
Terminator.
Definition: eth_slow.h:235
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
uint32_t type
Operating system type.
Definition: ena.h:12
#define ETH_SLOW_SUBTYPE_MARKER
Marker subtype.
Definition: eth_slow.h:28
static const uint8_t eth_slow_address[ETH_ALEN]
Slow protocols multicast address.
Definition: eth_slow.c:53
#define LACP_STATE_AGGREGATABLE
LACP link is aggregateable.
Definition: eth_slow.h:162
#define DBGC(...)
Definition: compiler.h:505
#define LACP_STATE_COLLECTING
LACP link is collecting (receiving)
Definition: eth_slow.h:174
#define LACP_STATE_IN_SYNC
LACP link is in synchronisation.
Definition: eth_slow.h:168
struct eth_slow_lacp lacp
LACP packet.
Definition: eth_slow.h:15
#define ETH_SLOW_TLV_MARKER_REQUEST
Marker request type.
Definition: eth_slow.h:76
Slow protocols packet.
Definition: eth_slow.h:253
#define ntohl(value)
Definition: byteswap.h:135
#define LACP_SYSTEM_PRIORITY_MAX
Maximum system priority.
Definition: eth_slow.h:139
struct eth_slow_tlv_header tlv
TLV header.
Definition: eth_slow.h:98
#define ETH_SLOW_TLV_LACP_COLLECTOR
LACP collector type.
Definition: eth_slow.h:69
iPXE timers
#define ntohs(value)
Definition: byteswap.h:137
static const char * eth_slow_lacp_tlv_name(uint8_t type)
Name LACP TLV type.
Definition: eth_slow.c:63
static int netdev_link_blocked(struct net_device *netdev)
Check link block state of network device.
Definition: netdevice.h:651
Marker packet.
Definition: eth_slow.h:241
struct eth_slow_lacp_collector_tlv collector
Collector information.
Definition: eth_slow.h:233
uint8_t state
State.
Definition: eth_slow.h:133
LACP packet.
Definition: eth_slow.h:225
#define ELOOP
Too many levels of symbolic links.
Definition: errno.h:449
struct eth_slow_header header
Slow protocols header.
Definition: eth_slow.h:255
#define ETH_SLOW_TLV_MARKER_RESPONSE
Marker response type.
Definition: eth_slow.h:83
struct eth_slow_tlv_header tlv
TLV header.
Definition: eth_slow.h:203
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint16_t max_delay
Maximum delay (in 10us increments)
Definition: eth_slow.h:205
FILE_SECBOOT(PERMITTED)
void netdev_link_block(struct net_device *netdev, unsigned long timeout)
Mark network device link as being blocked.
Definition: netdevice.c:248
Ethernet protocol.
static int eth_slow_marker_rx(struct io_buffer *iobuf, struct net_device *netdev)
Process incoming marker packet.
Definition: eth_slow.c:247
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
uint8_t system[ETH_ALEN]
System identifier.
Definition: eth_slow.h:110
void netdev_link_unblock(struct net_device *netdev)
Mark network device link as being unblocked.
Definition: netdevice.c:263
static struct net_device * netdev
Definition: gdbudp.c:52
uint16_t port
Requester port.
Definition: eth_slow.h:215
static const char * eth_slow_marker_tlv_name(uint8_t type)
Name marker TLV type.
Definition: eth_slow.c:80
#define ETH_P_SLOW
Definition: if_ether.h:24
static int eth_slow_rx(struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused)
Process incoming slow packet.
Definition: eth_slow.c:277
struct eth_slow_header header
Slow protocols header.
Definition: eth_slow.h:227
#define LACP_PORT_PRIORITY_MAX
Maximum port priority.
Definition: eth_slow.h:142
#define DBGC2_HDA(...)
Definition: compiler.h:523
#define LACP_STATE_FAST
LACP timeout is short.
Definition: eth_slow.h:156
#define iob_unput(iobuf, len)
Definition: iobuf.h:140
uint8_t flags
Flags.
Definition: ena.h:18
uint8_t length
Length.
Definition: eth_slow.h:45
#define ETH_SLOW_TLV_LACP_PARTNER
LACP partner type.
Definition: eth_slow.h:62
#define ETH_SLOW_TLV_LACP_ACTOR_LEN
LACP actor length.
Definition: eth_slow.h:58
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:176
A network device.
Definition: netdevice.h:353
#define ETH_SLOW_TLV_LACP_COLLECTOR_LEN
LACP collector length.
Definition: eth_slow.h:72
uint8_t subtype
Slow protocols subtype.
Definition: eth_slow.h:16
#define ETH_SLOW_TLV_LACP_PARTNER_LEN
LACP partner length.
Definition: eth_slow.h:65
unsigned char uint8_t
Definition: stdint.h:10
struct eth_slow_lacp_entity_tlv partner
Partner information.
Definition: eth_slow.h:231
#define ETH_ALEN
Definition: if_ether.h:9
#define LACP_INTERVAL_SLOW
LACP slow interval (30 seconds)
Definition: eth_slow.h:198
struct net_protocol eth_slow_protocol __net_protocol
Slow protocol.
Definition: eth_slow.c:50
A network-layer protocol.
Definition: netdevice.h:65
#define ETH_SLOW_TLV_TERMINATOR
Terminator type.
Definition: eth_slow.h:49
uint8_t reserved[50]
Reserved.
Definition: eth_slow.h:237
uint16_t system_priority
System priority.
Definition: eth_slow.h:104
Network device management.
uint32_t xact
Requester transaction ID.
Definition: eth_slow.h:219
uint8_t type
Type.
Definition: eth_slow.h:39
#define ETH_SLOW_SUBTYPE_LACP
LACP subtype.
Definition: eth_slow.h:22
struct eth_slow_marker marker
Marker packet.
Definition: eth_slow.h:259
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:363
#define ETH_SLOW_TLV_LACP_ACTOR
LACP actor type.
Definition: eth_slow.h:55
int net_tx(struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest, const void *ll_source)
Transmit network-layer packet.
Definition: netdevice.c:1074
void * data
Start of data.
Definition: iobuf.h:53
static void eth_slow_marker_dump(struct io_buffer *iobuf, struct net_device *netdev, const char *label)
Dump marker packet.
Definition: eth_slow.c:225
uint16_t port_priority
Port priority.
Definition: eth_slow.h:122
static const char * eth_slow_lacp_state_name(uint8_t state)
Name LACP state.
Definition: eth_slow.c:95
struct eth_slow_tlv_header tlv
TLV header.
Definition: eth_slow.h:213
struct eth_slow_lacp_entity_tlv actor
Actor information.
Definition: eth_slow.h:229
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:388
#define LACP_STATE_DISTRIBUTING
LACP link is distributing (transmitting)
Definition: eth_slow.h:180
#define LACP_INTERVAL_FAST
LACP fast interval (1 second)
Definition: eth_slow.h:195
Ethernet slow protocols.
uint16_t port
Port identifier.
Definition: eth_slow.h:127
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:115
String functions.
#define htons(value)
Definition: byteswap.h:136
struct eth_slow_marker_tlv marker
Marker information.
Definition: eth_slow.h:15
static void eth_slow_lacp_dump(struct io_buffer *iobuf, struct net_device *netdev, const char *label)
Dump LACP packet.
Definition: eth_slow.c:114
uint8_t version
Subtype version number.
Definition: eth_slow.h:18
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:38