FD.io VPP  v19.04.1-1-ge4a0f9f
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 u32
89  vlib_buffer_t * b, u32 bond_sw_if_index)
90 {
91  u16 *ethertype_p, ethertype;
94 
95  ethertype = clib_mem_unaligned (&eth->type, u16);
96  if (!ethernet_frame_is_tagged (ntohs (ethertype)))
97  {
98  // Let some layer2 packets pass through.
99  if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
100  && !packet_is_cdp (eth)
101  && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
102  {
103  /* Change the physical interface to bond interface */
104  vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
105  return 1;
106  }
107  }
108  else
109  {
110  vlan = (void *) (eth + 1);
111  ethertype_p = &vlan->type;
112  ethertype = clib_mem_unaligned (ethertype_p, u16);
113  if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
114  {
115  vlan++;
116  ethertype_p = &vlan->type;
117  }
118  ethertype = clib_mem_unaligned (ethertype_p, u16);
119  if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
120  && (ethertype != htons (ETHERNET_TYPE_CDP))
121  && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
122  {
123  /* Change the physical interface to bond interface */
124  vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
125  return 1;
126  }
127  }
128 
129  vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
130  return 0;
131 }
132 
133 static inline void
135  u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
136  u32 packet_count,
137  u32 * bond_sw_if_index, vlib_buffer_t * b,
138  u32 * next_index, vlib_error_t * error)
139 {
141  slave_if_t *sif;
142  bond_if_t *bif;
143 
144  if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
145  return;
146 
147  if (packet_count)
149  VNET_INTERFACE_COUNTER_RX, thread_index,
150  *last_slave_sw_if_index, packet_count);
151 
152  *last_slave_sw_if_index = slave_sw_if_index;
153  *next_index = BOND_INPUT_NEXT_DROP;
154 
155  sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
156  ASSERT (sif);
157 
159 
160  ASSERT (bif);
161  ASSERT (vec_len (bif->slaves));
162 
163  if (PREDICT_TRUE (bif->admin_up == 0))
164  {
165  *bond_sw_if_index = slave_sw_if_index;
166  *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
167  }
168 
169  *bond_sw_if_index = bif->sw_if_index;
170  *error = 0;
171  vnet_feature_next (next_index, b);
172 }
173 
175  vlib_node_runtime_t * node,
176  vlib_frame_t * frame)
177 {
179  u32 *from, n_left;
180  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
181  u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
182  u16 nexts[VLIB_FRAME_SIZE], *next;
183  u32 last_slave_sw_if_index = ~0;
184  u32 bond_sw_if_index = 0;
185  vlib_error_t error = 0;
186  u32 next_index = 0;
187  u32 cnt = 0;
188 
189  /* Vector of buffer / pkt indices we're supposed to process */
190  from = vlib_frame_vector_args (frame);
191 
192  /* Number of buffers / pkts */
193  n_left = frame->n_vectors;
194 
195  vlib_get_buffers (vm, from, bufs, n_left);
196 
197  b = bufs;
198  next = nexts;
199  sw_if_index = sw_if_indices;
200 
201  while (n_left >= 4)
202  {
203  u32 x = 0;
204  /* Prefetch next iteration */
205  if (PREDICT_TRUE (n_left >= 16))
206  {
207  vlib_prefetch_buffer_data (b[8], LOAD);
208  vlib_prefetch_buffer_data (b[9], LOAD);
209  vlib_prefetch_buffer_data (b[10], LOAD);
210  vlib_prefetch_buffer_data (b[11], LOAD);
211 
212  vlib_prefetch_buffer_header (b[12], LOAD);
213  vlib_prefetch_buffer_header (b[13], LOAD);
214  vlib_prefetch_buffer_header (b[14], LOAD);
215  vlib_prefetch_buffer_header (b[15], LOAD);
216  }
217 
218  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
219  sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
220  sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
221  sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
222 
223  x |= sw_if_index[0] ^ last_slave_sw_if_index;
224  x |= sw_if_index[1] ^ last_slave_sw_if_index;
225  x |= sw_if_index[2] ^ last_slave_sw_if_index;
226  x |= sw_if_index[3] ^ last_slave_sw_if_index;
227 
228  if (PREDICT_TRUE (x == 0))
229  {
230  next[0] = next[1] = next[2] = next[3] = next_index;
231  if (next_index == BOND_INPUT_NEXT_DROP)
232  {
233  b[0]->error = error;
234  b[1]->error = error;
235  b[2]->error = error;
236  b[3]->error = error;
237  }
238  else
239  {
240  cnt +=
241  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
242  cnt +=
243  bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
244  cnt +=
245  bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
246  cnt +=
247  bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
248  }
249  }
250  else
251  {
252 
253  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
254  cnt, &bond_sw_if_index, b[0], &next_index,
255  &error);
256  next[0] = next_index;
257  if (next_index == BOND_INPUT_NEXT_DROP)
258  b[0]->error = error;
259  else
260  cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
261 
262  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
263  cnt, &bond_sw_if_index, b[1], &next_index,
264  &error);
265  next[1] = next_index;
266  if (next_index == BOND_INPUT_NEXT_DROP)
267  b[1]->error = error;
268  else
269  cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
270 
271  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
272  cnt, &bond_sw_if_index, b[2], &next_index,
273  &error);
274  next[2] = next_index;
275  if (next_index == BOND_INPUT_NEXT_DROP)
276  b[2]->error = error;
277  else
278  cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
279 
280  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
281  cnt, &bond_sw_if_index, b[3], &next_index,
282  &error);
283  next[3] = next_index;
284  if (next_index == BOND_INPUT_NEXT_DROP)
285  b[3]->error = error;
286  else
287  cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
288  }
289 
294 
295  /* next */
296  n_left -= 4;
297  b += 4;
298  sw_if_index += 4;
299  next += 4;
300  }
301 
302  while (n_left)
303  {
304  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
305  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
306  cnt, &bond_sw_if_index, b[0], &next_index, &error);
307  next[0] = next_index;
308  if (next_index == BOND_INPUT_NEXT_DROP)
309  b[0]->error = error;
310  else
311  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
312 
314 
315  /* next */
316  n_left -= 1;
317  b += 1;
318  sw_if_index += 1;
319  next += 1;
320  }
321 
322  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
323  {
324  n_left = frame->n_vectors; /* number of packets to process */
325  b = bufs;
326  sw_if_index = sw_if_indices;
328 
329  while (n_left)
330  {
331  if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
332  {
333  t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
334  t0->sw_if_index = sw_if_index[0];
336  sizeof (ethernet_header_t));
337  t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
338  }
339  /* next */
340  n_left--;
341  b++;
342  sw_if_index++;
343  }
344  }
345 
346  /* increase rx counters */
349  VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
350 
351  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
353  BOND_INPUT_ERROR_NONE, frame->n_vectors);
354 
355  return frame->n_vectors;
356 }
357 
358 static clib_error_t *
360 {
361  return 0;
362 }
363 
364 /* *INDENT-OFF* */
366  .name = "bond-input",
367  .vector_size = sizeof (u32),
368  .format_buffer = format_ethernet_header_with_length,
369  .format_trace = format_bond_input_trace,
370  .type = VLIB_NODE_TYPE_INTERNAL,
371  .n_errors = BOND_INPUT_N_ERROR,
372  .error_strings = bond_input_error_strings,
373  .n_next_nodes = BOND_INPUT_N_NEXT,
374  .next_nodes =
375  {
376  [BOND_INPUT_NEXT_DROP] = "error-drop"
377  }
378 };
379 
381 
382 VNET_FEATURE_INIT (bond_input, static) =
383 {
384  .arc_name = "device-input",
385  .node_name = "bond-input",
386  .runs_before = VNET_FEATURES ("ethernet-input"),
387 };
388 /* *INDENT-ON* */
389 
390 static clib_error_t *
392 {
393  bond_main_t *bm = &bond_main;
394  slave_if_t *sif;
395  vlib_main_t *vm = bm->vlib_main;
396 
397  sif = bond_get_slave_by_sw_if_index (sw_if_index);
398  if (sif)
399  {
401  if (sif->lacp_enabled)
402  return 0;
403 
404  if (sif->port_enabled == 0)
405  {
407  }
408  else
409  {
410  vnet_main_t *vnm = vnet_get_main ();
411  vnet_hw_interface_t *hw =
412  vnet_get_sup_hw_interface (vnm, sw_if_index);
413 
416  }
417  }
418 
419  return 0;
420 }
421 
423 
424 static clib_error_t *
426 {
427  bond_main_t *bm = &bond_main;
428  slave_if_t *sif;
430  vlib_main_t *vm = bm->vlib_main;
431 
432  sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
434  if (sif)
435  {
436  if (sif->lacp_enabled)
437  return 0;
438 
439  if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
440  {
442  }
443  else if (sif->port_enabled)
444  {
446  }
447  }
448 
449  return 0;
450 }
451 
453 
454 /*
455  * fd.io coding-style-patch-verification: ON
456  *
457  * Local Variables:
458  * eval: (c-set-style "gnu")
459  * End:
460  */
#define foreach_bond_input_error
Definition: node.c:28
u32 sw_if_index
Definition: ipsec_gre.api:37
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(bond_sw_interface_up_down)
u32 flags
Definition: vhost_user.h:115
#define CLIB_UNUSED(x)
Definition: clib.h:82
static u32 bond_sw_if_idx_rewrite(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, u32 bond_sw_if_index)
Definition: node.c:88
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
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:359
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 vlib_error_t
Definition: error.h:44
bond_main_t bond_main
Definition: node.c:25
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 increment)
Increment a simple counter.
Definition: counter.h:78
#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:469
void bond_enable_collecting_distributing(vlib_main_t *vm, slave_if_t *sif)
Definition: cli.c:59
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:365
#define static_always_inline
Definition: clib.h:99
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
u8 dst_address[6]
Definition: packet.h:55
u32 sw_if_index
Definition: node.h:170
vnet_hw_interface_flags_t flags
Definition: interface.h:494
#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:344
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:391
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
u8 admin_up
Definition: node.h:156
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
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:823
u32 node_index
Node index.
Definition: node.h:495
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:1180
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:173
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:360
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:480
u32 bif_dev_instance
Definition: node.h:300
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:57
u8 lacp_enabled
Definition: node.h:248
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:451
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:274
static clib_error_t * bond_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: node.c:425
#define vnet_buffer(b)
Definition: buffer.h:369
u8 port_enabled
Definition: node.h:242
static slave_if_t * bond_get_slave_by_sw_if_index(u32 sw_if_index)
Definition: node.h:488
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:362
Definition: defs.h:46
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 packet_count, u32 *bond_sw_if_index, vlib_buffer_t *b, u32 *next_index, vlib_error_t *error)
Definition: node.c:134