FD.io VPP  v19.04.4-rc0-5-ge88582fac
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 
26 
27 /*
28  * Generate lacp pdu
29  */
30 static void
31 lacp_fill_pdu (lacp_pdu_t * lacpdu, slave_if_t * sif)
32 {
33  /* Actor TLV */
34  lacpdu->actor.port_info = sif->actor;
35 
36  /* Partner TLV */
37  lacpdu->partner.port_info = sif->partner;
38 }
39 
40 /*
41  * send a lacp pkt on an ethernet interface
42  */
43 static void
45 {
46  lacp_main_t *lm = &lacp_main;
47  u32 *to_next;
48  ethernet_lacp_pdu_t *h0;
50  u32 bi0;
51  vlib_buffer_t *b0;
52  vlib_frame_t *f;
53  vlib_main_t *vm = lm->vlib_main;
54  vnet_main_t *vnm = lm->vnet_main;
55 
56  /*
57  * see lacp_periodic_init() to understand what's already painted
58  * into the buffer by the packet template mechanism
59  */
61  (vm, &lm->packet_templates[sif->packet_template_index], &bi0);
62 
63  if (!h0)
64  return;
65 
66  /* Add the interface's ethernet source address */
67  hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
68 
69  clib_memcpy (h0->ethernet.src_address, hw->hw_address,
70  vec_len (hw->hw_address));
71 
72  lacp_fill_pdu (&h0->lacp, sif);
73 
74  /* Set the outbound packet length */
75  b0 = vlib_get_buffer (vm, bi0);
76  b0->current_length = sizeof (ethernet_lacp_pdu_t);
77  b0->current_data = 0;
79 
80  /* And the outbound interface */
81  vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
82 
83  /* And output the packet on the correct interface */
85 
86  to_next = vlib_frame_vector_args (f);
87  to_next[0] = bi0;
88  f->n_vectors = 1;
89 
91 
93  sif->pdu_sent++;
94 }
95 
96 /*
97  * Decide which lacp packet template to use
98  */
99 static int
101 {
103 
104  return 0;
105 }
106 
107 void
109 {
110  if (sif->mode != BOND_MODE_LACP)
111  {
113  return;
114  }
115 
116  if (sif->packet_template_index == (u8) ~ 0)
117  {
118  /* If we don't know how to talk to this peer, don't try again */
119  if (lacp_pick_packet_template (sif))
120  {
122  return;
123  }
124  }
125 
126  switch (sif->packet_template_index)
127  {
130  break;
131 
132  default:
133  ASSERT (0);
134  }
135 }
136 
137 void
139 {
140  bond_main_t *bm = &bond_main;
141  lacp_main_t *lm = &lacp_main;
142  slave_if_t *sif;
143 
144  /* *INDENT-OFF* */
145  pool_foreach (sif, bm->neighbors,
146  ({
147  if (sif->port_enabled == 0)
148  continue;
149 
150  if (lacp_timer_is_running (sif->current_while_timer) &&
151  lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
152  {
153  lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
154  LACP_RX_EVENT_TIMER_EXPIRED, &sif->rx_state);
155  }
156 
159  {
160  lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
161  LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
162  }
165  {
166  sif->ready_n = 1;
167  lacp_stop_timer (&sif->wait_while_timer);
168  lacp_selection_logic (vm, sif);
169  }
170  }));
171  /* *INDENT-ON* */
172 }
173 
174 static void
176  slave_if_t * sif, u8 enable)
177 {
178  lacp_main_t *lm = &lacp_main;
179  uword port_number;
180 
181  if (enable)
182  {
183  port_number = clib_bitmap_first_clear (bif->port_number_bitmap);
185  port_number, 1);
186  // bitmap starts at 0. Our port number starts at 1.
187  lacp_init_neighbor (sif, bif->hw_address, port_number + 1, sif->group);
188  lacp_init_state_machines (vm, sif);
189  lm->lacp_int++;
190  if (lm->lacp_int == 1)
191  {
194  }
195  }
196  else
197  {
198  lm->lacp_int--;
199  if (lm->lacp_int == 0)
200  {
203  }
204  }
205 }
206 
207 static clib_error_t *
209 {
210  lacp_main_t *lm = &lacp_main;
211  ethernet_lacp_pdu_t h;
212  ethernet_marker_pdu_t m;
213  u8 dst[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
214 
215  /* initialize binary API */
217 
218  /* Create the ethernet lacp packet template */
219 
220  clib_memset (&h, 0, sizeof (h));
221 
222  memcpy (h.ethernet.dst_address, dst, sizeof (h.ethernet.dst_address));
223 
224  /* leave src address blank (fill in at send time) */
225 
226  h.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
227 
228  h.lacp.subtype = LACP_SUBTYPE;
229  h.lacp.version_number = LACP_ACTOR_LACP_VERSION;
230 
231  /* Actor TLV */
232  h.lacp.actor.tlv_type = LACP_ACTOR_INFORMATION;
233  h.lacp.actor.tlv_length = sizeof (lacp_actor_partner_t);
234 
235  /* Partner TLV */
236  h.lacp.partner.tlv_type = LACP_PARTNER_INFORMATION;
237  h.lacp.partner.tlv_length = sizeof (lacp_actor_partner_t);
238 
239  /* Collector TLV */
240  h.lacp.collector.tlv_type = LACP_COLLECTOR_INFORMATION;
241  h.lacp.collector.tlv_length = sizeof (lacp_collector_t);
242  h.lacp.collector.max_delay = 0;
243 
244  /* Terminator TLV */
245  h.lacp.terminator.tlv_type = LACP_TERMINATOR_INFORMATION;
246  h.lacp.terminator.tlv_length = 0;
247 
250  /* data */ &h,
251  sizeof (h),
252  /* alloc chunk size */ 8,
253  "lacp-ethernet");
254 
255  /* Create the ethernet marker protocol packet template */
256 
257  clib_memset (&m, 0, sizeof (m));
258 
259  memcpy (m.ethernet.dst_address, dst, sizeof (m.ethernet.dst_address));
260 
261  /* leave src address blank (fill in at send time) */
262 
263  m.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
264 
265  m.marker.subtype = MARKER_SUBTYPE;
266  m.marker.version_number = MARKER_PROTOCOL_VERSION;
267 
268  m.marker.marker_info.tlv_length = sizeof (marker_information_t);
269 
270  /* Terminator TLV */
271  m.marker.terminator.tlv_type = MARKER_TERMINATOR_INFORMATION;
272  m.marker.terminator.tlv_length = 0;
273 
276  /* data */ &m,
277  sizeof (m),
278  /* alloc chunk size */ 8,
279  "marker-ethernet");
280 
282 
283  return 0;
284 }
285 
286 int
288  slave_if_t * sif, int event, int *state)
289 {
290  lacp_fsm_state_t *transition;
291  int rc = 0;
292 
293  transition = &machine->tables[*state].state_table[event];
294  LACP_DBG2 (sif, event, *state, machine, transition);
295  *state = transition->next_state;
296  if (transition->action)
297  rc = (*transition->action) ((void *) vm, (void *) sif);
298 
299  return rc;
300 }
301 
302 void
303 lacp_init_neighbor (slave_if_t * sif, u8 * hw_address, u16 port_number,
304  u32 group)
305 {
315  sif->lacp_enabled = 1;
316  sif->loopback_port = 0;
317  sif->ready = 0;
318  sif->ready_n = 0;
319  sif->port_moved = 0;
320  sif->ntt = 0;
321  sif->selected = LACP_PORT_UNSELECTED;
322  sif->actor.state = LACP_STATE_AGGREGATION;
324  sif->actor.state |= LACP_STATE_LACP_TIMEOUT;
325  if (sif->is_passive == 0)
326  sif->actor.state |= LACP_STATE_LACP_ACTIVITY;
327  clib_memcpy (sif->actor.system, hw_address, 6);
328  sif->actor.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
329  sif->actor.key = htons (group);
330  sif->actor.port_number = htons (port_number);
331  sif->actor.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
332 
333  sif->partner.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
334  sif->partner.key = htons (group);
335  sif->partner.port_number = htons (port_number);
336  sif->partner.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
337  sif->partner.key = htons (group);
338  sif->partner.state = 0;
339 
340  sif->actor_admin = sif->actor;
341  sif->partner_admin = sif->partner;
342 }
343 
344 void
346 {
347  lacp_init_tx_machine (vm, sif);
348  lacp_init_mux_machine (vm, sif);
349  lacp_init_ptx_machine (vm, sif);
350  lacp_init_rx_machine (vm, sif);
351 }
352 
354 
355 static clib_error_t *
357 {
358  lacp_main_t *lm = &lacp_main;
359  slave_if_t *sif;
360  vlib_main_t *vm = lm->vlib_main;
361 
362  sif = bond_get_slave_by_sw_if_index (sw_if_index);
363  if (sif)
364  {
366  if (sif->port_enabled == 0)
367  {
368  if (sif->lacp_enabled)
369  {
370  lacp_init_neighbor (sif, sif->actor_admin.system,
371  ntohs (sif->actor_admin.port_number),
372  ntohs (sif->actor_admin.key));
373  lacp_init_state_machines (vm, sif);
374  }
375  }
376  }
377 
378  return 0;
379 }
380 
382 
383 static clib_error_t *
385 {
386  lacp_main_t *lm = &lacp_main;
387  slave_if_t *sif;
389  vlib_main_t *vm = lm->vlib_main;
390 
391  sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
393  if (sif)
394  {
395  if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
396  {
397  if (sif->lacp_enabled)
398  {
399  lacp_init_neighbor (sif, sif->actor_admin.system,
400  ntohs (sif->actor_admin.port_number),
401  ntohs (sif->actor_admin.key));
402  lacp_init_state_machines (vm, sif);
403  }
404  }
405  }
406 
407  return 0;
408 }
409 
411 
412 /* *INDENT-OFF* */
414  .version = VPP_BUILD_VER,
415  .description = "Link Aggregation Control Protocol (LACP)",
416 };
417 /* *INDENT-ON* */
418 
419 /*
420  * fd.io coding-style-patch-verification: ON
421  *
422  * Local Variables:
423  * eval: (c-set-style "gnu")
424  * End:
425  */
void lacp_send_lacp_pdu(vlib_main_t *vm, slave_if_t *sif)
Definition: lacp.c:108
u32 sw_if_index
Definition: ipsec_gre.api:37
void lacp_init_mux_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: mux_machine.c:224
vlib_main_t * vlib_main
Definition: node.h:119
u32 flags
Definition: vhost_user.h:115
void lacp_init_ptx_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: ptx_machine.c:209
int selected
Definition: node.h:254
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
f64 last_lacpdu_recd_time
Definition: node.h:269
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:44
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:255
void lacp_init_neighbor(slave_if_t *sif, u8 *hw_address, u16 port_number, u32 group)
Definition: lacp.c:303
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
vl_api_ip4_address_t dst
Definition: ipsec_gre.api:39
u32 lacp_int
Definition: node.h:132
f64 current_while_timer
Definition: node.h:260
u8 mode
Definition: node.h:302
unsigned char u8
Definition: types.h:56
lacp_fsm_state_t * state_table
Definition: machine.h:37
u8 ntt
Definition: node.h:236
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:278
static void bond_register_callback(lacp_enable_disable_func func)
Definition: node.h:454
f32 ttl_in_seconds
Definition: node.h:198
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:389
static u8 lacp_timer_is_running(f64 timer)
Definition: node.h:163
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
vnet_main_t * vnet_main
Definition: node.h:120
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:126
f64 last_marker_pdu_recd_time
Definition: node.h:275
action_func action
Definition: machine.h:28
lacp_port_info_t actor
Definition: node.h:229
static u8 lacp_timer_is_expired(vlib_main_t *vm, f64 timer)
Definition: node.h:169
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
vhost_vring_state_t state
Definition: vhost_user.h:120
unsigned int u32
Definition: types.h:88
f64 partner_churn_timer
Definition: node.h:281
static void lacp_fill_pdu(lacp_pdu_t *lacpdu, slave_if_t *sif)
Definition: lacp.c:31
#define LACP_DEFAULT_SYSTEM_PRIORITY
Definition: protocol.h:99
void lacp_periodic(vlib_main_t *vm)
Definition: lacp.c:138
#define MARKER_SUBTYPE
Definition: protocol.h:132
u8 ready
Definition: node.h:251
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:367
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:272
static void lacp_stop_timer(f64 *timer)
Definition: node.h:157
VLIB_PLUGIN_REGISTER()
unsigned short u16
Definition: types.h:57
u8 port_moved
Definition: node.h:257
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
static void lacp_interface_enable_disable(vlib_main_t *vm, bond_if_t *bif, slave_if_t *sif, u8 enable)
Definition: lacp.c:175
#define LACP_SUBTYPE
Definition: protocol.h:25
#define LACP_SHORT_TIMOUT_TIME
Definition: node.h:26
#define MARKER_PROTOCOL_VERSION
Definition: protocol.h:133
static int lacp_pick_packet_template(slave_if_t *sif)
Definition: lacp.c:100
static clib_error_t * lacp_periodic_init(vlib_main_t *vm)
Definition: lacp.c:208
u16 n_vectors
Definition: node.h:395
u8 is_passive
Definition: node.h:225
u32 sw_if_index
Definition: node.h:195
vlib_main_t * vm
Definition: buffer.c:312
lacp_port_info_t partner
Definition: node.h:228
#define LACP_DEFAULT_PORT_PRIORITY
Definition: protocol.h:98
u32 group
Definition: node.h:293
void lacp_init_rx_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: rx_machine.c:415
lacp_main_t lacp_main
Definition: lacp.c:25
clib_error_t * lacp_plugin_api_hookup(vlib_main_t *vm)
Definition: lacp_api.c:144
f64 last_lacpdu_sent_time
Definition: node.h:266
u8 loopback_port
Definition: node.h:299
#define ASSERT(truth)
#define LACP_DBG2(n, e, s, m, t)
Definition: node.h:53
static clib_error_t * lacp_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: lacp.c:384
vlib_packet_template_t marker_packet_templates[MARKER_N_PACKET_TEMPLATES]
Definition: node.h:129
u8 ready_n
Definition: node.h:248
void lacp_init_tx_machine(vlib_main_t *vm, slave_if_t *sif)
Definition: tx_machine.c:96
u8 lacp_enabled
Definition: node.h:245
Definition: defs.h:47
u64 pdu_sent
Definition: node.h:311
u32 lacp_process_node_index
Definition: node.h:123
#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:183
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:229
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(lacp_hw_interface_up_down)
#define vnet_buffer(b)
Definition: buffer.h:369
slave_if_t * neighbors
Definition: node.h:335
u8 hw_address[6]
Definition: node.h:185
f64 actor_churn_timer
Definition: node.h:263
u8 port_enabled
Definition: node.h:239
static slave_if_t * bond_get_slave_by_sw_if_index(u32 sw_if_index)
Definition: node.h:485
lacp_port_info_t actor_admin
Definition: node.h:233
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:207
void lacp_init_state_machines(vlib_main_t *vm, slave_if_t *sif)
Definition: lacp.c:345
f64 wait_while_timer
Definition: node.h:284
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:356
int lacp_machine_dispatch(lacp_machine_t *machine, vlib_main_t *vm, slave_if_t *sif, int event, int *state)
Definition: lacp.c:287
#define LACP_ACTOR_LACP_VERSION
Definition: protocol.h:26