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  /* If partner is not in sync, collecting, and distributing,
157  * then block the link until after the next expected LACP
158  * packet.
159  */
160  if ( ~lacp->actor.state & ( LACP_STATE_IN_SYNC |
163  DBGC ( netdev, "SLOW %s LACP partner is down\n", netdev->name );
164  interval = ( ( lacp->actor.state & LACP_STATE_FAST ) ?
165  ( ( LACP_INTERVAL_FAST + 1 ) * TICKS_PER_SEC ) :
166  ( ( LACP_INTERVAL_SLOW + 1 ) * TICKS_PER_SEC ) );
167  netdev_link_block ( netdev, interval );
168  } else {
169  if ( netdev_link_blocked ( netdev ) ) {
170  DBGC ( netdev, "SLOW %s LACP partner is up\n",
171  netdev->name );
172  }
174  }
175 
176  /* Build response */
177  memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) );
178  memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) );
179  memset ( &lacp->collector, 0, sizeof ( lacp->collector ) );
182  memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) );
185  memset ( &lacp->partner.reserved, 0,
186  sizeof ( lacp->partner.reserved ) );
187  memset ( &lacp->actor, 0, sizeof ( lacp->actor ) );
192  sizeof ( lacp->actor.system ) );
193  lacp->actor.key = htons ( 1 );
195  lacp->actor.port = htons ( 1 );
202 
203  /* Send response */
204  eth_slow_lacp_dump ( iobuf, netdev, "TX" );
205  return net_tx ( iobuf, netdev, &eth_slow_protocol, eth_slow_address,
206  netdev->ll_addr );
207 }
208 
209 /**
210  * Dump marker packet
211  *
212  * @v iobuf I/O buffer
213  * @v netdev Network device
214  * @v label "RX" or "TX"
215  */
216 static void eth_slow_marker_dump ( struct io_buffer *iobuf,
217  struct net_device *netdev,
218  const char *label ) {
219  union eth_slow_packet *eth_slow = iobuf->data;
220  struct eth_slow_marker *marker = &eth_slow->marker;
221 
222  DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n",
223  netdev->name, label,
225  ntohs ( marker->marker.port ),
226  eth_ntoa ( marker->marker.system ),
227  ntohl ( marker->marker.xact ) );
228  DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
229 }
230 
231 /**
232  * Process incoming marker packet
233  *
234  * @v iobuf I/O buffer
235  * @v netdev Network device
236  * @ret rc Return status code
237  */
238 static int eth_slow_marker_rx ( struct io_buffer *iobuf,
239  struct net_device *netdev ) {
240  union eth_slow_packet *eth_slow = iobuf->data;
241  struct eth_slow_marker *marker = &eth_slow->marker;
242 
243  eth_slow_marker_dump ( iobuf, netdev, "RX" );
244 
245  if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) {
246  /* Send marker response */
248  eth_slow_marker_dump ( iobuf, netdev, "TX" );
249  return net_tx ( iobuf, netdev, &eth_slow_protocol,
251  } else {
252  /* Discard all other marker packets */
253  free_iob ( iobuf );
254  return -EINVAL;
255  }
256 }
257 
258 /**
259  * Process incoming slow packet
260  *
261  * @v iobuf I/O buffer
262  * @v netdev Network device
263  * @v ll_dest Link-layer destination address
264  * @v ll_source Link-layer source address
265  * @v flags Packet flags
266  * @ret rc Return status code
267  */
268 static int eth_slow_rx ( struct io_buffer *iobuf,
269  struct net_device *netdev,
270  const void *ll_dest __unused,
271  const void *ll_source __unused,
272  unsigned int flags __unused ) {
273  union eth_slow_packet *eth_slow = iobuf->data;
274 
275  /* Sanity checks */
276  if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
277  free_iob ( iobuf );
278  return -EINVAL;
279  }
280 
281  /* Handle according to subtype */
282  switch ( eth_slow->header.subtype ) {
284  return eth_slow_lacp_rx ( iobuf, netdev );
286  return eth_slow_marker_rx ( iobuf, netdev );
287  default:
288  DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n",
289  netdev->name, eth_slow->header.subtype );
290  free_iob ( iobuf );
291  return -EINVAL;
292  }
293 }
294 
295 /** Slow protocol */
296 struct net_protocol eth_slow_protocol __net_protocol = {
297  .name = "Slow",
298  .net_proto = htons ( ETH_P_SLOW ),
299  .rx = eth_slow_rx,
300 };
#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:145
uint8_t type
Type.
Definition: ena.h:16
#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:641
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
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:203
Ethernet protocol.
static int eth_slow_marker_rx(struct io_buffer *iobuf, struct net_device *netdev)
Process incoming marker packet.
Definition: eth_slow.c:238
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:218
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:268
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
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:151
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:175
A network device.
Definition: netdevice.h:348
#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:358
#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:999
void * data
Start of data.
Definition: iobuf.h:44
static void eth_slow_marker_dump(struct io_buffer *iobuf, struct net_device *netdev, const char *label)
Dump marker packet.
Definition: eth_slow.c:216
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:381
#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
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:32
uint8_t flags
Flags.
Definition: ena.h:18