FD.io VPP  v18.10-32-g1161dda
Vector Packet Processing
l2e.c
Go to the documentation of this file.
1 /*
2  * l2_emulation.h : Extract L3 packets from the L2 input and feed
3  * them into the L3 path.
4  *
5  * Copyright (c) 2013 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <plugins/l2e/l2e.h>
20 #include <vnet/l2/l2_input.h>
21 #include <vnet/l2/feat_bitmap.h>
22 
23 /**
24  * Grouping of global data for the L2 emulation feature
25  */
26 typedef struct l2_emulation_main_t_
27 {
28  /**
29  * Next nodes for L2 output features
30  */
33 
35 
36 /**
37  * Per-interface L2 configuration
38  */
39 typedef struct l2_emulation_t_
40 {
41  /**
42  * Enabled or Disabled.
43  * this is required since one L3 protocl can be enabled, but others not
44  */
47 
48 /**
49  * A zero'd out struct we can use in the vec_validate
50  */
51 static const l2_emulation_t ezero = { };
52 
53 /**
54  * Per-interface vector of emulation configs
55  */
57 
58 void
60 {
61  vec_validate_init_empty (l2_emulations, sw_if_index, ezero);
62 
63  l2_emulation_t *l23e = &l2_emulations[sw_if_index];
64 
65  l23e->enabled = 1;
66 
67  /*
68  * L3 enable the interface - using IP unnumbered from the control
69  * plane may not be possible since there may be no BVI interface
70  * to which to unnumber
71  */
72  ip4_sw_interface_enable_disable (sw_if_index, 1);
73  ip6_sw_interface_enable_disable (sw_if_index, 1);
74 
75  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_L2_EMULATION, 1);
76 }
77 
78 
79 void
81 {
82  if (vec_len (l2_emulations) >= sw_if_index)
83  {
84  l2_emulation_t *l23e = &l2_emulations[sw_if_index];
85  memset (l23e, 0, sizeof (*l23e));
86 
87  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_L2_EMULATION, 0);
88  ip4_sw_interface_enable_disable (sw_if_index, 0);
89  ip6_sw_interface_enable_disable (sw_if_index, 0);
90  }
91 }
92 
93 static clib_error_t *
95  u32 sw_if_index, u32 is_add)
96 {
97  if (is_add)
98  {
99  vec_validate_init_empty (l2_emulations, sw_if_index, ezero);
100  }
101 
102  return (NULL);
103 }
104 
106 
107 static clib_error_t *
109  unformat_input_t * input, vlib_cli_command_t * cmd)
110 {
111  vnet_main_t *vnm = vnet_get_main ();
112  u32 sw_if_index = ~0;
113  u8 enable = 1;
114 
116  {
117  if (unformat (input, "%U", unformat_vnet_sw_interface,
118  vnm, &sw_if_index))
119  ;
120  else if (unformat (input, "enable"))
121  enable = 1;
122  else if (unformat (input, "disable"))
123  enable = 0;
124  else
125  break;
126  }
127 
128  if (~0 == sw_if_index)
129  return clib_error_return (0, "interface must be specified");
130 
131  if (enable)
132  l2_emulation_enable (sw_if_index);
133  else
134  l2_emulation_disable (sw_if_index);
135 
136  return (NULL);
137 }
138 
139 /*?
140  * Configure l2 emulation.
141  * When the interface is in L2 mode, configure the extraction of L3
142  * packets out of the L2 path and into the L3 path.
143  *
144  * @cliexpar
145  * @cliexstart{set interface l2 input l2-emulation <interface-name> [disable]}
146  * @cliexend
147  ?*/
148 /* *INDENT-OFF* */
149 VLIB_CLI_COMMAND (l2_emulation_cli_node, static) = {
150  .path = "set interface l2 l2-emulation",
151  .short_help =
152  "set interface l2 l2-emulation <interface-name> [disable|enable]\n",
153  .function = l2_emulation_cli,
154 };
155 /* *INDENT-ON* */
156 
157 static clib_error_t *
159  unformat_input_t * input, vlib_cli_command_t * cmd)
160 {
161  vnet_main_t *vnm = vnet_get_main ();
162  l2_emulation_t *l23e;
164 
165  vec_foreach_index (sw_if_index, l2_emulations)
166  {
167  l23e = &l2_emulations[sw_if_index];
168  if (l23e->enabled)
169  {
170  vlib_cli_output (vm, "%U\n",
171  format_vnet_sw_if_index_name, vnm, sw_if_index);
172  }
173  }
174  return (NULL);
175 }
176 
177 /*?
178  * Show l2 emulation.
179  * When the interface is in L2 mode, configure the extraction of L3
180  * packets out of the L2 path and into the L3 path.
181  *
182  * @cliexpar
183  * @cliexstart{show interface l2 l2-emulation}
184  * @cliexend
185  ?*/
186 /* *INDENT-OFF* */
187 VLIB_CLI_COMMAND (l2_emulation_show_node, static) = {
188  .path = "show interface l2 l2-emulation",
189  .short_help = "show interface l2 l2-emulation\n",
190  .function = l2_emulation_show,
191 };
192 /* *INDENT-ON* */
193 
194 #define foreach_l2_emulation \
195  _(IP4, "Extract IPv4") \
196  _(IP6, "Extract IPv6")
197 
198 typedef enum
199 {
200 #define _(sym,str) L2_EMULATION_ERROR_##sym,
202 #undef _
205 
206 static char *l2_emulation_error_strings[] = {
207 #define _(sym,string) string,
209 #undef _
210 };
211 
212 typedef enum
213 {
214 #define _(sym,str) L2_EMULATION_NEXT_##sym,
216 #undef _
219 
220 /**
221  * per-packet trace data
222  */
223 typedef struct l2_emulation_trace_t_
224 {
225  /* per-pkt trace data */
228 
229 static uword
231  vlib_node_runtime_t * node, vlib_frame_t * frame)
232 {
234  u32 n_left_from, *from, *to_next;
235  l2_emulation_next_t next_index;
236  u32 ip4_hits = 0;
237  u32 ip6_hits = 0;
238 
239  next_index = 0;
240  n_left_from = frame->n_vectors;
241  from = vlib_frame_vector_args (frame);
242 
243  while (n_left_from > 0)
244  {
245  u32 n_left_to_next;
246 
247  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
248  while (n_left_from >= 4 && n_left_to_next >= 2)
249  {
250  vlib_buffer_t *b0, *b1;
251  u32 sw_if_index0, sw_if_index1;
252  u16 ether_type0, ether_type1;
253  u32 next0 = ~0, next1 = ~0;
254  u8 l2_len0, l2_len1;
255  u32 bi0, bi1;
256  u8 *h0, *h1;
257 
258  bi0 = to_next[0] = from[0];
259  bi1 = to_next[1] = from[1];
260 
261  from += 2;
262  n_left_from -= 2;
263  to_next += 2;
264  n_left_to_next -= 2;
265 
266  b0 = vlib_get_buffer (vm, bi0);
267  b1 = vlib_get_buffer (vm, bi1);
268  l2_len0 = vnet_buffer (b0)->l2.l2_len;
269  l2_len1 = vnet_buffer (b1)->l2.l2_len;
270 
271  h0 = vlib_buffer_get_current (b0);
272  h1 = vlib_buffer_get_current (b1);
273 
274  ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
275  ether_type1 = clib_net_to_host_u16 (*(u16 *) (h1 + l2_len1 - 2));
276  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
277  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
278 
279  /*
280  * only extract unicast
281  */
282  if (PREDICT_TRUE (!(h0[0] & 0x1)))
283  {
284  switch (ether_type0)
285  {
286  case ETHERNET_TYPE_IP4:
287  ASSERT (l2_emulations[sw_if_index0].enabled);
288  ++ip4_hits;
289  next0 = L2_EMULATION_NEXT_IP4;
290  vlib_buffer_advance (b0, l2_len0);
291  break;
292  case ETHERNET_TYPE_IP6:
293  ASSERT (l2_emulations[sw_if_index0].enabled);
294  ++ip6_hits;
295  next0 = L2_EMULATION_NEXT_IP6;
296  vlib_buffer_advance (b0, l2_len0);
297  default:
298  break;
299  }
300  }
301  if (PREDICT_TRUE (!(h1[0] & 0x1)))
302  {
303  switch (ether_type1)
304  {
305  case ETHERNET_TYPE_IP4:
306  ASSERT (l2_emulations[sw_if_index1].enabled);
307  ++ip4_hits;
308  next1 = L2_EMULATION_NEXT_IP4;
309  vlib_buffer_advance (b1, l2_len1);
310  break;
311  case ETHERNET_TYPE_IP6:
312  ASSERT (l2_emulations[sw_if_index1].enabled);
313  ++ip6_hits;
314  next1 = L2_EMULATION_NEXT_IP6;
315  vlib_buffer_advance (b1, l2_len1);
316  default:
317  break;
318  }
319  }
321  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
322  {
324  vlib_add_trace (vm, node, b0, sizeof (*t));
325  t->extracted = (next0 != ~0);
326  }
328  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
329  {
331  vlib_add_trace (vm, node, b1, sizeof (*t));
332  t->extracted = (next1 != ~0);
333  }
334 
335  /* Determine the next node and remove ourself from bitmap */
336  if (PREDICT_TRUE (next0 == ~0))
337  next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
338  L2INPUT_FEAT_L2_EMULATION);
339 
340  /* Determine the next node and remove ourself from bitmap */
341  if (PREDICT_TRUE (next1 == ~0))
342  next1 = vnet_l2_feature_next (b1, em->l2_input_feat_next,
343  L2INPUT_FEAT_L2_EMULATION);
344 
345  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
346  to_next, n_left_to_next,
347  bi0, bi1, next0, next1);
348  }
349  while (n_left_from > 0 && n_left_to_next > 0)
350  {
351  vlib_buffer_t *b0;
352  u32 sw_if_index0;
353  u16 ether_type0;
354  u32 next0 = ~0;
355  u8 l2_len0;
356  u32 bi0;
357  u8 *h0;
358 
359  bi0 = from[0];
360  to_next[0] = bi0;
361  from += 1;
362  to_next += 1;
363  n_left_from -= 1;
364  n_left_to_next -= 1;
365 
366  b0 = vlib_get_buffer (vm, bi0);
367  l2_len0 = vnet_buffer (b0)->l2.l2_len;
368 
369  h0 = vlib_buffer_get_current (b0);
370  ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
371  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
372 
373  /*
374  * only extract unicast
375  */
376  if (PREDICT_TRUE (!(h0[0] & 0x1)))
377  {
378  switch (ether_type0)
379  {
380  case ETHERNET_TYPE_IP4:
381  ASSERT (l2_emulations[sw_if_index0].enabled);
382  ++ip4_hits;
383  next0 = L2_EMULATION_NEXT_IP4;
384  vlib_buffer_advance (b0, l2_len0);
385  break;
386  case ETHERNET_TYPE_IP6:
387  ASSERT (l2_emulations[sw_if_index0].enabled);
388  ++ip6_hits;
389  next0 = L2_EMULATION_NEXT_IP6;
390  vlib_buffer_advance (b0, l2_len0);
391  default:
392  break;
393  }
394  }
395 
397  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
398  {
400  vlib_add_trace (vm, node, b0, sizeof (*t));
401  t->extracted = (next0 != ~0);
402  }
403 
404  /* Determine the next node and remove ourself from bitmap */
405  if (PREDICT_TRUE (next0 == ~0))
406  next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
407  L2INPUT_FEAT_L2_EMULATION);
408 
409  /* verify speculative enqueue, maybe switch current next frame */
410  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
411  to_next, n_left_to_next,
412  bi0, next0);
413  }
414 
415  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
416  }
417 
419  L2_EMULATION_ERROR_IP4, ip4_hits);
421  L2_EMULATION_ERROR_IP6, ip6_hits);
422 
423  return frame->n_vectors;
424 }
425 
426 /* packet trace format function */
427 static u8 *
428 format_l2_emulation_trace (u8 * s, va_list * args)
429 {
430  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
431  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
432  l2_emulation_trace_t *t = va_arg (*args, l2_emulation_trace_t *);
433 
434  s = format (s, "l2-emulation: %s", (t->extracted ? "yes" : "no"));
435 
436  return s;
437 }
438 
439 /* *INDENT-OFF* */
441  .function = l2_emulation_node_fn,
442  .name = "l2-emulation",
443  .vector_size = sizeof (u32),
444  .format_trace = format_l2_emulation_trace,
445  .type = VLIB_NODE_TYPE_INTERNAL,
446 
448  .error_strings = l2_emulation_error_strings,
449 
450  .n_next_nodes = L2_EMULATION_N_NEXT,
451 
452  /* edit / add dispositions here */
453  .next_nodes = {
454  [L2_EMULATION_NEXT_IP4] = "ip4-input",
455  [L2_EMULATION_NEXT_IP6] = "ip6-input",
456  },
457 };
458 /* *INDENT-ON* */
459 
461 
462 
463 static clib_error_t *
465 {
467 
468  /* Initialize the feature next-node indexes */
470  l2_emulation_node.index,
473  em->l2_input_feat_next);
474 
475  return 0;
476 }
477 
479 
480 /*
481  * fd.io coding-style-patch-verification: ON
482  *
483  * Local Variables:
484  * eval: (c-set-style "gnu")
485  * End:
486  */
#define vec_foreach_index(var, v)
Iterate over vector indices.
#define CLIB_UNUSED(x)
Definition: clib.h:81
vlib_node_registration_t l2_emulation_node
(constructor) VLIB_REGISTER_NODE (l2_emulation_node)
Definition: l2e.c:440
struct l2_emulation_main_t_ l2_emulation_main_t
Grouping of global data for the L2 emulation feature.
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
#define PREDICT_TRUE(x)
Definition: clib.h:108
static clib_error_t * l2_emulation_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: l2e.c:94
#define NULL
Definition: clib.h:57
#define foreach_l2_emulation
Definition: l2e.c:194
Grouping of global data for the L2 emulation feature.
Definition: l2e.c:26
u32 l2_input_feat_next[32]
Next nodes for L2 output features.
Definition: l2e.c:31
void l2_emulation_disable(u32 sw_if_index)
Definition: l2e.c:80
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static char * l2_emulation_error_strings[]
Definition: l2e.c:206
unformat_function_t unformat_vnet_sw_interface
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(l2_emulation_interface_add_del)
VLIB_NODE_FUNCTION_MULTIARCH(l2_emulation_node, l2_emulation_node_fn)
per-packet trace data
Definition: l2e.c:223
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static u32 vnet_l2_feature_next(vlib_buffer_t *b, u32 *next_nodes, u32 feat_bit)
Return the graph node index for the feature corresponding to the next set bit after clearing the curr...
Definition: feat_bitmap.h:94
memset(h->entries, 0, sizeof(h->entries[0])*entries)
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
u32 sw_if_index
Definition: vxlan_gbp.api:39
l2_emulation_next_t
Definition: l2e.c:212
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
struct l2_emulation_trace_t_ l2_emulation_trace_t
per-packet trace data
void ip4_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip4_forward.c:524
static u8 * format_l2_emulation_trace(u8 *s, va_list *args)
Definition: l2e.c:428
static l2_emulation_main_t l2_emulation_main
Definition: l2e.c:34
struct _unformat_input_t unformat_input_t
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
u32 node_index
Node index.
Definition: node.h:494
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
struct l2_emulation_t_ l2_emulation_t
Per-interface L2 configuration.
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1176
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u16 n_vectors
Definition: node.h:401
vlib_main_t * vm
Definition: buffer.c:294
static void feat_bitmap_init_next_nodes(vlib_main_t *vm, u32 node_index, u32 num_features, char **feat_names, u32 *next_nodes)
Initialize the feature next-node indexes of a graph node.
Definition: feat_bitmap.h:43
#define ARRAY_LEN(x)
Definition: clib.h:61
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:455
char ** l2input_get_feat_names(void)
Return an array of strings containing graph node names of each feature.
Definition: l2_input.c:60
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
static clib_error_t * l2_emulation_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l2e.c:108
u8 enabled
Enabled or Disabled.
Definition: l2e.c:45
l2_emulation_t * l2_emulations
Per-interface vector of emulation configs.
Definition: l2e.c:56
#define ASSERT(truth)
void l2_emulation_enable(u32 sw_if_index)
L2 Emulation is a feautre that is applied to L2 ports to &#39;extract&#39; IP packets from the L2 path and in...
Definition: l2e.c:59
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:218
static uword l2_emulation_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2e.c:230
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
u32 l2input_intf_bitmap_enable(u32 sw_if_index, u32 feature_bitmap, u32 enable)
Enable (or disable) the feature in the bitmap for the given interface.
Definition: l2_input.c:520
Per-interface L2 configuration.
Definition: l2e.c:39
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
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:267
static clib_error_t * l2_emulation_init(vlib_main_t *vm)
Definition: l2e.c:464
#define vnet_buffer(b)
Definition: buffer.h:344
l2_emulation_error_t
Definition: l2e.c:198
u16 flags
Copy of main node flags.
Definition: node.h:507
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:310
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:116
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:725
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:58
void ip6_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip6_forward.c:142
static clib_error_t * l2_emulation_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l2e.c:158
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
Definition: defs.h:46
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170