FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
lacp.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <stdint.h>
17 #include <vlib/vlib.h>
18 #include <vlib/unix/unix.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vpp/app/version.h>
21 #include <vppinfra/hash.h>
22 #include <vnet/bonding/node.h>
23 #include <lacp/node.h>
24 #include <vpp/stats/stat_segment.h>
25 
27 
28 /*
29  * Generate lacp pdu
30  */
31 static void
32 lacp_fill_pdu (lacp_pdu_t * lacpdu, slave_if_t * sif)
33 {
34  /* Actor TLV */
35  lacpdu->actor.port_info = sif->actor;
36 
37  /* Partner TLV */
38  lacpdu->partner.port_info = sif->partner;
39 }
40 
41 /*
42  * send a lacp pkt on an ethernet interface
43  */
44 static void
46 {
47  lacp_main_t *lm = &lacp_main;
48  u32 *to_next;
49  ethernet_lacp_pdu_t *h0;
51  u32 bi0;
52  vlib_buffer_t *b0;
53  vlib_frame_t *f;
54  vlib_main_t *vm = lm->vlib_main;
55  vnet_main_t *vnm = lm->vnet_main;
56 
57  /*
58  * see lacp_periodic_init() to understand what's already painted
59  * into the buffer by the packet template mechanism
60  */
62  (vm, &lm->packet_templates[sif->packet_template_index], &bi0);
63 
64  if (!h0)
65  return;
66 
67  /* Add the interface's ethernet source address */
68  hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
69 
70  clib_memcpy (h0->ethernet.src_address, hw->hw_address,
71  vec_len (hw->hw_address));
72 
73  lacp_fill_pdu (&h0->lacp, sif);
74 
75  /* Set the outbound packet length */
76  b0 = vlib_get_buffer (vm, bi0);
77  b0->current_length = sizeof (ethernet_lacp_pdu_t);
78  b0->current_data = 0;
80 
81  /* And the outbound interface */
82  vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
83 
84  /* And output the packet on the correct interface */
86 
87  to_next = vlib_frame_vector_args (f);
88  to_next[0] = bi0;
89  f->n_vectors = 1;
90 
92 
94  sif->pdu_sent++;
95 }
96 
97 /*
98  * Decide which lacp packet template to use
99  */
100 static int
102 {
104 
105  return 0;
106 }
107 
108 void
110 {
111  if ((sif->mode != BOND_MODE_LACP) || (sif->port_enabled == 0))
112  {
114  return;
115  }
116 
117  if (sif->packet_template_index == (u8) ~ 0)
118  {
119  /* If we don't know how to talk to this peer, don't try again */
120  if (lacp_pick_packet_template (sif))
121  {
123  return;
124  }
125  }
126 
127  switch (sif->packet_template_index)
128  {
131  break;
132 
133  default:
134  ASSERT (0);
135  }
136 }
137 
138 void
140 {
141  bond_main_t *bm = &bond_main;
142  lacp_main_t *lm = &lacp_main;
143  slave_if_t *sif;
144  bond_if_t *bif;
145  u8 actor_state, partner_state;
146 
147  /* *INDENT-OFF* */
148  pool_foreach (sif, bm->neighbors,
149  ({
150  if (sif->port_enabled == 0)
151  continue;
152 
153  actor_state = sif->actor.state;
154  partner_state = sif->partner.state;
155  if (lacp_timer_is_running (sif->current_while_timer) &&
156  lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
157  {
158  lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
159  LACP_RX_EVENT_TIMER_EXPIRED, &sif->rx_state);
160  }
161 
164  {
165  lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
166  LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
167  }
170  {
171  sif->ready_n = 1;
172  lacp_stop_timer (&sif->wait_while_timer);
173  lacp_selection_logic (vm, sif);
174  }
175  if (actor_state != sif->actor.state)
176  {
177  bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
178  stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
179  [sif->sw_if_index].actor_state,
180  sif->actor.state);
181  }
182  if (partner_state != sif->partner.state)
183  {
184  bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
185  stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
186  [sif->sw_if_index].partner_state,
187  sif->partner.state);
188  }
189  }));
190  /* *INDENT-ON* */
191 }
192 
193 static void
195  slave_if_t * sif, u8 enable)
196 {
197  lacp_main_t *lm = &lacp_main;
198  uword port_number;
199 
200  if (enable)
201  {
203  port_number = clib_bitmap_first_clear (bif->port_number_bitmap);
205  port_number, 1);
206  // bitmap starts at 0. Our port number starts at 1.
207  lacp_init_neighbor (sif, bif->hw_address, port_number + 1, sif->group);
208  lacp_init_state_machines (vm, sif);
209  lm->lacp_int++;
210  if (lm->lacp_int == 1)
211  {
214  }
215  }
216  else
217  {
218  ASSERT (lm->lacp_int >= 1);
219  if (lm->lacp_int == 0)
220  {
221  /* *INDENT-OFF* */
222  ELOG_TYPE_DECLARE (e) =
223  {
224  .format = "lacp-int-en-dis: BUG lacp_int == 0",
225  };
226  /* *INDENT-ON* */
228  }
229  else
230  {
231  lm->lacp_int--;
232  if (lm->lacp_int == 0)
235  }
236  }
237 }
238 
239 static clib_error_t *
241 {
242  lacp_main_t *lm = &lacp_main;
243  ethernet_lacp_pdu_t h;
244  ethernet_marker_pdu_t m;
245  u8 dst[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
246 
247  /* initialize binary API */
249 
250  /* Create the ethernet lacp packet template */
251 
252  clib_memset (&h, 0, sizeof (h));
253 
254  memcpy (h.ethernet.dst_address, dst, sizeof (h.ethernet.dst_address));
255 
256  /* leave src address blank (fill in at send time) */
257 
258  h.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
259 
260  h.lacp.subtype = LACP_SUBTYPE;
261  h.lacp.version_number = LACP_ACTOR_LACP_VERSION;
262 
263  /* Actor TLV */
264  h.lacp.actor.tlv_type = LACP_ACTOR_INFORMATION;
265  h.lacp.actor.tlv_length = sizeof (lacp_actor_partner_t);
266 
267  /* Partner TLV */
268  h.lacp.partner.tlv_type = LACP_PARTNER_INFORMATION;
269  h.lacp.partner.tlv_length = sizeof (lacp_actor_partner_t);
270 
271  /* Collector TLV */
272  h.lacp.collector.tlv_type = LACP_COLLECTOR_INFORMATION;
273  h.lacp.collector.tlv_length = sizeof (lacp_collector_t);
274  h.lacp.collector.max_delay = 0;
275 
276  /* Terminator TLV */
277  h.lacp.terminator.tlv_type = LACP_TERMINATOR_INFORMATION;
278  h.lacp.terminator.tlv_length = 0;
279 
282  /* data */ &h,
283  sizeof (h),
284  /* alloc chunk size */ 8,
285  "lacp-ethernet");
286 
287  /* Create the ethernet marker protocol packet template */
288 
289  clib_memset (&m, 0, sizeof (m));
290 
291  memcpy (m.ethernet.dst_address, dst, sizeof (m.ethernet.dst_address));
292 
293  /* leave src address blank (fill in at send time) */
294 
295  m.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
296 
297  m.marker.subtype = MARKER_SUBTYPE;
298  m.marker.version_number = MARKER_PROTOCOL_VERSION;
299 
300  m.marker.marker_info.tlv_length = sizeof (marker_information_t);
301 
302  /* Terminator TLV */
303  m.marker.terminator.tlv_type = MARKER_TERMINATOR_INFORMATION;
304  m.marker.terminator.tlv_length = 0;
305 
308  /* data */ &m,
309  sizeof (m),
310  /* alloc chunk size */ 8,
311  "marker-ethernet");
312 
314 
315  return 0;
316 }
317 
318 int
320  slave_if_t * sif, int event, int *state)
321 {
322  lacp_fsm_state_t *transition;
323  int rc = 0;
324 
325  transition = &machine->tables[*state].state_table[event];
326  LACP_DBG2 (sif, event, *state, machine, transition);
327  *state = transition->next_state;
328  if (transition->action)
329  rc = (*transition->action) ((void *) vm, (void *) sif);
330 
331  return rc;
332 }
333 
334 void
335 lacp_init_neighbor (slave_if_t * sif, u8 * hw_address, u16 port_number,
336  u32 group)
337 {
347  sif->lacp_enabled = 1;
348  sif->loopback_port = 0;
349  sif->ready = 0;
350  sif->ready_n = 0;
351  sif->port_moved = 0;
352  sif->ntt = 0;
353  sif->selected = LACP_PORT_UNSELECTED;
354  sif->actor.state = LACP_STATE_AGGREGATION;
356  sif->actor.state |= LACP_STATE_LACP_TIMEOUT;
357  if (sif->is_passive == 0)
358  sif->actor.state |= LACP_STATE_LACP_ACTIVITY;
359  clib_memcpy (sif->actor.system, hw_address, 6);
360  sif->actor.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
361  sif->actor.key = htons (group);
362  sif->actor.port_number = htons (port_number);
363  sif->actor.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
364 
365  sif->partner.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
366  sif->partner.key = htons (group);
367  sif->partner.port_number = htons (port_number);
368  sif->partner.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
369  sif->partner.state = 0;
370 
371  sif->actor_admin = sif->actor;
372  sif->partner_admin = sif->partner;
373 }
374 
375 void
377 {
378  bond_main_t *bm = &bond_main;
380 
381  lacp_init_tx_machine (vm, sif);
382  lacp_init_mux_machine (vm, sif);
383  lacp_init_ptx_machine (vm, sif);
384  lacp_init_rx_machine (vm, sif);
386  [sif->sw_if_index].actor_state,
387  sif->actor.state);
389  [sif->sw_if_index].partner_state,
390  sif->partner.state);
391 }
392 
394 
395 static clib_error_t *
397 {
398  lacp_main_t *lm = &lacp_main;
399  slave_if_t *sif;
400  vlib_main_t *vm = lm->vlib_main;
401 
402  sif = bond_get_slave_by_sw_if_index (sw_if_index);
403  if (sif)
404  {
405  if (sif->lacp_enabled == 0)
406  return 0;
407 
408  /* port_enabled is both admin up and hw link up */
409  sif->port_enabled = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
410  vnet_sw_interface_is_link_up (vnm, sw_if_index));
411  if (sif->port_enabled == 0)
412  {
413  lacp_init_neighbor (sif, sif->actor_admin.system,
414  ntohs (sif->actor_admin.port_number),
415  ntohs (sif->actor_admin.key));
416  lacp_init_state_machines (vm, sif);
417  }
418  }
419 
420  return 0;
421 }
422 
424 
425 static clib_error_t *
427 {
428  lacp_main_t *lm = &lacp_main;
429  slave_if_t *sif;
431  vlib_main_t *vm = lm->vlib_main;
432 
433  sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
435  if (sif)
436  {
437  if (sif->lacp_enabled == 0)
438  return 0;
439 
440  /* port_enabled is both admin up and hw link up */
441  sif->port_enabled = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
443  sw->sw_if_index));
444  if (sif->port_enabled == 0)
445  {
446  lacp_init_neighbor (sif, sif->actor_admin.system,
447  ntohs (sif->actor_admin.port_number),
448  ntohs (sif->actor_admin.key));
449  lacp_init_state_machines (vm, sif);
450  }
451  }
452 
453  return 0;
454 }
455 
457 
458 /* *INDENT-OFF* */
460  .version = VPP_BUILD_VER,
461  .description = "Link Aggregation Control Protocol (LACP)",
462 };
463 /* *INDENT-ON* */
464 
465 /*
466  * fd.io coding-style-patch-verification: ON
467  *
468  * Local Variables:
469  * eval: (c-set-style "gnu")
470  * End:
471  */
void lacp_send_lacp_pdu(vlib_main_t *vm, slave_if_t *sif)
Definition: lacp.c:109
void lacp_init_mux_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: mux_machine.c:238
vlib_main_t * vlib_main
Definition: node.h:121
vlib_main_t vlib_global_main
Definition: main.c:1943
lacp_stats_t ** stats
Definition: node.h:388
void lacp_init_ptx_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: ptx_machine.c:223
int selected
Definition: node.h:280
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
volatile u32 lacp_int
Definition: node.h:134
f64 last_lacpdu_recd_time
Definition: node.h:295
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:110
static void lacp_send_ethernet_lacp_pdu(slave_if_t *sif)
Definition: lacp.c:45
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:279
void lacp_init_neighbor(slave_if_t *sif, u8 *hw_address, u16 port_number, u32 group)
Definition: lacp.c:335
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
bond_main_t bond_main
Definition: node.c:25
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
f64 current_while_timer
Definition: node.h:286
u8 mode
Definition: node.h:328
static uword vnet_sw_interface_is_link_up(vnet_main_t *vnm, u32 sw_if_index)
unsigned char u8
Definition: types.h:56
lacp_fsm_state_t * state_table
Definition: machine.h:37
u8 ntt
Definition: node.h:262
static vnet_sw_interface_t * vnet_get_hw_sw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define clib_memcpy(d, s, n)
Definition: string.h:180
f64 periodic_timer
Definition: node.h:304
void lacp_create_periodic_process(void)
Definition: node.c:229
static void bond_register_callback(lacp_enable_disable_func func)
Definition: node.h:493
f32 ttl_in_seconds
Definition: node.h:221
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:400
static u8 lacp_timer_is_running(f64 timer)
Definition: node.h:166
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:498
vl_api_interface_index_t sw_if_index
Definition: gre.api:59
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
vnet_main_t * vnet_main
Definition: node.h:122
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(lacp_sw_interface_up_down)
vlib_packet_template_t packet_templates[LACP_N_PACKET_TEMPLATES]
Definition: node.h:128
f64 last_marker_pdu_recd_time
Definition: node.h:301
action_func action
Definition: machine.h:28
u32 sw_if_index
Definition: node.h:184
lacp_port_info_t actor
Definition: node.h:255
static u8 lacp_timer_is_expired(vlib_main_t *vm, f64 timer)
Definition: node.h:172
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:185
unsigned int u32
Definition: types.h:88
f64 partner_churn_timer
Definition: node.h:307
static void lacp_fill_pdu(lacp_pdu_t *lacpdu, slave_if_t *sif)
Definition: lacp.c:32
#define LACP_DEFAULT_SYSTEM_PRIORITY
Definition: protocol.h:99
void lacp_periodic(vlib_main_t *vm)
Definition: lacp.c:139
#define MARKER_SUBTYPE
Definition: protocol.h:132
u8 ready
Definition: node.h:277
void vlib_packet_template_init(vlib_main_t *vm, vlib_packet_template_t *t, void *packet_data, uword n_packet_data_bytes, uword min_n_buffers_each_alloc, char *fmt,...)
Definition: buffer.c:378
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:934
f64 last_marker_pdu_sent_time
Definition: node.h:298
static void lacp_stop_timer(f64 *timer)
Definition: node.h:160
VLIB_PLUGIN_REGISTER()
unsigned short u16
Definition: types.h:57
u8 port_moved
Definition: node.h:283
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:194
static void lacp_interface_enable_disable(vlib_main_t *vm, bond_if_t *bif, slave_if_t *sif, u8 enable)
Definition: lacp.c:194
#define LACP_SUBTYPE
Definition: protocol.h:25
#define ELOG_DATA(em, f)
Definition: elog.h:484
#define LACP_SHORT_TIMOUT_TIME
Definition: node.h:26
vl_api_address_t dst
Definition: gre.api:61
#define MARKER_PROTOCOL_VERSION
Definition: protocol.h:133
static int lacp_pick_packet_template(slave_if_t *sif)
Definition: lacp.c:101
vlib_main_t * vm
Definition: in2out_ed.c:1810
static clib_error_t * lacp_periodic_init(vlib_main_t *vm)
Definition: lacp.c:240
u32 partner_state
Definition: node.h:357
u32 flags
Definition: vhost_user.h:141
u16 n_vectors
Definition: node.h:397
u8 is_passive
Definition: node.h:251
u32 sw_if_index
Definition: node.h:218
lacp_port_info_t partner
Definition: node.h:254
#define LACP_DEFAULT_PORT_PRIORITY
Definition: protocol.h:98
u32 group
Definition: node.h:319
elog_main_t elog_main
Definition: main.h:193
void lacp_init_rx_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: rx_machine.c:428
lacp_main_t lacp_main
Definition: lacp.c:26
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:442
clib_error_t * lacp_plugin_api_hookup(vlib_main_t *vm)
Definition: lacp_api.c:119
f64 last_lacpdu_sent_time
Definition: node.h:292
u8 loopback_port
Definition: node.h:325
#define ASSERT(truth)
#define LACP_DBG2(n, e, s, m, t)
Definition: node.h:53
static bond_if_t * bond_get_master_by_dev_instance(u32 dev_instance)
Definition: node.h:516
u32 bif_dev_instance
Definition: node.h:323
static clib_error_t * lacp_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: lacp.c:426
vlib_packet_template_t marker_packet_templates[MARKER_N_PACKET_TEMPLATES]
Definition: node.h:131
u8 ready_n
Definition: node.h:274
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
void lacp_init_tx_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: tx_machine.c:109
u8 lacp_enabled
Definition: node.h:271
Definition: defs.h:47
u64 pdu_sent
Definition: node.h:337
u32 lacp_process_node_index
Definition: node.h:125
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
VLIB buffer representation.
Definition: buffer.h:102
uword * port_number_bitmap
Definition: node.h:206
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
lacp_port_info_t partner_admin
Definition: node.h:255
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(lacp_hw_interface_up_down)
#define vnet_buffer(b)
Definition: buffer.h:408
slave_if_t * neighbors
Definition: node.h:370
vl_api_dhcp_client_state_t state
Definition: dhcp.api:201
u32 actor_state
Definition: node.h:358
u8 hw_address[6]
Definition: node.h:208
f64 actor_churn_timer
Definition: node.h:289
u8 port_enabled
Definition: node.h:265
static slave_if_t * bond_get_slave_by_sw_if_index(u32 sw_if_index)
Definition: node.h:524
lacp_port_info_t actor_admin
Definition: node.h:259
static uword clib_bitmap_first_clear(uword *ai)
Return the lowest numbered clear bit in a bitmap.
Definition: bitmap.h:445
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:167
u8 packet_template_index
Definition: node.h:230
void lacp_init_state_machines(vlib_main_t *vm, slave_if_t *sif)
Definition: lacp.c:376
f64 wait_while_timer
Definition: node.h:310
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
lacp_fsm_machine_t * tables
Definition: machine.h:42
static clib_error_t * lacp_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: lacp.c:396
int lacp_machine_dispatch(lacp_machine_t *machine, vlib_main_t *vm, slave_if_t *sif, int event, int *state)
Definition: lacp.c:319
void stat_segment_set_state_counter(u32 index, u64 value)
Definition: stat_segment.c:854
#define LACP_ACTOR_LACP_VERSION
Definition: protocol.h:26