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