FD.io VPP  v18.04-17-g3a0d853
Vector Packet Processing
l2_patch.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vlib/vlib.h>
16 #include <vnet/vnet.h>
17 #include <vnet/pg/pg.h>
18 #include <vnet/ethernet/ethernet.h>
19 #include <vnet/feature/feature.h>
20 #include <vppinfra/error.h>
21 
22 typedef struct
23 {
24  /* vector of dispositions, indexed by rx_sw_if_index */
27 
28  /* convenience variables */
32 
33 typedef struct
34 {
38 
39 /* packet trace format function */
40 static u8 *
41 format_l2_patch_trace (u8 * s, va_list * args)
42 {
43  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
44  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
45  l2_patch_trace_t *t = va_arg (*args, l2_patch_trace_t *);
46 
47  s = format (s, "L2_PATCH: rx %d tx %d", t->rx_sw_if_index,
48  t->tx_sw_if_index);
49  return s;
50 }
51 
53 
55 
56 #define foreach_l2_patch_error \
57 _(PATCHED, "L2 patch packets") \
58 _(DROPPED, "L2 patch misconfigured drops")
59 
60 typedef enum
61 {
62 #define _(sym,str) L2_PATCH_ERROR_##sym,
64 #undef _
67 
68 static char *l2_patch_error_strings[] = {
69 #define _(sym,string) string,
71 #undef _
72 };
73 
74 typedef enum
75 {
79 
80 static uword
82  vlib_node_runtime_t * node, vlib_frame_t * frame)
83 {
84  u32 n_left_from, *from, *to_next;
85  l2_patch_next_t next_index;
87  vlib_node_t *n = vlib_get_node (vm, l2_patch_node.index);
88  u32 node_counter_base_index = n->error_heap_index;
89  vlib_error_main_t *em = &vm->error_main;
90 
91  from = vlib_frame_vector_args (frame);
92  n_left_from = frame->n_vectors;
93  next_index = node->cached_next_index;
94 
95  while (n_left_from > 0)
96  {
97  u32 n_left_to_next;
98 
99  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
100 
101  while (n_left_from >= 4 && n_left_to_next >= 2)
102  {
103  u32 bi0, bi1;
104  vlib_buffer_t *b0, *b1;
105  u32 next0, next1;
106  u32 sw_if_index0, sw_if_index1;
107 
108  /* Prefetch next iteration. */
109  {
110  vlib_buffer_t *p2, *p3;
111 
112  p2 = vlib_get_buffer (vm, from[2]);
113  p3 = vlib_get_buffer (vm, from[3]);
114 
115  vlib_prefetch_buffer_header (p2, LOAD);
116  vlib_prefetch_buffer_header (p3, LOAD);
117 
118  /* So stupid / simple, we don't need to prefetch data */
119  }
120 
121  /* speculatively enqueue b0 and b1 to the current next frame */
122  to_next[0] = bi0 = from[0];
123  to_next[1] = bi1 = from[1];
124  from += 2;
125  to_next += 2;
126  n_left_from -= 2;
127  n_left_to_next -= 2;
128 
129  b0 = vlib_get_buffer (vm, bi0);
130  b1 = vlib_get_buffer (vm, bi1);
131 
132  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
133  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
134 
135  ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index0] != ~0);
136  ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0] != ~0);
137  ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index1] != ~0);
138  ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1] != ~0);
139 
140  next0 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index0];
141  next1 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index1];
142  vnet_buffer (b0)->sw_if_index[VLIB_TX] =
143  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0];
144  vnet_buffer (b1)->sw_if_index[VLIB_TX] =
145  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1];
146 
147  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
148  {
149  if (b0->flags & VLIB_BUFFER_IS_TRACED)
150  {
151  l2_patch_trace_t *t =
152  vlib_add_trace (vm, node, b0, sizeof (*t));
153  t->rx_sw_if_index = sw_if_index0;
154  t->tx_sw_if_index =
155  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0];
156  }
157  if (b1->flags & VLIB_BUFFER_IS_TRACED)
158  {
159  l2_patch_trace_t *t =
160  vlib_add_trace (vm, node, b1, sizeof (*t));
161  t->rx_sw_if_index = sw_if_index1;
162  t->tx_sw_if_index =
163  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1];
164  }
165  }
166 
167  /* verify speculative enqueues, maybe switch current next frame */
168  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
169  to_next, n_left_to_next,
170  bi0, bi1, next0, next1);
171  }
172 
173  while (n_left_from > 0 && n_left_to_next > 0)
174  {
175  u32 bi0;
176  vlib_buffer_t *b0;
177  u32 next0;
178  u32 sw_if_index0;
179 
180  /* speculatively enqueue b0 to the current next frame */
181  bi0 = from[0];
182  to_next[0] = bi0;
183  from += 1;
184  to_next += 1;
185  n_left_from -= 1;
186  n_left_to_next -= 1;
187 
188  b0 = vlib_get_buffer (vm, bi0);
189 
190  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
191 
192  ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index0] != ~0);
193  ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0] != ~0);
194 
195  next0 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index0];
196  vnet_buffer (b0)->sw_if_index[VLIB_TX] =
197  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0];
198 
199  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
200  {
201  if (b0->flags & VLIB_BUFFER_IS_TRACED)
202  {
203  l2_patch_trace_t *t =
204  vlib_add_trace (vm, node, b0, sizeof (*t));
205  t->rx_sw_if_index = sw_if_index0;
206  t->tx_sw_if_index =
207  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0];
208  }
209  }
210 
211  /* verify speculative enqueue, maybe switch current next frame */
212  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
213  to_next, n_left_to_next,
214  bi0, next0);
215  }
216 
217  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
218  }
219 
220  em->counters[node_counter_base_index + L2_PATCH_ERROR_PATCHED] +=
221  frame->n_vectors;
222 
223  return frame->n_vectors;
224 }
225 
226 /* *INDENT-OFF* */
227 VLIB_REGISTER_NODE (l2_patch_node, static) = {
228  .function = l2_patch_node_fn,
229  .name = "l2-patch",
230  .vector_size = sizeof (u32),
231  .format_trace = format_l2_patch_trace,
232  .type = VLIB_NODE_TYPE_INTERNAL,
233 
234  .n_errors = ARRAY_LEN(l2_patch_error_strings),
235  .error_strings = l2_patch_error_strings,
236 
237  .n_next_nodes = L2_PATCH_N_NEXT,
238 
239  /* edit / add dispositions here */
240  .next_nodes = {
241  [L2_PATCH_NEXT_DROP] = "error-drop",
242  },
243 };
244 /* *INDENT-ON* */
245 
247  int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
248  int is_add)
249 {
251  vnet_hw_interface_t *rxhi, *txhi;
252  u32 tx_next_index;
253 
254  /*
255  * We assume that the API msg handler has used 2x VALIDATE_SW_IF_INDEX
256  * macros...
257  */
258 
259  rxhi = vnet_get_sup_hw_interface (l2pm->vnet_main, rx_sw_if_index);
260 
261  /* Make sure caller didn't pass a vlan subif, etc. */
262  if (rxhi->sw_if_index != rx_sw_if_index)
263  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
264 
265  txhi = vnet_get_sup_hw_interface (l2pm->vnet_main, tx_sw_if_index);
266  if (txhi->sw_if_index != tx_sw_if_index)
267  return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
268 
269  if (is_add)
270  {
271  tx_next_index = vlib_node_add_next (l2pm->vlib_main,
272  l2_patch_node.index,
273  txhi->output_node_index);
274 
276  rx_sw_if_index, ~0);
277 
278  l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = tx_next_index;
280  rx_sw_if_index, ~0);
281  l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index]
282  = txhi->sw_if_index;
283 
286 
287  vnet_feature_enable_disable ("device-input", "l2-patch",
288  rxhi->hw_if_index, 1, 0, 0);
289  }
290  else
291  {
293  0 /* disable promiscuous mode */ );
294 
295  vnet_feature_enable_disable ("device-input", "l2-patch",
296  rxhi->hw_if_index, 0, 0, 0);
297  if (vec_len (l2pm->tx_next_by_rx_sw_if_index) > rx_sw_if_index)
298  {
299  l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = ~0;
300  l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index] = ~0;
301  }
302  }
303 
304  return 0;
305 }
306 
307 static clib_error_t *
309  unformat_input_t * input, vlib_cli_command_t * cmd)
310 {
312  unformat_input_t _line_input, *line_input = &_line_input;
313  u32 rx_sw_if_index, tx_sw_if_index;
314  int rv;
315  int rx_set = 0;
316  int tx_set = 0;
317  int is_add = 1;
318  clib_error_t *error = NULL;
319 
320  /* Get a line of input. */
321  if (!unformat_user (input, unformat_line_input, line_input))
322  return 0;
323 
324  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
325  {
326  if (unformat (line_input, "rx %U", unformat_vnet_sw_interface,
327  l2pm->vnet_main, &rx_sw_if_index))
328  rx_set = 1;
329  else if (unformat (line_input, "tx %U", unformat_vnet_sw_interface,
330  l2pm->vnet_main, &tx_sw_if_index))
331  tx_set = 1;
332  else if (unformat (line_input, "del"))
333  is_add = 0;
334  else
335  break;
336  }
337 
338  if (rx_set == 0)
339  {
340  error = clib_error_return (0, "rx interface not set");
341  goto done;
342  }
343 
344  if (tx_set == 0)
345  {
346  error = clib_error_return (0, "tx interface not set");
347  goto done;
348  }
349 
350  rv = vnet_l2_patch_add_del (rx_sw_if_index, tx_sw_if_index, is_add);
351 
352  switch (rv)
353  {
354  case 0:
355  break;
356 
357  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
358  error = clib_error_return (0, "rx interface not a physical port");
359  goto done;
360 
361  case VNET_API_ERROR_INVALID_SW_IF_INDEX_2:
362  error = clib_error_return (0, "tx interface not a physical port");
363  goto done;
364 
365  default:
366  error = clib_error_return
367  (0, "WARNING: vnet_l2_patch_add_del returned %d", rv);
368  goto done;
369  }
370 
371 
372 done:
373  unformat_free (line_input);
374 
375  return error;
376 }
377 
378 /*?
379  * Create or delete a Layer 2 patch.
380  *
381  * @cliexpar
382  * @cliexstart{test l2patch rx <intfc> tx <intfc> [del]}
383  * @cliexend
384  * @todo This is incomplete. This needs a detailed description and a
385  * practical example.
386 ?*/
387 /* *INDENT-OFF* */
388 VLIB_CLI_COMMAND (test_patch_command, static) = {
389  .path = "test l2patch",
390  .short_help = "test l2patch rx <intfc> tx <intfc> [del]",
391  .function = test_patch_command_fn,
392 };
393 /* *INDENT-ON* */
394 
395 /** Display the contents of the l2patch table. */
396 static clib_error_t *
398  unformat_input_t * input, vlib_cli_command_t * cmd)
399 {
401  u32 rx_sw_if_index;
402  u32 no_entries = 1;
403 
406 
407  for (rx_sw_if_index = 0;
408  rx_sw_if_index < vec_len (l2pm->tx_sw_if_index_by_rx_sw_if_index);
409  rx_sw_if_index++)
410  {
411  u32 tx_sw_if_index =
412  l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index];
413  if (tx_sw_if_index != ~0)
414  {
415  no_entries = 0;
416  vlib_cli_output (vm, "%26U -> %U",
418  l2pm->vnet_main, rx_sw_if_index,
420  l2pm->vnet_main, tx_sw_if_index);
421  }
422  }
423 
424  if (no_entries)
425  vlib_cli_output (vm, "no l2patch entries");
426 
427  return 0;
428 }
429 
430 /*?
431  * Show Layer 2 patch entries.
432  *
433  * @cliexpar
434  * @cliexstart{show l2patch}
435  * @cliexend
436  * @todo This is incomplete. This needs a detailed description and a
437  * practical example.
438 ?*/
439 /* *INDENT-OFF* */
440 VLIB_CLI_COMMAND (show_l2patch_cli, static) = {
441  .path = "show l2patch",
442  .short_help = "Show l2 interface cross-connect entries",
443  .function = show_l2patch,
444 };
445 /* *INDENT-ON* */
446 
447 clib_error_t *
449 {
451 
452  mp->vlib_main = vm;
453  mp->vnet_main = vnet_get_main ();
454 
455  return 0;
456 }
457 
459 
460 /*
461  * fd.io coding-style-patch-verification: ON
462  *
463  * Local Variables:
464  * eval: (c-set-style "gnu")
465  * End:
466  */
vnet_main_t * vnet_main
Definition: l2_patch.c:30
static clib_error_t * show_l2patch(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Display the contents of the l2patch table.
Definition: l2_patch.c:397
u32 error_heap_index
Definition: node.h:278
#define CLIB_UNUSED(x)
Definition: clib.h:79
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)
#define NULL
Definition: clib.h:55
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
format_function_t format_vnet_sw_if_index_name
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1110
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:191
#define clib_error_return(e, args...)
Definition: error.h:99
unformat_function_t unformat_line_input
Definition: format.h:281
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
vlib_error_main_t error_main
Definition: main.h:141
static u8 * format_l2_patch_trace(u8 *s, va_list *args)
Definition: l2_patch.c:41
struct _unformat_input_t unformat_input_t
static char * l2_patch_error_strings[]
Definition: l2_patch.c:68
#define PREDICT_FALSE(x)
Definition: clib.h:105
#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
#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
u64 * counters
Definition: error.h:78
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:294
l2_patch_main_t l2_patch_main
Definition: l2_patch.c:52
u32 tx_sw_if_index
Definition: l2_patch.c:36
u32 * tx_next_by_rx_sw_if_index
Definition: l2_patch.c:25
#define ETHERNET_INTERFACE_FLAG_ACCEPT_ALL
Definition: ethernet.h:147
#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
l2_patch_error_t
Definition: l2_patch.c:60
#define foreach_l2_patch_error
Definition: l2_patch.c:56
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:456
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
vlib_main_t * vlib_main
Definition: l2_patch.c:29
static vlib_node_registration_t l2_patch_node
(constructor) VLIB_REGISTER_NODE (l2_patch_node)
Definition: l2_patch.c:54
static uword l2_patch_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2_patch.c:81
u32 * tx_sw_if_index_by_rx_sw_if_index
Definition: l2_patch.c:26
static clib_error_t * test_patch_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: l2_patch.c:308
l2_patch_next_t
Definition: l2_patch.c:74
u64 uword
Definition: types.h:112
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
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
int vnet_l2_patch_add_del(u32 rx_sw_if_index, u32 tx_sw_if_index, int is_add)
Definition: l2_patch.c:247
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define vnet_buffer(b)
Definition: buffer.h:372
u32 rx_sw_if_index
Definition: l2_patch.c:35
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:59
u16 flags
Copy of main node flags.
Definition: node.h:450
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
#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:483
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:680
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
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
Definition: defs.h:46
clib_error_t * l2_patch_init(vlib_main_t *vm)
Definition: l2_patch.c:448
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:233
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u32 ethernet_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: interface.c:367