FD.io VPP  v18.07-34-g55fbdb9
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 
25 
26 #define foreach_bond_input_error \
27  _(NONE, "no error") \
28  _(IF_DOWN, "interface down") \
29  _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
30 
31 typedef enum
32 {
33 #define _(f,s) BOND_INPUT_ERROR_##f,
35 #undef _
38 
39 #ifndef CLIB_MARCH_VARIANT
40 static char *bond_input_error_strings[] = {
41 #define _(n,s) s,
43 #undef _
44 };
45 
46 static u8 *
47 format_bond_input_trace (u8 * s, va_list * args)
48 {
49  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
50  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
51  bond_packet_trace_t *t = va_arg (*args, bond_packet_trace_t *);
52 
53  s = format (s, "src %U, dst %U, %U -> %U",
57  t->sw_if_index,
59  t->bond_sw_if_index);
60 
61  return s;
62 }
63 #endif
64 
65 
66 typedef enum
67 {
71 
74 {
75  llc_header_t *llc;
76  snap_header_t *snap;
77 
78  llc = (llc_header_t *) (eth + 1);
79  snap = (snap_header_t *) (llc + 1);
80 
81  return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
82  ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
83  (snap->protocol == htons (0x2000)) &&
84  (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
85  (snap->oui[2] == 0x0C)));
86 }
87 
88 static inline u32
90  vlib_buffer_t * b, u32 bond_sw_if_index)
91 {
92  u16 *ethertype_p, ethertype;
95 
96  ethertype = clib_mem_unaligned (&eth->type, u16);
97  if (!ethernet_frame_is_tagged (ntohs (ethertype)))
98  {
99  // Let some layer2 packets pass through.
100  if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
101  && !packet_is_cdp (eth)
102  && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
103  {
104  /* Change the physical interface to bond interface */
105  vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
106  return 1;
107  }
108  }
109  else
110  {
111  vlan = (void *) (eth + 1);
112  ethertype_p = &vlan->type;
113  ethertype = clib_mem_unaligned (ethertype_p, u16);
114  if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
115  {
116  vlan++;
117  ethertype_p = &vlan->type;
118  }
119  ethertype = clib_mem_unaligned (ethertype_p, u16);
120  if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
121  && (ethertype != htons (ETHERNET_TYPE_CDP))
122  && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
123  {
124  /* Change the physical interface to bond interface */
125  vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
126  return 1;
127  }
128  }
129 
130  vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
131  return 0;
132 }
133 
134 static inline void
136  u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
137  u32 packet_count,
138  u32 * bond_sw_if_index, vlib_buffer_t * b,
139  u32 * next_index, vlib_error_t * error)
140 {
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  if (packet_count)
150  VNET_INTERFACE_COUNTER_RX, thread_index,
151  *last_slave_sw_if_index, packet_count);
152 
153  *last_slave_sw_if_index = slave_sw_if_index;
154  *next_index = BOND_INPUT_NEXT_DROP;
155 
156  sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
157  ASSERT (sif);
158 
160 
161  ASSERT (bif);
162  ASSERT (vec_len (bif->slaves));
163 
164  if (PREDICT_TRUE (bif->admin_up == 0))
165  {
166  *bond_sw_if_index = slave_sw_if_index;
167  *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
168  }
169 
170  *bond_sw_if_index = bif->sw_if_index;
171  *error = 0;
172  vnet_feature_next ( /* not used */ 0, next_index, b);
173 }
174 
176  vlib_node_runtime_t * node,
177  vlib_frame_t * frame)
178 {
180  u32 *from, n_left;
181  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
182  u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
183  u16 nexts[VLIB_FRAME_SIZE], *next;
184  u32 last_slave_sw_if_index = ~0;
185  u32 bond_sw_if_index = 0;
186  vlib_error_t error = 0;
187  u32 next_index = 0;
188  u32 cnt = 0;
189 
190  /* Vector of buffer / pkt indices we're supposed to process */
191  from = vlib_frame_vector_args (frame);
192 
193  /* Number of buffers / pkts */
194  n_left = frame->n_vectors;
195 
196  vlib_get_buffers (vm, from, bufs, n_left);
197 
198  b = bufs;
199  next = nexts;
200  sw_if_index = sw_if_indices;
201 
202  while (n_left >= 4)
203  {
204  u32 x = 0;
205  /* Prefetch next iteration */
206  if (PREDICT_TRUE (n_left >= 16))
207  {
209  CLIB_CACHE_LINE_BYTES, LOAD);
211  CLIB_CACHE_LINE_BYTES, LOAD);
213  CLIB_CACHE_LINE_BYTES, LOAD);
215  CLIB_CACHE_LINE_BYTES, LOAD);
216 
217  vlib_prefetch_buffer_header (b[12], LOAD);
218  vlib_prefetch_buffer_header (b[13], LOAD);
219  vlib_prefetch_buffer_header (b[14], LOAD);
220  vlib_prefetch_buffer_header (b[15], LOAD);
221  }
222 
223  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
224  sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
225  sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
226  sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
227 
228  x |= sw_if_index[0] ^ last_slave_sw_if_index;
229  x |= sw_if_index[1] ^ last_slave_sw_if_index;
230  x |= sw_if_index[2] ^ last_slave_sw_if_index;
231  x |= sw_if_index[3] ^ last_slave_sw_if_index;
232 
233  if (PREDICT_TRUE (x == 0))
234  {
235  next[0] = next[1] = next[2] = next[3] = next_index;
236  if (next_index == BOND_INPUT_NEXT_DROP)
237  {
238  b[0]->error = error;
239  b[1]->error = error;
240  b[2]->error = error;
241  b[3]->error = error;
242  }
243  else
244  {
245  cnt +=
246  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
247  cnt +=
248  bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
249  cnt +=
250  bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
251  cnt +=
252  bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
253  }
254  }
255  else
256  {
257 
258  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
259  cnt, &bond_sw_if_index, b[0], &next_index,
260  &error);
261  next[0] = next_index;
262  if (next_index == BOND_INPUT_NEXT_DROP)
263  b[0]->error = error;
264  else
265  cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
266 
267  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
268  cnt, &bond_sw_if_index, b[1], &next_index,
269  &error);
270  next[1] = next_index;
271  if (next_index == BOND_INPUT_NEXT_DROP)
272  b[1]->error = error;
273  else
274  cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
275 
276  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
277  cnt, &bond_sw_if_index, b[2], &next_index,
278  &error);
279  next[2] = next_index;
280  if (next_index == BOND_INPUT_NEXT_DROP)
281  b[2]->error = error;
282  else
283  cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
284 
285  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
286  cnt, &bond_sw_if_index, b[3], &next_index,
287  &error);
288  next[3] = next_index;
289  if (next_index == BOND_INPUT_NEXT_DROP)
290  b[3]->error = error;
291  else
292  cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
293  }
294 
299 
300  /* next */
301  n_left -= 4;
302  b += 4;
303  sw_if_index += 4;
304  next += 4;
305  }
306 
307  while (n_left)
308  {
309  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
310  bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
311  cnt, &bond_sw_if_index, b[0], &next_index, &error);
312  next[0] = next_index;
313  if (next_index == BOND_INPUT_NEXT_DROP)
314  b[0]->error = error;
315  else
316  bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
317 
319 
320  /* next */
321  n_left -= 1;
322  b += 1;
323  sw_if_index += 1;
324  next += 1;
325  }
326 
327  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
328  {
329  n_left = frame->n_vectors; /* number of packets to process */
330  b = bufs;
331  sw_if_index = sw_if_indices;
333 
334  while (n_left)
335  {
336  if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
337  {
338  t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
339  t0->sw_if_index = sw_if_index[0];
341  sizeof (ethernet_header_t));
342  t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
343  }
344  /* next */
345  n_left--;
346  b++;
347  sw_if_index++;
348  }
349  }
350 
351  /* increase rx counters */
354  VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
355 
356  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
358  BOND_INPUT_ERROR_NONE, frame->n_vectors);
359 
360  return frame->n_vectors;
361 }
362 
363 #ifndef CLIB_MARCH_VARIANT
364 static clib_error_t *
366 {
367  return 0;
368 }
369 
370 /* *INDENT-OFF* */
372  .name = "bond-input",
373  .vector_size = sizeof (u32),
374  .format_buffer = format_ethernet_header_with_length,
375  .format_trace = format_bond_input_trace,
376  .type = VLIB_NODE_TYPE_INTERNAL,
377  .n_errors = BOND_INPUT_N_ERROR,
378  .error_strings = bond_input_error_strings,
379  .n_next_nodes = BOND_INPUT_N_NEXT,
380  .next_nodes =
381  {
382  [BOND_INPUT_NEXT_DROP] = "error-drop"
383  }
384 };
385 
387 
388 VNET_FEATURE_INIT (bond_input, static) =
389 {
390  .arc_name = "device-input",
391  .node_name = "bond-input",
392  .runs_before = VNET_FEATURES ("ethernet-input"),
393 };
394 /* *INDENT-ON* */
395 
396 static clib_error_t *
398 {
399  bond_main_t *bm = &bond_main;
400  slave_if_t *sif;
401  vlib_main_t *vm = bm->vlib_main;
402 
403  sif = bond_get_slave_by_sw_if_index (sw_if_index);
404  if (sif)
405  {
407  if (sif->port_enabled == 0)
408  {
409  if (sif->lacp_enabled == 0)
410  {
412  }
413  }
414  else
415  {
416  if (sif->lacp_enabled == 0)
417  {
419  }
420  }
421  }
422 
423  return 0;
424 }
425 
427 
428 static clib_error_t *
430 {
431  bond_main_t *bm = &bond_main;
432  slave_if_t *sif;
434  vlib_main_t *vm = bm->vlib_main;
435 
436  sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
438  if (sif)
439  {
440  if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
441  {
442  if (sif->lacp_enabled == 0)
443  {
445  }
446  }
447  else
448  {
449  if (sif->lacp_enabled == 0)
450  {
452  }
453  }
454  }
455 
456  return 0;
457 }
458 
460 #endif
461 
462 /*
463  * fd.io coding-style-patch-verification: ON
464  *
465  * Local Variables:
466  * eval: (c-set-style "gnu")
467  * End:
468  */
#define foreach_bond_input_error
Definition: node.c:26
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(bond_sw_interface_up_down)
#define CLIB_UNUSED(x)
Definition: clib.h:79
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:89
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
static clib_error_t * bond_input_init(vlib_main_t *vm)
Definition: node.c:365
vnet_interface_main_t interface_main
Definition: vnet.h:56
#define PREDICT_TRUE(x)
Definition: clib.h:106
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
u8 src_address[6]
Definition: packet.h:56
u32 thread_index
Definition: main.h:176
u8 src_sap
Definition: llc.h:82
u16 vlib_error_t
Definition: error.h:44
bond_main_t bond_main
Definition: node.c:24
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
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:79
#define VLIB_NODE_FN(node)
Definition: node.h:173
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:458
bond_input_error_t
Definition: node.c:31
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:451
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:371
#define static_always_inline
Definition: clib.h:93
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
u8 dst_address[6]
Definition: packet.h:55
u32 sw_if_index
Definition: node.h:157
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:184
bond_output_next_t
Definition: node.c:66
vlib_main_t * vlib_main
Definition: node.h:304
unsigned int u32
Definition: types.h:88
#define VLIB_FRAME_SIZE
Definition: node.h:364
static clib_error_t * bond_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: node.c:397
u8 admin_up
Definition: node.h:148
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:202
#define PREDICT_FALSE(x)
Definition: clib.h:105
vnet_main_t vnet_main
Definition: misc.c:43
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:810
u32 node_index
Node index.
Definition: node.h:473
static_always_inline void vnet_feature_next(u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:237
static u8 * format_bond_input_trace(u8 *s, va_list *args)
Definition: node.c:47
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:135
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1168
u32 flags
Definition: vhost_user.h:110
u8 * format_ethernet_header_with_length(u8 *s, va_list *args)
Definition: format.c:91
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
u32 * slaves
Definition: node.h:160
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:77
vlib_main_t * vm
Definition: buffer.c:294
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
ethernet_header_t ethernet
Definition: node.h:318
#define clib_memcpy(a, b, c)
Definition: string.h:75
void bond_disable_collecting_distributing(vlib_main_t *vm, slave_if_t *sif)
Definition: cli.c:25
VNET_FEATURE_INIT(bond_input, static)
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:661
#define ASSERT(truth)
static_always_inline u8 packet_is_cdp(ethernet_header_t *eth)
Definition: node.c:73
static bond_if_t * bond_get_master_by_dev_instance(u32 dev_instance)
Definition: node.h:438
u32 bif_dev_instance
Definition: node.h:279
static_always_inline int ethernet_frame_is_tagged(u16 type)
Definition: ethernet.h:85
#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:40
#define VNET_FEATURES(...)
Definition: feature.h:391
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:236
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:546
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
static clib_error_t * bond_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: node.c:429
#define vnet_buffer(b)
Definition: buffer.h:360
u8 port_enabled
Definition: node.h:230
static slave_if_t * bond_get_slave_by_sw_if_index(u32 sw_if_index)
Definition: node.h:446
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:128
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:295
u32 bond_sw_if_index
Definition: node.h:320
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
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:135