FD.io VPP  v18.07.1-19-g511ce25
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 
22 /**
23  * Grouping of global data for the L2 emulation feature
24  */
25 typedef struct l2_emulation_main_t_
26 {
27  /**
28  * Next nodes for L2 output features
29  */
32 
34 
35 /**
36  * Per-interface L2 configuration
37  */
38 typedef struct l2_emulation_t_
39 {
40  /**
41  * Enabled or Disabled.
42  * this is required since one L3 protocl can be enabled, but others not
43  */
46 
47 /**
48  * A zero'd out struct we can use in the vec_validate
49  */
50 static const l2_emulation_t ezero = { };
51 
52 /**
53  * Per-interface vector of emulation configs
54  */
56 
57 void
58 l2_emulation_enable (u32 sw_if_index)
59 {
60  vec_validate_init_empty (l2_emulations, sw_if_index, ezero);
61 
62  l2_emulation_t *l23e = &l2_emulations[sw_if_index];
63 
64  l23e->enabled = 1;
65 
66  /*
67  * L3 enable the interface - using IP unnumbered from the control
68  * plane may not be possible since there may be no BVI interface
69  * to which to unnumber
70  */
71  ip4_sw_interface_enable_disable (sw_if_index, 1);
72  ip6_sw_interface_enable_disable (sw_if_index, 1);
73 
74  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_L2_EMULATION, 1);
75 }
76 
77 
78 void
80 {
81  if (vec_len (l2_emulations) >= sw_if_index)
82  {
83  l2_emulation_t *l23e = &l2_emulations[sw_if_index];
84  memset (l23e, 0, sizeof (*l23e));
85 
86  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_L2_EMULATION, 0);
87  ip4_sw_interface_enable_disable (sw_if_index, 0);
88  ip6_sw_interface_enable_disable (sw_if_index, 0);
89  }
90 }
91 
92 static clib_error_t *
94  u32 sw_if_index, u32 is_add)
95 {
96  if (is_add)
97  {
98  vec_validate_init_empty (l2_emulations, sw_if_index, ezero);
99  }
100 
101  return (NULL);
102 }
103 
105 
106 static clib_error_t *
108  unformat_input_t * input, vlib_cli_command_t * cmd)
109 {
110  vnet_main_t *vnm = vnet_get_main ();
111  u32 sw_if_index = ~0;
112  u8 enable = 1;
113 
115  {
116  if (unformat (input, "%U", unformat_vnet_sw_interface,
117  vnm, &sw_if_index))
118  ;
119  else if (unformat (input, "enable"))
120  enable = 1;
121  else if (unformat (input, "disable"))
122  enable = 0;
123  else
124  break;
125  }
126 
127  if (~0 == sw_if_index)
128  return clib_error_return (0, "interface must be specified");
129 
130  if (enable)
131  l2_emulation_enable (sw_if_index);
132  else
133  l2_emulation_disable (sw_if_index);
134 
135  return (NULL);
136 }
137 
138 /*?
139  * Configure l2 emulation.
140  * When the interface is in L2 mode, configure the extraction of L3
141  * packets out of the L2 path and into the L3 path.
142  *
143  * @cliexpar
144  * @cliexstart{set interface l2 input l2-emulation <interface-name> [disable]}
145  * @cliexend
146  ?*/
147 /* *INDENT-OFF* */
148 VLIB_CLI_COMMAND (l2_emulation_cli_node, static) = {
149  .path = "set interface l2 l2-emulation",
150  .short_help =
151  "set interface l2 l2-emulation <interface-name> [disable|enable]\n",
152  .function = l2_emulation_cli,
153 };
154 /* *INDENT-ON* */
155 
156 static clib_error_t *
158  unformat_input_t * input, vlib_cli_command_t * cmd)
159 {
160  vnet_main_t *vnm = vnet_get_main ();
161  l2_emulation_t *l23e;
162  u32 sw_if_index;
163 
164  vec_foreach_index (sw_if_index, l2_emulations)
165  {
166  l23e = &l2_emulations[sw_if_index];
167  if (l23e->enabled)
168  {
169  vlib_cli_output (vm, "%U\n",
170  format_vnet_sw_if_index_name, vnm, sw_if_index);
171  }
172  }
173  return (NULL);
174 }
175 
176 /*?
177  * Show l2 emulation.
178  * When the interface is in L2 mode, configure the extraction of L3
179  * packets out of the L2 path and into the L3 path.
180  *
181  * @cliexpar
182  * @cliexstart{show interface l2 l2-emulation}
183  * @cliexend
184  ?*/
185 /* *INDENT-OFF* */
186 VLIB_CLI_COMMAND (l2_emulation_show_node, static) = {
187  .path = "show interface l2 l2-emulation",
188  .short_help = "show interface l2 l2-emulation\n",
189  .function = l2_emulation_show,
190 };
191 /* *INDENT-ON* */
192 
193 #define foreach_l2_emulation \
194  _(IP4, "Extract IPv4") \
195  _(IP6, "Extract IPv6")
196 
197 typedef enum
198 {
199 #define _(sym,str) L2_EMULATION_ERROR_##sym,
201 #undef _
204 
205 static char *l2_emulation_error_strings[] = {
206 #define _(sym,string) string,
208 #undef _
209 };
210 
211 typedef enum
212 {
213 #define _(sym,str) L2_EMULATION_NEXT_##sym,
215 #undef _
218 
219 /**
220  * per-packet trace data
221  */
222 typedef struct l2_emulation_trace_t_
223 {
224  /* per-pkt trace data */
227 
228 static uword
230  vlib_node_runtime_t * node, vlib_frame_t * frame)
231 {
233  u32 n_left_from, *from, *to_next;
234  l2_emulation_next_t next_index;
235  u32 ip4_hits = 0;
236  u32 ip6_hits = 0;
237 
238  next_index = 0;
239  n_left_from = frame->n_vectors;
240  from = vlib_frame_vector_args (frame);
241 
242  while (n_left_from > 0)
243  {
244  u32 n_left_to_next;
245 
246  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
247  while (n_left_from >= 4 && n_left_to_next >= 2)
248  {
249  vlib_buffer_t *b0, *b1;
250  u32 sw_if_index0, sw_if_index1;
251  u16 ether_type0, ether_type1;
252  u32 next0 = ~0, next1 = ~0;
253  u8 l2_len0, l2_len1;
254  u32 bi0, bi1;
255  u8 *h0, *h1;
256 
257  bi0 = to_next[0] = from[0];
258  bi1 = to_next[1] = from[1];
259 
260  from += 2;
261  n_left_from -= 2;
262  to_next += 2;
263  n_left_to_next -= 2;
264 
265  b0 = vlib_get_buffer (vm, bi0);
266  b1 = vlib_get_buffer (vm, bi1);
267  l2_len0 = vnet_buffer (b0)->l2.l2_len;
268  l2_len1 = vnet_buffer (b1)->l2.l2_len;
269 
270  h0 = vlib_buffer_get_current (b0);
271  h1 = vlib_buffer_get_current (b1);
272 
273  ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
274  ether_type1 = clib_net_to_host_u16 (*(u16 *) (h1 + l2_len1 - 2));
275  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
276  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
277 
278  /*
279  * only extract unicast
280  */
281  if (PREDICT_TRUE (!(h0[0] & 0x1)))
282  {
283  switch (ether_type0)
284  {
285  case ETHERNET_TYPE_IP4:
286  ASSERT (l2_emulations[sw_if_index0].enabled);
287  ++ip4_hits;
288  next0 = L2_EMULATION_NEXT_IP4;
289  vlib_buffer_advance (b0, l2_len0);
290  break;
291  case ETHERNET_TYPE_IP6:
292  ASSERT (l2_emulations[sw_if_index0].enabled);
293  ++ip6_hits;
294  next0 = L2_EMULATION_NEXT_IP6;
295  vlib_buffer_advance (b0, l2_len0);
296  default:
297  break;
298  }
299  }
300  if (PREDICT_TRUE (!(h1[0] & 0x1)))
301  {
302  switch (ether_type1)
303  {
304  case ETHERNET_TYPE_IP4:
305  ASSERT (l2_emulations[sw_if_index1].enabled);
306  ++ip4_hits;
307  next1 = L2_EMULATION_NEXT_IP4;
308  vlib_buffer_advance (b1, l2_len1);
309  break;
310  case ETHERNET_TYPE_IP6:
311  ASSERT (l2_emulations[sw_if_index1].enabled);
312  ++ip6_hits;
313  next1 = L2_EMULATION_NEXT_IP6;
314  vlib_buffer_advance (b1, l2_len1);
315  default:
316  break;
317  }
318  }
320  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
321  {
323  vlib_add_trace (vm, node, b0, sizeof (*t));
324  t->extracted = (next0 != ~0);
325  }
327  && (b1->flags & VLIB_BUFFER_IS_TRACED)))
328  {
330  vlib_add_trace (vm, node, b1, sizeof (*t));
331  t->extracted = (next1 != ~0);
332  }
333 
334  /* Determine the next node and remove ourself from bitmap */
335  if (PREDICT_TRUE (next0 == ~0))
336  next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
337  L2INPUT_FEAT_L2_EMULATION);
338 
339  /* Determine the next node and remove ourself from bitmap */
340  if (PREDICT_TRUE (next1 == ~0))
341  next1 = vnet_l2_feature_next (b1, em->l2_input_feat_next,
342  L2INPUT_FEAT_L2_EMULATION);
343 
344  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
345  to_next, n_left_to_next,
346  bi0, bi1, next0, next1);
347  }
348  while (n_left_from > 0 && n_left_to_next > 0)
349  {
350  vlib_buffer_t *b0;
351  u32 sw_if_index0;
352  u16 ether_type0;
353  u32 next0 = ~0;
354  u8 l2_len0;
355  u32 bi0;
356  u8 *h0;
357 
358  bi0 = from[0];
359  to_next[0] = bi0;
360  from += 1;
361  to_next += 1;
362  n_left_from -= 1;
363  n_left_to_next -= 1;
364 
365  b0 = vlib_get_buffer (vm, bi0);
366  l2_len0 = vnet_buffer (b0)->l2.l2_len;
367 
368  h0 = vlib_buffer_get_current (b0);
369  ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
370  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
371 
372  /*
373  * only extract unicast
374  */
375  if (PREDICT_TRUE (!(h0[0] & 0x1)))
376  {
377  switch (ether_type0)
378  {
379  case ETHERNET_TYPE_IP4:
380  ASSERT (l2_emulations[sw_if_index0].enabled);
381  ++ip4_hits;
382  next0 = L2_EMULATION_NEXT_IP4;
383  vlib_buffer_advance (b0, l2_len0);
384  break;
385  case ETHERNET_TYPE_IP6:
386  ASSERT (l2_emulations[sw_if_index0].enabled);
387  ++ip6_hits;
388  next0 = L2_EMULATION_NEXT_IP6;
389  vlib_buffer_advance (b0, l2_len0);
390  default:
391  break;
392  }
393  }
394 
396  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
397  {
399  vlib_add_trace (vm, node, b0, sizeof (*t));
400  t->extracted = (next0 != ~0);
401  }
402 
403  /* Determine the next node and remove ourself from bitmap */
404  if (PREDICT_TRUE (next0 == ~0))
405  next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
406  L2INPUT_FEAT_L2_EMULATION);
407 
408  /* verify speculative enqueue, maybe switch current next frame */
409  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
410  to_next, n_left_to_next,
411  bi0, next0);
412  }
413 
414  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
415  }
416 
418  L2_EMULATION_ERROR_IP4, ip4_hits);
420  L2_EMULATION_ERROR_IP6, ip6_hits);
421 
422  return frame->n_vectors;
423 }
424 
425 /* packet trace format function */
426 static u8 *
427 format_l2_emulation_trace (u8 * s, va_list * args)
428 {
429  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
430  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
431  l2_emulation_trace_t *t = va_arg (*args, l2_emulation_trace_t *);
432 
433  s = format (s, "l2-emulation: %s", (t->extracted ? "yes" : "no"));
434 
435  return s;
436 }
437 
438 /* *INDENT-OFF* */
440  .function = l2_emulation_node_fn,
441  .name = "l2-emulation",
442  .vector_size = sizeof (u32),
443  .format_trace = format_l2_emulation_trace,
444  .type = VLIB_NODE_TYPE_INTERNAL,
445 
447  .error_strings = l2_emulation_error_strings,
448 
449  .n_next_nodes = L2_EMULATION_N_NEXT,
450 
451  /* edit / add dispositions here */
452  .next_nodes = {
453  [L2_EMULATION_NEXT_IP4] = "ip4-input",
454  [L2_EMULATION_NEXT_IP6] = "ip6-input",
455  },
456 };
457 /* *INDENT-ON* */
458 
460 
461 
462 static clib_error_t *
464 {
466 
467  /* Initialize the feature next-node indexes */
469  l2_emulation_node.index,
472  em->l2_input_feat_next);
473 
474  return 0;
475 }
476 
478 
479 /*
480  * fd.io coding-style-patch-verification: ON
481  *
482  * Local Variables:
483  * eval: (c-set-style "gnu")
484  * End:
485  */
#define vec_foreach_index(var, v)
Iterate over vector indices.
#define CLIB_UNUSED(x)
Definition: clib.h:79
vlib_node_registration_t l2_emulation_node
(constructor) VLIB_REGISTER_NODE (l2_emulation_node)
Definition: l2e.c:439
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:106
static clib_error_t * l2_emulation_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: l2e.c:93
#define NULL
Definition: clib.h:55
#define foreach_l2_emulation
Definition: l2e.c:193
Grouping of global data for the L2 emulation feature.
Definition: l2e.c:25
u32 l2_input_feat_next[32]
Next nodes for L2 output features.
Definition: l2e.c:30
void l2_emulation_disable(u32 sw_if_index)
Definition: l2e.c:79
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static char * l2_emulation_error_strings[]
Definition: l2e.c:205
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:222
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
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
l2_emulation_next_t
Definition: l2e.c:211
#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:496
static u8 * format_l2_emulation_trace(u8 *s, va_list *args)
Definition: l2e.c:427
static l2_emulation_main_t l2_emulation_main
Definition: l2e.c:33
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:202
#define PREDICT_FALSE(x)
Definition: clib.h:105
u32 node_index
Node index.
Definition: node.h:473
#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:1168
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u16 n_vectors
Definition: node.h:380
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:59
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:454
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:154
static clib_error_t * l2_emulation_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l2e.c:107
u8 enabled
Enabled or Disabled.
Definition: l2e.c:44
l2_emulation_t * l2_emulations
Per-interface vector of emulation configs.
Definition: l2e.c:55
#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:58
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:215
static uword l2_emulation_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2e.c:229
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
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:38
#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:463
#define vnet_buffer(b)
Definition: buffer.h:360
l2_emulation_error_t
Definition: l2e.c:197
u16 flags
Copy of main node flags.
Definition: node.h:486
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:295
#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:111
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:681
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
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:157
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