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