FD.io VPP  v19.08-27-gf4dcae4
Vector Packet Processing
node.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 
18 #define _GNU_SOURCE
19 #include <stdint.h>
20 #include <vnet/llc/llc.h>
21 #include <vnet/snap/snap.h>
22 #include <vnet/bonding/node.h>
23 
24 #ifndef CLIB_MARCH_VARIANT
26 #endif /* CLIB_MARCH_VARIANT */
27 
28 #define foreach_bond_input_error \
29  _(NONE, "no error") \
30  _(IF_DOWN, "interface down") \
31  _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
32 
33 typedef enum
34 {
35 #define _(f,s) BOND_INPUT_ERROR_##f,
37 #undef _
40 
41 static char *bond_input_error_strings[] = {
42 #define _(n,s) s,
44 #undef _
45 };
46 
47 static u8 *
48 format_bond_input_trace (u8 * s, va_list * args)
49 {
50  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
51  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
52  bond_packet_trace_t *t = va_arg (*args, bond_packet_trace_t *);
53 
54  s = format (s, "src %U, dst %U, %U -> %U",
58  t->sw_if_index,
60  t->bond_sw_if_index);
61 
62  return s;
63 }
64 
65 typedef enum
66 {
70 
73 {
74  llc_header_t *llc;
75  snap_header_t *snap;
76 
77  llc = (llc_header_t *) (eth + 1);
78  snap = (snap_header_t *) (llc + 1);
79 
80  return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
81  ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
82  (snap->protocol == htons (0x2000)) &&
83  (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
84  (snap->oui[2] == 0x0C)));
85 }
86 
87 static inline void
89  vlib_buffer_t * b, u32 bond_sw_if_index,
90  u32 * n_rx_packets, u32 * n_rx_bytes)
91 {
92  u16 *ethertype_p, ethertype;
95 
96  (*n_rx_packets)++;
97  *n_rx_bytes += b->current_length;
98  ethertype = clib_mem_unaligned (&eth->type, u16);
99  if (!ethernet_frame_is_tagged (ntohs (ethertype)))
100  {
101  // Let some layer2 packets pass through.
102  if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
103  && !packet_is_cdp (eth)
104  && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
105  {
106  /* Change the physical interface to bond interface */
107  vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
108  return;
109  }
110  }
111  else
112  {
113  vlan = (void *) (eth + 1);
114  ethertype_p = &vlan->type;
115  ethertype = clib_mem_unaligned (ethertype_p, u16);
116  if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
117  {
118  vlan++;
119  ethertype_p = &vlan->type;
120  }
121  ethertype = clib_mem_unaligned (ethertype_p, u16);
122  if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
123  && (ethertype != htons (ETHERNET_TYPE_CDP))
124  && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
125  {
126  /* Change the physical interface to bond interface */
127  vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
128  return;
129  }
130  }
131 
132  vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
133  return;
134 }
135 
136 static inline void
138  u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
139  u32 * bond_sw_if_index, vlib_buffer_t * b,
140  u32 * next_index, vlib_error_t * error)
141 {
142  slave_if_t *sif;
143  bond_if_t *bif;
144 
145  if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
146  return;
147 
148  *last_slave_sw_if_index = slave_sw_if_index;
149  *next_index = BOND_INPUT_NEXT_DROP;
150 
151  sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
152  ASSERT (sif);
153 
155 
156  ASSERT (bif);
157  ASSERT (vec_len (bif->slaves));
158 
159  if (PREDICT_TRUE (bif->admin_up == 0))
160  {
161  *bond_sw_if_index = slave_sw_if_index;
162  *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
163  }
164 
165  *bond_sw_if_index = bif->sw_if_index;
166  *error = 0;
167  vnet_feature_next (next_index, b);
168 }
169 
171  vlib_node_runtime_t * node,
172  vlib_frame_t * frame)
173 {
175  u32 *from, n_left;
176  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
177  u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
178  u16 nexts[VLIB_FRAME_SIZE], *next;
179  u32 last_slave_sw_if_index = ~0;
180  u32 bond_sw_if_index = 0;
181  vlib_error_t error = 0;
182  u32 next_index = 0;
183  u32 n_rx_bytes = 0, n_rx_packets = 0;
184 
185  /* Vector of buffer / pkt indices we're supposed to process */
186  from = vlib_frame_vector_args (frame);
187 
188  /* Number of buffers / pkts */
189  n_left = frame->n_vectors;
190 
191  vlib_get_buffers (vm, from, bufs, n_left);
192 
193  b = bufs;
194  next = nexts;
195  sw_if_index = sw_if_indices;
196 
197  while (n_left >= 4)
198  {
199  u32 x = 0;
200  /* Prefetch next iteration */
201  if (PREDICT_TRUE (n_left >= 16))
202  {
203  vlib_prefetch_buffer_data (b[8], LOAD);
204  vlib_prefetch_buffer_data (b[9], LOAD);
205  vlib_prefetch_buffer_data (b[10], LOAD);
206  vlib_prefetch_buffer_data (b[11], LOAD);
207 
208  vlib_prefetch_buffer_header (b[12], LOAD);
209  vlib_prefetch_buffer_header (b[13], LOAD);
210  vlib_prefetch_buffer_header (b[14], LOAD);
211  vlib_prefetch_buffer_header (b[15], LOAD);
212  }
213 
214  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
215  sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
216  sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
217  sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
218 
219  x |= sw_if_index[0] ^ last_slave_sw_if_index;
220  x |= sw_if_index[1] ^ last_slave_sw_if_index;
221  x |= sw_if_index[2] ^ last_slave_sw_if_index;
222  x |= sw_if_index[3] ^ last_slave_sw_if_index;
223 
224  if (PREDICT_TRUE (x == 0))
225  {
226  next[0] = next[1] = next[2] = next[3] = next_index;
227  if (next_index == BOND_INPUT_NEXT_DROP)
228  {
229  b[0]->error = error;
230  b[1]->error = error;
231  b[2]->error = error;
232  b[3]->error = error;
233  }
234  else
235  {
236  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
237  &n_rx_packets, &n_rx_bytes);
238  bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index,
239  &n_rx_packets, &n_rx_bytes);
240  bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index,
241  &n_rx_packets, &n_rx_bytes);
242  bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index,
243  &n_rx_packets, &n_rx_bytes);
244  }
245  }
246  else
247  {
248  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
249  &bond_sw_if_index, b[0], &next_index, &error);
250  next[0] = next_index;
251  if (next_index == BOND_INPUT_NEXT_DROP)
252  b[0]->error = error;
253  else
254  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
255  &n_rx_packets, &n_rx_bytes);
256 
257  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
258  &bond_sw_if_index, b[1], &next_index, &error);
259  next[1] = next_index;
260  if (next_index == BOND_INPUT_NEXT_DROP)
261  b[1]->error = error;
262  else
263  bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index,
264  &n_rx_packets, &n_rx_bytes);
265 
266  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
267  &bond_sw_if_index, b[2], &next_index, &error);
268  next[2] = next_index;
269  if (next_index == BOND_INPUT_NEXT_DROP)
270  b[2]->error = error;
271  else
272  bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index,
273  &n_rx_packets, &n_rx_bytes);
274 
275  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
276  &bond_sw_if_index, b[3], &next_index, &error);
277  next[3] = next_index;
278  if (next_index == BOND_INPUT_NEXT_DROP)
279  b[3]->error = error;
280  else
281  bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index,
282  &n_rx_packets, &n_rx_bytes);
283  }
284 
289 
290  /* next */
291  n_left -= 4;
292  b += 4;
293  sw_if_index += 4;
294  next += 4;
295  }
296 
297  while (n_left)
298  {
299  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
300  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
301  &bond_sw_if_index, b[0], &next_index, &error);
302  next[0] = next_index;
303  if (next_index == BOND_INPUT_NEXT_DROP)
304  b[0]->error = error;
305  else
306  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
307  &n_rx_packets, &n_rx_bytes);
308 
310 
311  /* next */
312  n_left -= 1;
313  b += 1;
314  sw_if_index += 1;
315  next += 1;
316  }
317 
318  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
319  {
320  n_left = frame->n_vectors; /* number of packets to process */
321  b = bufs;
322  sw_if_index = sw_if_indices;
324 
325  while (n_left)
326  {
327  if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
328  {
329  t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
330  t0->sw_if_index = sw_if_index[0];
332  sizeof (ethernet_header_t));
333  t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
334  }
335  /* next */
336  n_left--;
337  b++;
338  sw_if_index++;
339  }
340  }
341 
342  /* increase rx counters */
345  VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, n_rx_packets,
346  n_rx_bytes);
347 
348  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
350  BOND_INPUT_ERROR_NONE, frame->n_vectors);
351 
352  return frame->n_vectors;
353 }
354 
355 static clib_error_t *
357 {
358  return 0;
359 }
360 
361 /* *INDENT-OFF* */
363  .name = "bond-input",
364  .vector_size = sizeof (u32),
365  .format_buffer = format_ethernet_header_with_length,
366  .format_trace = format_bond_input_trace,
368  .n_errors = BOND_INPUT_N_ERROR,
369  .error_strings = bond_input_error_strings,
370  .n_next_nodes = BOND_INPUT_N_NEXT,
371  .next_nodes =
372  {
373  [BOND_INPUT_NEXT_DROP] = "error-drop"
374  }
375 };
376 
378 
379 VNET_FEATURE_INIT (bond_input, static) =
380 {
381  .arc_name = "device-input",
382  .node_name = "bond-input",
383  .runs_before = VNET_FEATURES ("ethernet-input"),
384 };
385 /* *INDENT-ON* */
386 
387 static clib_error_t *
389 {
390  bond_main_t *bm = &bond_main;
391  slave_if_t *sif;
392  vlib_main_t *vm = bm->vlib_main;
393 
394  sif = bond_get_slave_by_sw_if_index (sw_if_index);
395  if (sif)
396  {
398  if (sif->lacp_enabled)
399  return 0;
400 
401  if (sif->port_enabled == 0)
402  {
404  }
405  else
406  {
407  vnet_main_t *vnm = vnet_get_main ();
408  vnet_hw_interface_t *hw =
409  vnet_get_sup_hw_interface (vnm, sw_if_index);
410 
413  }
414  }
415 
416  return 0;
417 }
418 
420 
421 static clib_error_t *
423 {
424  bond_main_t *bm = &bond_main;
425  slave_if_t *sif;
427  vlib_main_t *vm = bm->vlib_main;
428 
429  sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
431  if (sif)
432  {
433  if (sif->lacp_enabled)
434  return 0;
435 
436  if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
437  {
439  }
440  else if (sif->port_enabled)
441  {
443  }
444  }
445 
446  return 0;
447 }
448 
450 
451 /*
452  * fd.io coding-style-patch-verification: ON
453  *
454  * Local Variables:
455  * eval: (c-set-style "gnu")
456  * End:
457  */
#define foreach_bond_input_error
Definition: node.c:28
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(bond_sw_interface_up_down)
u32 flags
Definition: vhost_user.h:141
#define CLIB_UNUSED(x)
Definition: clib.h:82
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:220
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
static clib_error_t * bond_input_init(vlib_main_t *vm)
Definition: node.c:356
vnet_interface_main_t interface_main
Definition: vnet.h:56
#define PREDICT_TRUE(x)
Definition: clib.h:112
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
u8 src_address[6]
Definition: packet.h:56
u32 thread_index
Definition: main.h:197
u8 src_sap
Definition: llc.h:82
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
u16 vlib_error_t
Definition: error.h:43
bond_main_t bond_main
Definition: node.c:25
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:201
bond_input_error_t
Definition: node.c:33
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:468
void bond_enable_collecting_distributing(vlib_main_t *vm, slave_if_t *sif)
Definition: cli.c:103
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static vnet_sw_interface_t * vnet_get_hw_sw_interface(vnet_main_t *vnm, u32 hw_if_index)
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(bond_hw_interface_up_down)
vlib_node_registration_t bond_input_node
(constructor) VLIB_REGISTER_NODE (bond_input_node)
Definition: node.c:362
#define static_always_inline
Definition: clib.h:99
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
static void bond_update_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *last_slave_sw_if_index, u32 slave_sw_if_index, u32 *bond_sw_if_index, vlib_buffer_t *b, u32 *next_index, vlib_error_t *error)
Definition: node.c:137
vl_api_interface_index_t sw_if_index
Definition: gre.api:50
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:842
u8 dst_address[6]
Definition: packet.h:55
u32 sw_if_index
Definition: node.h:177
vnet_hw_interface_flags_t flags
Definition: interface.h:505
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
bond_output_next_t
Definition: node.c:65
vlib_main_t * vlib_main
Definition: node.h:359
unsigned int u32
Definition: types.h:88
#define VLIB_FRAME_SIZE
Definition: node.h:376
static clib_error_t * bond_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: node.c:388
static void bond_sw_if_idx_rewrite(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, u32 bond_sw_if_index, u32 *n_rx_packets, u32 *n_rx_bytes)
Definition: node.c:88
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
u8 admin_up
Definition: node.h:158
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:111
vnet_main_t vnet_main
Definition: misc.c:43
u32 node_index
Node index.
Definition: node.h:494
static u8 * format_bond_input_trace(u8 *s, va_list *args)
Definition: node.c:48
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
u8 * format_ethernet_header_with_length(u8 *s, va_list *args)
Definition: format.c:97
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u32 * slaves
Definition: node.h:180
vlib_main_t * vm
Definition: buffer.c:312
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:332
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:295
ethernet_header_t ethernet
Definition: node.h:375
void bond_disable_collecting_distributing(vlib_main_t *vm, slave_if_t *sif)
Definition: cli.c:25
#define vlib_prefetch_buffer_data(b, type)
Definition: buffer.h:204
VNET_FEATURE_INIT(bond_input, static)
#define ASSERT(truth)
static_always_inline u8 packet_is_cdp(ethernet_header_t *eth)
Definition: node.c:72
static bond_if_t * bond_get_master_by_dev_instance(u32 dev_instance)
Definition: node.h:495
u32 bif_dev_instance
Definition: node.h:315
static_always_inline int ethernet_frame_is_tagged(u16 type)
Definition: ethernet.h:78
#define clib_mem_unaligned(pointer, type)
Definition: types.h:155
u8 control
Definition: llc.h:87
static char * bond_input_error_strings[]
Definition: node.c:41
#define VNET_FEATURES(...)
Definition: feature.h:435
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
u8 lacp_enabled
Definition: node.h:263
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:489
VLIB buffer representation.
Definition: buffer.h:102
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
static clib_error_t * bond_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: node.c:422
#define vnet_buffer(b)
Definition: buffer.h:361
u8 port_enabled
Definition: node.h:257
static slave_if_t * bond_get_slave_by_sw_if_index(u32 sw_if_index)
Definition: node.h:503
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:244
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
u32 bond_sw_if_index
Definition: node.h:377
Definition: defs.h:46