FD.io VPP  v16.09
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 <vppinfra/error.h>
20 
21 typedef struct
22 {
25 
26  /* vector of dispositions, indexed by rx_sw_if_index */
29 
30  /* convenience variables */
34 
35 typedef struct
36 {
40 
41 /* packet trace format function */
42 static u8 *
43 format_l2_patch_trace (u8 * s, va_list * args)
44 {
45  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
46  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
47  l2_patch_trace_t *t = va_arg (*args, l2_patch_trace_t *);
48 
49  s = format (s, "L2_PATCH: rx %d tx %d", t->rx_sw_if_index,
50  t->tx_sw_if_index);
51  return s;
52 }
53 
55 
57 
58 #define foreach_l2_patch_error \
59 _(PATCHED, "L2 patch packets") \
60 _(DROPPED, "L2 patch misconfigured drops")
61 
62 typedef enum
63 {
64 #define _(sym,str) L2_PATCH_ERROR_##sym,
66 #undef _
69 
70 static char *l2_patch_error_strings[] = {
71 #define _(sym,string) string,
73 #undef _
74 };
75 
76 typedef enum
77 {
81 
82 static uword
84  vlib_node_runtime_t * node, vlib_frame_t * frame)
85 {
86  u32 n_left_from, *from, *to_next;
87  l2_patch_next_t next_index;
89  vlib_node_t *n = vlib_get_node (vm, l2_patch_node.index);
90  u32 node_counter_base_index = n->error_heap_index;
91  vlib_error_main_t *em = &vm->error_main;
92 
93  from = vlib_frame_vector_args (frame);
94  n_left_from = frame->n_vectors;
95  next_index = node->cached_next_index;
96 
97  while (n_left_from > 0)
98  {
99  u32 n_left_to_next;
100 
101  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
102 
103  while (n_left_from >= 4 && n_left_to_next >= 2)
104  {
105  u32 bi0, bi1;
106  vlib_buffer_t *b0, *b1;
107  u32 next0, next1;
108  u32 sw_if_index0, sw_if_index1;
109 
110  /* Prefetch next iteration. */
111  {
112  vlib_buffer_t *p2, *p3;
113 
114  p2 = vlib_get_buffer (vm, from[2]);
115  p3 = vlib_get_buffer (vm, from[3]);
116 
117  vlib_prefetch_buffer_header (p2, LOAD);
118  vlib_prefetch_buffer_header (p3, LOAD);
119 
120  /* So stupid / simple, we don't need to prefetch data */
121  }
122 
123  /* speculatively enqueue b0 and b1 to the current next frame */
124  to_next[0] = bi0 = from[0];
125  to_next[1] = bi1 = from[1];
126  from += 2;
127  to_next += 2;
128  n_left_from -= 2;
129  n_left_to_next -= 2;
130 
131  b0 = vlib_get_buffer (vm, bi0);
132  b1 = vlib_get_buffer (vm, bi1);
133 
134  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
135  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
136 
137  ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index0] != ~0);
138  ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0] != ~0);
139  ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index1] != ~0);
140  ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1] != ~0);
141 
142  if (PREDICT_TRUE (sw_if_index0 == l2pm->cached_rx_sw_if_index))
143  next0 = l2pm->cached_next_index;
144  else
145  {
146  next0 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index0];
147  l2pm->cached_rx_sw_if_index = sw_if_index0;
148  l2pm->cached_next_index = next0;
149  }
150 
151  if (PREDICT_TRUE (sw_if_index1 == l2pm->cached_rx_sw_if_index))
152  next1 = l2pm->cached_next_index;
153  else
154  next1 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index1];
155 
156  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
157  {
158  if (b0->flags & VLIB_BUFFER_IS_TRACED)
159  {
160  l2_patch_trace_t *t =
161  vlib_add_trace (vm, node, b0, sizeof (*t));
162  t->rx_sw_if_index = sw_if_index0;
163  t->tx_sw_if_index =
164  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0];
165  }
166  if (b1->flags & VLIB_BUFFER_IS_TRACED)
167  {
168  l2_patch_trace_t *t =
169  vlib_add_trace (vm, node, b1, sizeof (*t));
170  t->rx_sw_if_index = sw_if_index1;
171  t->tx_sw_if_index =
172  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1];
173  }
174  }
175 
176  /* verify speculative enqueues, maybe switch current next frame */
177  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
178  to_next, n_left_to_next,
179  bi0, bi1, next0, next1);
180  }
181 
182  while (n_left_from > 0 && n_left_to_next > 0)
183  {
184  u32 bi0;
185  vlib_buffer_t *b0;
186  u32 next0;
187  u32 sw_if_index0;
188 
189  /* speculatively enqueue b0 to the current next frame */
190  bi0 = from[0];
191  to_next[0] = bi0;
192  from += 1;
193  to_next += 1;
194  n_left_from -= 1;
195  n_left_to_next -= 1;
196 
197  b0 = vlib_get_buffer (vm, bi0);
198 
199  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
200 
201  ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index0] != ~0);
202  ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0] != ~0);
203 
204  if (PREDICT_TRUE (sw_if_index0 == l2pm->cached_rx_sw_if_index))
205  next0 = l2pm->cached_next_index;
206  else
207  {
208  next0 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index0];
209  l2pm->cached_rx_sw_if_index = sw_if_index0;
210  l2pm->cached_next_index = next0;
211  }
212 
213  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
214  {
215  if (b0->flags & VLIB_BUFFER_IS_TRACED)
216  {
217  l2_patch_trace_t *t =
218  vlib_add_trace (vm, node, b0, sizeof (*t));
219  t->rx_sw_if_index = sw_if_index0;
220  t->tx_sw_if_index =
221  l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0];
222  }
223  }
224 
225  /* verify speculative enqueue, maybe switch current next frame */
226  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
227  to_next, n_left_to_next,
228  bi0, next0);
229  }
230 
231  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
232  }
233 
234  em->counters[node_counter_base_index + L2_PATCH_ERROR_PATCHED] +=
235  frame->n_vectors;
236 
237  return frame->n_vectors;
238 }
239 
240 /* *INDENT-OFF* */
241 VLIB_REGISTER_NODE (l2_patch_node, static) = {
242  .function = l2_patch_node_fn,
243  .name = "l2_patch",
244  .vector_size = sizeof (u32),
245  .format_trace = format_l2_patch_trace,
247 
248  .n_errors = ARRAY_LEN(l2_patch_error_strings),
249  .error_strings = l2_patch_error_strings,
250 
251  .n_next_nodes = L2_PATCH_N_NEXT,
252 
253  /* edit / add dispositions here */
254  .next_nodes = {
255  [L2_PATCH_NEXT_DROP] = "error-drop",
256  },
257 };
258 /* *INDENT-ON* */
259 
261  int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index,
262  int is_add)
263 {
265  vnet_hw_interface_t *rxhi, *txhi;
266  u32 tx_next_index;
267 
268  /*
269  * We assume that the API msg handler has used 2x VALIDATE_SW_IF_INDEX
270  * macros...
271  */
272 
273  rxhi = vnet_get_sup_hw_interface (l2pm->vnet_main, rx_sw_if_index);
274 
275  /* Make sure caller didn't pass a vlan subif, etc. */
276  if (rxhi->sw_if_index != rx_sw_if_index)
277  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
278 
279  txhi = vnet_get_sup_hw_interface (l2pm->vnet_main, tx_sw_if_index);
280  if (txhi->sw_if_index != tx_sw_if_index)
281  return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
282 
283  if (is_add)
284  {
285  tx_next_index = vlib_node_add_next (l2pm->vlib_main,
286  l2_patch_node.index,
287  txhi->output_node_index);
288 
290  rx_sw_if_index, ~0);
291 
292  l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = tx_next_index;
294  rx_sw_if_index, ~0);
295  l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index]
296  = txhi->sw_if_index;
297 
300 
302  rxhi->hw_if_index,
303  l2_patch_node.index);
304  }
305  else
306  {
308  0 /* disable promiscuous mode */ );
309 
311  rxhi->hw_if_index,
312  ~0 /* disable */ );
313  if (vec_len (l2pm->tx_next_by_rx_sw_if_index) > rx_sw_if_index)
314  {
315  l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = ~0;
316  l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index] = ~0;
317  }
318  }
319 
320  return 0;
321 }
322 
323 static clib_error_t *
325  unformat_input_t * input, vlib_cli_command_t * cmd)
326 {
328  unformat_input_t _line_input, *line_input = &_line_input;
329  u32 rx_sw_if_index, tx_sw_if_index;
330  int rv;
331  int rx_set = 0;
332  int tx_set = 0;
333  int is_add = 1;
334 
335  /* Get a line of input. */
336  if (!unformat_user (input, unformat_line_input, line_input))
337  return 0;
338 
339  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
340  {
341  if (unformat (line_input, "rx %U", unformat_vnet_sw_interface,
342  l2pm->vnet_main, &rx_sw_if_index))
343  rx_set = 1;
344  else if (unformat (line_input, "tx %U", unformat_vnet_sw_interface,
345  l2pm->vnet_main, &tx_sw_if_index))
346  tx_set = 1;
347  else if (unformat (line_input, "del"))
348  is_add = 0;
349  else
350  break;
351  }
352 
353  if (rx_set == 0)
354  return clib_error_return (0, "rx interface not set");
355 
356  if (tx_set == 0)
357  return clib_error_return (0, "tx interface not set");
358 
359  rv = vnet_l2_patch_add_del (rx_sw_if_index, tx_sw_if_index, is_add);
360 
361  switch (rv)
362  {
363  case 0:
364  break;
365 
366  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
367  return clib_error_return (0, "rx interface not a physical port");
368 
369  case VNET_API_ERROR_INVALID_SW_IF_INDEX_2:
370  return clib_error_return (0, "tx interface not a physical port");
371 
372  default:
373  return clib_error_return
374  (0, "WARNING: vnet_l2_patch_add_del returned %d", rv);
375  }
376 
377  return 0;
378 }
379 
380 /* *INDENT-OFF* */
381 VLIB_CLI_COMMAND (test_patch_command, static) = {
382  .path = "test l2patch",
383  .short_help =
384  "rx <intfc> tx <intfc> [del]",
385  .function = test_patch_command_fn,
386 };
387 /* *INDENT-ON* */
388 
389 /** Display the contents of the l2patch table. */
390 static clib_error_t *
392  unformat_input_t * input, vlib_cli_command_t * cmd)
393 {
395  u32 rx_sw_if_index;
396  u32 no_entries = 1;
397 
400 
401  for (rx_sw_if_index = 0;
402  rx_sw_if_index < vec_len (l2pm->tx_sw_if_index_by_rx_sw_if_index);
403  rx_sw_if_index++)
404  {
405  u32 tx_sw_if_index =
406  l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index];
407  if (tx_sw_if_index != ~0)
408  {
409  no_entries = 0;
410  vlib_cli_output (vm, "%26U -> %U",
412  l2pm->vnet_main, rx_sw_if_index,
414  l2pm->vnet_main, tx_sw_if_index);
415  }
416  }
417 
418  if (no_entries)
419  vlib_cli_output (vm, "no l2patch entries");
420 
421  return 0;
422 }
423 
424 /* *INDENT-OFF* */
425 VLIB_CLI_COMMAND (show_l2patch_cli, static) = {
426  .path = "show l2patch",
427  .short_help = "Show l2 interface cross-connect entries",
428  .function = show_l2patch,
429 };
430 /* *INDENT-ON* */
431 
432 clib_error_t *
434 {
436 
437  mp->vlib_main = vm;
438  mp->vnet_main = vnet_get_main ();
439 
440  return 0;
441 }
442 
444 
445 /*
446  * fd.io coding-style-patch-verification: ON
447  *
448  * Local Variables:
449  * eval: (c-set-style "gnu")
450  * End:
451  */
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:457
vnet_main_t * vnet_main
Definition: l2_patch.c:32
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:391
u32 error_heap_index
Definition: node.h:278
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define PREDICT_TRUE(x)
Definition: clib.h:98
int vnet_hw_interface_rx_redirect_to_node(vnet_main_t *vnm, u32 hw_if_index, u32 node_index)
Definition: interface.c:1022
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
struct _vlib_node_registration vlib_node_registration_t
u32 cached_next_index
Definition: l2_patch.c:23
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:1061
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
vlib_error_main_t error_main
Definition: main.h:124
static u8 * format_l2_patch_trace(u8 *s, va_list *args)
Definition: l2_patch.c:43
static char * l2_patch_error_strings[]
Definition: l2_patch.c:70
#define PREDICT_FALSE(x)
Definition: clib.h:97
#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:130
#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:348
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
u64 * counters
Definition: error.h:78
u16 n_vectors
Definition: node.h:344
l2_patch_main_t l2_patch_main
Definition: l2_patch.c:54
u32 tx_sw_if_index
Definition: l2_patch.c:38
u32 * tx_next_by_rx_sw_if_index
Definition: l2_patch.c:27
#define ETHERNET_INTERFACE_FLAG_ACCEPT_ALL
Definition: ethernet.h:85
#define ARRAY_LEN(x)
Definition: clib.h:59
l2_patch_error_t
Definition: l2_patch.c:62
#define foreach_l2_patch_error
Definition: l2_patch.c:58
u16 cached_next_index
Definition: node.h:462
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
vlib_main_t * vlib_main
Definition: l2_patch.c:31
#define vnet_buffer(b)
Definition: buffer.h:335
static vlib_node_registration_t l2_patch_node
(constructor) VLIB_REGISTER_NODE (l2_patch_node)
Definition: l2_patch.c:56
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
static uword l2_patch_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2_patch.c:83
u32 * tx_sw_if_index_by_rx_sw_if_index
Definition: l2_patch.c:28
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
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:324
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
l2_patch_next_t
Definition: l2_patch.c:76
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
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
int vnet_l2_patch_add_del(u32 rx_sw_if_index, u32 tx_sw_if_index, int is_add)
Definition: l2_patch.c:261
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:163
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u32 rx_sw_if_index
Definition: l2_patch.c:37
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:58
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
#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:445
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
unformat_function_t unformat_line_input
Definition: format.h:281
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
u32 cached_rx_sw_if_index
Definition: l2_patch.c:24
Definition: defs.h:46
clib_error_t * l2_patch_init(vlib_main_t *vm)
Definition: l2_patch.c:433
u32 ethernet_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: interface.c:274