FD.io VPP  v21.01.1
Vector Packet Processing
l2_vtr.c
Go to the documentation of this file.
1 /*
2  * l2_vtr.c : layer 2 vlan tag rewrite configuration
3  *
4  * Copyright (c) 2013 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vnet/ethernet/packet.h>
22 #include <vnet/l2/l2_input.h>
23 #include <vnet/l2/l2_output.h>
24 #include <vnet/l2/feat_bitmap.h>
25 #include <vnet/l2/l2_vtr.h>
26 #include <vnet/l2/l2_input_vtr.h>
27 #include <vnet/l2/l2_output.h>
28 
29 #include <vppinfra/error.h>
30 #include <vlib/cli.h>
31 
32 /**
33  * @file
34  * @brief Ethernet VLAN Tag Rewrite.
35  *
36  * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
37  * Existing tags can be popped, new tags can be pushed, and existing tags can
38  * be swapped with new tags. The rewrite feature is attached to a subinterface
39  * as input and output operations. The input operation is explicitly configured.
40  * The output operation is the symmetric opposite and is automatically derived
41  * from the input operation.
42  */
43 
44 /** Just a placeholder; ensures file is not eliminated by linker. */
47 {
48  return 0;
49 }
50 
52 
53 u32
56  u8 * b_dmac, u8 * b_smac,
57  u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag)
58 {
59  u32 error = 0;
60  u32 enable = 0;
61 
62  l2_output_config_t *config = 0;
64  hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
65 
66  if (!hi)
67  {
68  error = VNET_API_ERROR_INVALID_INTERFACE;
69  goto done;
70  }
71 
72  // Config for this interface should be already initialized
73  ptr_config_t *in_config;
74  ptr_config_t *out_config;
75  config = vec_elt_at_index (l2output_main.configs, sw_if_index);
76  in_config = &(config->input_pbb_vtr);
77  out_config = &(config->output_pbb_vtr);
78 
79  in_config->pop_bytes = 0;
80  in_config->push_bytes = 0;
81  out_config->pop_bytes = 0;
82  out_config->push_bytes = 0;
83  enable = (vtr_op != L2_VTR_DISABLED);
84 
85  if (!enable)
86  goto done;
87 
88  if (vtr_op == L2_VTR_POP_2)
89  {
90  in_config->pop_bytes = sizeof (ethernet_pbb_header_packed_t);
91  }
92  else if (vtr_op == L2_VTR_PUSH_2)
93  {
94  clib_memcpy_fast (in_config->macs_tags.b_dst_address, b_dmac,
95  sizeof (in_config->macs_tags.b_dst_address));
96  clib_memcpy_fast (in_config->macs_tags.b_src_address, b_smac,
97  sizeof (in_config->macs_tags.b_src_address));
98  in_config->macs_tags.b_type =
99  clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AD);
100  in_config->macs_tags.priority_dei_id =
101  clib_net_to_host_u16 (b_vlanid & 0xFFF);
102  in_config->macs_tags.i_type =
103  clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AH);
105  clib_net_to_host_u32 (i_sid & 0xFFFFF);
106  in_config->push_bytes = sizeof (ethernet_pbb_header_packed_t);
107  }
108  else if (vtr_op == L2_VTR_TRANSLATE_2_2)
109  {
110  /* TODO after PoC */
111  }
112 
113  /*
114  * Construct the output tag-rewrite config
115  *
116  * The push/pop values are always reversed
117  */
118  out_config->raw_data = in_config->raw_data;
119  out_config->pop_bytes = in_config->push_bytes;
120  out_config->push_bytes = in_config->pop_bytes;
121 
122 done:
123  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
124  if (config)
125  config->out_vtr_flag = (u8) enable;
126 
127  /* output vtr enable is checked explicitly in l2_output */
128  return error;
129 }
130 
131 /**
132  * Configure vtag tag rewrite on the given interface.
133  * Return 1 if there is an error, 0 if ok
134  */
135 u32
136 l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op, u32 push_dot1q, /* ethertype of first pushed tag is dot1q/dot1ad */
137  u32 vtr_tag1, /* first pushed tag */
138  u32 vtr_tag2) /* second pushed tag */
139 {
142  u32 hw_no_tags;
143  u32 error = 0;
144  l2_output_config_t *config;
145  vtr_config_t *in_config;
146  vtr_config_t *out_config;
147  u32 enable;
148  u32 push_inner_et;
149  u32 push_outer_et;
150  u32 cfg_tags;
151 
152  hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
153  if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
154  {
155  error = VNET_API_ERROR_INVALID_INTERFACE; /* non-ethernet interface */
156  goto done;
157  }
158 
159  /* Init the config for this interface */
160  vec_validate (l2output_main.configs, sw_if_index);
161  config = vec_elt_at_index (l2output_main.configs, sw_if_index);
162  in_config = &(config->input_vtr);
163  out_config = &(config->output_vtr);
164  in_config->raw_tags = 0;
165  out_config->raw_tags = 0;
166 
167  /* Get the configured tags for the interface */
168  si = vnet_get_sw_interface (vnet_main, sw_if_index);
169  hw_no_tags = (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
170 
171  /* Construct the input tag-rewrite config */
172 
173  push_outer_et =
174  clib_net_to_host_u16 (push_dot1q ? ETHERNET_TYPE_VLAN :
175  ETHERNET_TYPE_DOT1AD);
176  push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
177  vtr_tag1 = clib_net_to_host_u16 (vtr_tag1);
178  vtr_tag2 = clib_net_to_host_u16 (vtr_tag2);
179 
180  /* Determine number of vlan tags with explicitly configured values */
181  cfg_tags = 0;
182  if (hw_no_tags || si->sub.eth.flags.no_tags)
183  {
184  cfg_tags = 0;
185  }
186  else if (si->sub.eth.flags.one_tag)
187  {
188  cfg_tags = 1;
189  if (si->sub.eth.flags.outer_vlan_id_any)
190  {
191  cfg_tags = 0;
192  }
193  }
194  else if (si->sub.eth.flags.two_tags)
195  {
196  cfg_tags = 2;
197  if (si->sub.eth.flags.inner_vlan_id_any)
198  {
199  cfg_tags = 1;
200  }
201  if (si->sub.eth.flags.outer_vlan_id_any)
202  {
203  cfg_tags = 0;
204  }
205  }
206 
207  switch (vtr_op)
208  {
209  case L2_VTR_DISABLED:
210  in_config->push_and_pop_bytes = 0;
211  break;
212 
213  case L2_VTR_POP_1:
214  if (cfg_tags < 1)
215  {
216  /* Need one or two tags */
217  error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;
218  goto done;
219  }
220  in_config->pop_bytes = 4;
221  in_config->push_bytes = 0;
222  break;
223 
224  case L2_VTR_POP_2:
225  if (cfg_tags < 2)
226  {
227  error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
228  goto done;
229  }
230  in_config->pop_bytes = 8;
231  in_config->push_bytes = 0;
232  break;
233 
234  case L2_VTR_PUSH_1:
235  in_config->pop_bytes = 0;
236  in_config->push_bytes = 4;
237  in_config->tags[1].priority_cfi_and_id = vtr_tag1;
238  in_config->tags[1].type = push_outer_et;
239  break;
240 
241  case L2_VTR_PUSH_2:
242  in_config->pop_bytes = 0;
243  in_config->push_bytes = 8;
244  in_config->tags[0].priority_cfi_and_id = vtr_tag1;
245  in_config->tags[0].type = push_outer_et;
246  in_config->tags[1].priority_cfi_and_id = vtr_tag2;
247  in_config->tags[1].type = push_inner_et;
248  break;
249 
251  if (cfg_tags < 1)
252  {
253  error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
254  goto done;
255  }
256  in_config->pop_bytes = 4;
257  in_config->push_bytes = 4;
258  in_config->tags[1].priority_cfi_and_id = vtr_tag1;
259  in_config->tags[1].type = push_outer_et;
260  break;
261 
263  if (cfg_tags < 1)
264  {
265  error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
266  goto done;
267  }
268  in_config->pop_bytes = 4;
269  in_config->push_bytes = 8;
270  in_config->tags[0].priority_cfi_and_id = vtr_tag1;
271  in_config->tags[0].type = push_outer_et;
272  in_config->tags[1].priority_cfi_and_id = vtr_tag2;
273  in_config->tags[1].type = push_inner_et;
274  break;
275 
277  if (cfg_tags < 2)
278  {
279  error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
280  goto done;
281  }
282  in_config->pop_bytes = 8;
283  in_config->push_bytes = 4;
284  in_config->tags[1].priority_cfi_and_id = vtr_tag1;
285  in_config->tags[1].type = push_outer_et;
286  break;
287 
289  if (cfg_tags < 2)
290  {
291  error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
292  goto done;
293  }
294  in_config->pop_bytes = 8;
295  in_config->push_bytes = 8;
296  in_config->tags[0].priority_cfi_and_id = vtr_tag1;
297  in_config->tags[0].type = push_outer_et;
298  in_config->tags[1].priority_cfi_and_id = vtr_tag2;
299  in_config->tags[1].type = push_inner_et;
300  break;
301  }
302 
303  /*
304  * Construct the output tag-rewrite config
305  *
306  * The push/pop values are always reversed
307  */
308  out_config->push_bytes = in_config->pop_bytes;
309  out_config->pop_bytes = in_config->push_bytes;
310 
311  /* Any pushed tags are derived from the subinterface config */
312  push_outer_et =
313  clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
314  ETHERNET_TYPE_VLAN);
315  push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
316  vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id);
317  vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id);
318 
319  if (out_config->push_bytes == 4)
320  {
321  out_config->tags[1].priority_cfi_and_id = vtr_tag1;
322  out_config->tags[1].type = push_outer_et;
323  }
324  else if (out_config->push_bytes == 8)
325  {
326  out_config->tags[0].priority_cfi_and_id = vtr_tag1;
327  out_config->tags[0].type = push_outer_et;
328  out_config->tags[1].priority_cfi_and_id = vtr_tag2;
329  out_config->tags[1].type = push_inner_et;
330  }
331 
332  /* set the interface enable flags */
333  enable = (vtr_op != L2_VTR_DISABLED);
334  config->out_vtr_flag = (u8) enable;
335  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
336  /* output vtr enable is checked explicitly in l2_output */
337 
338 done:
339  return error;
340 }
341 
342 /**
343  * Get vtag tag rewrite on the given interface.
344  * Return 1 if there is an error, 0 if ok
345  */
346 u32
347 l2vtr_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, u32 * vtr_op, u32 * push_dot1q, /* ethertype of first pushed tag is dot1q/dot1ad */
348  u32 * vtr_tag1, /* first pushed tag */
349  u32 * vtr_tag2) /* second pushed tag */
350 {
352  u32 error = 0;
353  vtr_config_t *in_config;
354 
355  if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
356  {
357  clib_warning ("invalid arguments");
358  error = VNET_API_ERROR_INVALID_ARGUMENT;
359  goto done;
360  }
361 
362  *vtr_op = L2_VTR_DISABLED;
363  *vtr_tag1 = 0;
364  *vtr_tag2 = 0;
365  *push_dot1q = 0;
366 
367  hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
368  if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
369  {
370  /* non-ethernet interface */
371  goto done;
372  }
373 
374  if (sw_if_index >= vec_len (l2output_main.configs))
375  {
376  /* no specific config (return disabled) */
377  goto done;
378  }
379 
380  /* Get the config for this interface */
381  in_config =
382  &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
383 
384  /* DISABLED */
385  if (in_config->push_and_pop_bytes == 0)
386  {
387  goto done;
388  }
389 
390  /* find out vtr_op */
391  switch (in_config->pop_bytes)
392  {
393  case 0:
394  switch (in_config->push_bytes)
395  {
396  case 0:
397  /* DISABLED */
398  goto done;
399  case 4:
400  *vtr_op = L2_VTR_PUSH_1;
401  *vtr_tag1 =
402  clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
403  *push_dot1q =
404  (ETHERNET_TYPE_VLAN ==
405  clib_host_to_net_u16 (in_config->tags[1].type));
406  break;
407  case 8:
408  *vtr_op = L2_VTR_PUSH_2;
409  *vtr_tag1 =
410  clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
411  *vtr_tag2 =
412  clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
413  *push_dot1q =
414  (ETHERNET_TYPE_VLAN ==
415  clib_host_to_net_u16 (in_config->tags[0].type));
416  break;
417  default:
418  clib_warning ("invalid push_bytes count: %d",
419  in_config->push_bytes);
420  error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
421  goto done;
422  }
423  break;
424 
425  case 4:
426  switch (in_config->push_bytes)
427  {
428  case 0:
429  *vtr_op = L2_VTR_POP_1;
430  break;
431  case 4:
432  *vtr_op = L2_VTR_TRANSLATE_1_1;
433  *vtr_tag1 =
434  clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
435  *push_dot1q =
436  (ETHERNET_TYPE_VLAN ==
437  clib_host_to_net_u16 (in_config->tags[1].type));
438  break;
439  case 8:
440  *vtr_op = L2_VTR_TRANSLATE_1_2;
441  *vtr_tag1 =
442  clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
443  *vtr_tag2 =
444  clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
445  *push_dot1q =
446  (ETHERNET_TYPE_VLAN ==
447  clib_host_to_net_u16 (in_config->tags[0].type));
448  break;
449  default:
450  clib_warning ("invalid push_bytes count: %d",
451  in_config->push_bytes);
452  error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
453  goto done;
454  }
455  break;
456 
457  case 8:
458  switch (in_config->push_bytes)
459  {
460  case 0:
461  *vtr_op = L2_VTR_POP_2;
462  break;
463  case 4:
464  *vtr_op = L2_VTR_TRANSLATE_2_1;
465  *vtr_tag1 =
466  clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
467  *push_dot1q =
468  (ETHERNET_TYPE_VLAN ==
469  clib_host_to_net_u16 (in_config->tags[1].type));
470  break;
471  case 8:
472  *vtr_op = L2_VTR_TRANSLATE_2_2;
473  *vtr_tag1 =
474  clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
475  *vtr_tag2 =
476  clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
477  *push_dot1q =
478  (ETHERNET_TYPE_VLAN ==
479  clib_host_to_net_u16 (in_config->tags[0].type));
480  break;
481  default:
482  clib_warning ("invalid push_bytes count: %d",
483  in_config->push_bytes);
484  error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
485  goto done;
486  }
487  break;
488 
489  default:
490  clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
491  error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
492  goto done;
493  }
494 
495 done:
496  return error;
497 }
498 
499 /**
500  * Set subinterface vtr enable/disable.
501  * The CLI format is:
502  * set interface l2 tag-rewrite <interface> [disable | pop 1 | pop 2 | push {dot1q|dot1ad} <tag> [<tag>]]
503  *
504  * "push" can also be replaced by "translate-{1|2}-{1|2}"
505  */
506 static clib_error_t *
508  unformat_input_t * input, vlib_cli_command_t * cmd)
509 {
510  vnet_main_t *vnm = vnet_get_main ();
511  clib_error_t *error = 0;
513  u32 vtr_op;
514  u32 push_dot1q = 0;
515  u32 tag1 = 0, tag2 = 0;
516 
517  if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
518  {
519  error = clib_error_return (0, "unknown interface `%U'",
520  format_unformat_error, input);
521  goto done;
522  }
523 
524  vtr_op = L2_VTR_DISABLED;
525 
526  if (unformat (input, "disable"))
527  {
528  vtr_op = L2_VTR_DISABLED;
529  }
530  else if (unformat (input, "pop 1"))
531  {
532  vtr_op = L2_VTR_POP_1;
533  }
534  else if (unformat (input, "pop 2"))
535  {
536  vtr_op = L2_VTR_POP_2;
537 
538  }
539  else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
540  {
541  vtr_op = L2_VTR_PUSH_2;
542  push_dot1q = 1;
543  }
544  else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
545  {
546  vtr_op = L2_VTR_PUSH_2;
547 
548  }
549  else if (unformat (input, "push dot1q %d", &tag1))
550  {
551  vtr_op = L2_VTR_PUSH_1;
552  push_dot1q = 1;
553  }
554  else if (unformat (input, "push dot1ad %d", &tag1))
555  {
556  vtr_op = L2_VTR_PUSH_1;
557 
558  }
559  else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
560  {
561  vtr_op = L2_VTR_TRANSLATE_1_1;
562  push_dot1q = 1;
563  }
564  else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
565  {
566  vtr_op = L2_VTR_TRANSLATE_1_1;
567 
568  }
569  else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
570  {
571  vtr_op = L2_VTR_TRANSLATE_2_1;
572  push_dot1q = 1;
573  }
574  else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
575  {
576  vtr_op = L2_VTR_TRANSLATE_2_1;
577 
578  }
579  else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
580  {
581  vtr_op = L2_VTR_TRANSLATE_2_2;
582  push_dot1q = 1;
583  }
584  else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
585  {
586  vtr_op = L2_VTR_TRANSLATE_2_2;
587 
588  }
589  else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
590  {
591  vtr_op = L2_VTR_TRANSLATE_1_2;
592  push_dot1q = 1;
593  }
594  else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
595  {
596  vtr_op = L2_VTR_TRANSLATE_1_2;
597 
598  }
599  else
600  {
601  error =
603  "expecting [disable | pop 1 | pop 2 | push {dot1q|dot1ah} <tag> [<tag>]\n"
604  " | translate {1|2}-{1|2} {dot1q|dot1ah} <tag> [<tag>]] but got `%U'",
605  format_unformat_error, input);
606  goto done;
607  }
608 
609  if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
610  {
611  error =
613  "vlan tag rewrite is not compatible with interface");
614  goto done;
615  }
616 
617 done:
618  return error;
619 }
620 
621 /*?
622  * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
623  * Existing tags can be popped, new tags can be pushed, and existing tags can
624  * be swapped with new tags. The rewrite feature is attached to a subinterface
625  * as input and output operations. The input operation is explicitly configured.
626  * The output operation is the symmetric opposite and is automatically derived
627  * from the input operation.
628  *
629  * <b>POP:</b> For pop operations, the subinterface encapsulation (the vlan
630  * tags specified when it was created) must have at least the number of popped
631  * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface.
632  * The output tag-rewrite operation for pops is to push the specified number of
633  * vlan tags onto the packet. The pushed tag values are the ones in the
634  * subinterface encapsulation.
635  *
636  * <b>PUSH:</b> For push operations, the ethertype is also specified. The
637  * output tag-rewrite operation for pushes is to pop the same number of tags
638  * off the packet. If the packet doesn't have enough tags it is dropped.
639  *
640  *
641  * @cliexpar
642  * @parblock
643  * By default a subinterface has no tag-rewrite. To return a subinterface to
644  * this state use:
645  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
646  *
647  * To pop vlan tags off packets received from a subinterface, use:
648  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1}
649  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2}
650  *
651  * To push one or two vlan tags onto packets received from an interface, use:
652  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100}
653  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150}
654  *
655  * Tags can also be translated, which is basically a combination of a pop and push.
656  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100}
657  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150}
658  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100}
659  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150}
660  *
661  * To display the VLAN Tag settings, show the associate bridge-domain:
662  * @cliexstart{show bridge-domain 200 detail}
663  * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
664  * 200 1 on on on on off N/A
665  *
666  * Interface Index SHG BVI VLAN-Tag-Rewrite
667  * GigabitEthernet0/8/0.200 5 0 - trans-1-1 dot1ad 100
668  * GigabitEthernet0/9/0.200 4 0 - none
669  * GigabitEthernet0/a/0.200 6 0 - none
670  * @cliexend
671  * @endparblock
672 ?*/
673 /* *INDENT-OFF* */
674 VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
675  .path = "set interface l2 tag-rewrite",
676  .short_help = "set interface l2 tag-rewrite <interface> [disable | pop {1|2} | push {dot1q|dot1ad} <tag> <tag>]",
677  .function = int_l2_vtr,
678 };
679 /* *INDENT-ON* */
680 
681 /**
682  * Get pbb tag rewrite on the given interface.
683  * Return 1 if there is an error, 0 if ok
684  */
685 u32
687  u32 * vtr_op, u16 * outer_tag, ethernet_header_t * eth_hdr,
688  u16 * b_vlanid, u32 * i_sid)
689 {
690  u32 error = 1;
691  ptr_config_t *in_config;
692 
693  if (!vtr_op || !outer_tag || !b_vlanid || !i_sid)
694  {
695  clib_warning ("invalid arguments");
696  error = VNET_API_ERROR_INVALID_ARGUMENT;
697  goto done;
698  }
699 
700  *vtr_op = L2_VTR_DISABLED;
701  *outer_tag = 0;
702  *b_vlanid = 0;
703  *i_sid = 0;
704 
705  if (sw_if_index >= vec_len (l2output_main.configs))
706  {
707  /* no specific config (return disabled) */
708  goto done;
709  }
710 
711  /* Get the config for this interface */
712  in_config =
713  &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_pbb_vtr);
714 
715  if (in_config->push_and_pop_bytes == 0)
716  {
717  /* DISABLED */
718  goto done;
719  }
720  else
721  {
722  if (in_config->pop_bytes && in_config->push_bytes)
723  *vtr_op = L2_VTR_TRANSLATE_2_1;
724  else if (in_config->pop_bytes)
725  *vtr_op = L2_VTR_POP_2;
726  else if (in_config->push_bytes)
727  *vtr_op = L2_VTR_PUSH_2;
728 
729  clib_memcpy_fast (&eth_hdr->dst_address,
730  in_config->macs_tags.b_dst_address,
731  sizeof (eth_hdr->dst_address));
732  clib_memcpy_fast (&eth_hdr->src_address,
733  in_config->macs_tags.b_src_address,
734  sizeof (eth_hdr->src_address));
735 
736  *b_vlanid =
737  clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF;
738  *i_sid =
739  clib_host_to_net_u32 (in_config->macs_tags.
740  priority_dei_uca_res_sid) & 0xFFFFF;
741  error = 0;
742  }
743 done:
744  return error;
745 }
746 
747 /**
748  * Set subinterface pbb vtr enable/disable.
749  * The CLI format is:
750  * set interface l2 pbb-tag-rewrite <interface> [disable | pop | push | translate_pbb_stag <outer_tag> dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]
751  */
752 static clib_error_t *
754  unformat_input_t * input, vlib_cli_command_t * cmd)
755 {
756  vnet_main_t *vnm = vnet_get_main ();
757  clib_error_t *error = 0;
758  u32 sw_if_index, tmp;
759  u32 vtr_op = L2_VTR_DISABLED;
760  u32 outer_tag = 0;
761  u8 dmac[6];
762  u8 smac[6];
763  u8 dmac_set = 0, smac_set = 0;
764  u16 b_vlanid = 0;
765  u32 s_id = ~0;
766 
768  {
769  if (unformat_user
770  (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
771  ;
772  else if (unformat (input, "disable"))
773  vtr_op = L2_VTR_DISABLED;
774  else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop"))
775  vtr_op = L2_VTR_POP_2;
776  else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push"))
777  vtr_op = L2_VTR_PUSH_2;
778  else if (vtr_op == L2_VTR_DISABLED
779  && unformat (input, "translate_pbb_stag %d", &outer_tag))
780  vtr_op = L2_VTR_TRANSLATE_2_1;
781  else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac))
782  dmac_set = 1;
783  else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
784  smac_set = 1;
785  else if (unformat (input, "b_vlanid %d", &tmp))
786  b_vlanid = tmp;
787  else if (unformat (input, "s_id %d", &s_id))
788  ;
789  else
790  {
791  error = clib_error_return (0,
792  "expecting [disable | pop | push | translate_pbb_stag <outer_tag>\n"
793  "dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]");
794  goto done;
795  }
796  }
797 
798  if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
799  && (!dmac_set || !smac_set || s_id == ~0))
800  {
801  error = clib_error_return (0,
802  "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
803  goto done;
804  }
805 
806  if (l2pbb_configure
807  (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
808  {
809  error =
811  "pbb tag rewrite is not compatible with interface");
812  goto done;
813  }
814 
815 done:
816  return error;
817 }
818 
819 /* *INDENT-OFF* */
820 VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = {
821  .path = "set interface l2 pbb-tag-rewrite",
822  .short_help = "set interface l2 pbb-tag-rewrite <interface> [disable | pop | push | translate_pbb_stag <outer_tag> dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]",
823  .function = int_l2_pbb_vtr,
824 };
825 /* *INDENT-ON* */
826 
827 /*
828  * fd.io coding-style-patch-verification: ON
829  *
830  * Local Variables:
831  * eval: (c-set-style "gnu")
832  * End:
833  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
u8 push_bytes
Definition: l2_vtr.h:62
u32 l2vtr_configure(vlib_main_t *vlib_main, vnet_main_t *vnet_main, u32 sw_if_index, u32 vtr_op, u32 push_dot1q, u32 vtr_tag1, u32 vtr_tag2)
Configure vtag tag rewrite on the given interface.
Definition: l2_vtr.c:136
clib_error_t * l2_vtr_init(vlib_main_t *vm)
Just a placeholder; ensures file is not eliminated by linker.
Definition: l2_vtr.c:46
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u8 pop_bytes
Definition: l2_vtr.h:63
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
u8 src_address[6]
Definition: packet.h:56
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
vlib_main_t * vm
Definition: in2out_ed.c:1580
unformat_function_t unformat_vnet_sw_interface
unsigned char u8
Definition: types.h:56
u16 push_and_pop_bytes
Definition: l2_vtr.h:65
Per-interface vlan tag rewrite configuration There will be one instance of this struct for each sw_if...
Definition: l2_vtr.h:46
u16 push_and_pop_bytes
Definition: l2_vtr.h:197
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
ptr_config_t output_pbb_vtr
Definition: l2_output.h:39
u8 dst_address[6]
Definition: packet.h:55
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
u8 push_bytes
Definition: l2_vtr.h:194
Definition: cJSON.c:84
vnet_sub_interface_t sub
Definition: interface.h:759
vtr_config_t input_vtr
Definition: l2_output.h:36
struct _unformat_input_t unformat_input_t
struct vnet_sub_interface_t::@376::@377::@379 flags
unsigned short u16
Definition: types.h:57
vnet_main_t vnet_main
Definition: misc.c:43
l2output_main_t l2output_main
Definition: l2_output.c:77
struct vnet_sub_interface_t::@376 eth
vnet_hw_interface_class_t ethernet_hw_interface_class
u32 l2pbb_configure(vlib_main_t *vlib_main, vnet_main_t *vnet_main, u32 sw_if_index, u32 vtr_op, u8 *b_dmac, u8 *b_smac, u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag)
Definition: l2_vtr.c:54
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
static vnet_hw_interface_t * vnet_get_sup_hw_interface_api_visible_or_null(vnet_main_t *vnm, u32 sw_if_index)
#define clib_warning(format, args...)
Definition: error.h:59
u8 pop_bytes
Definition: l2_vtr.h:195
vtr_config_t output_vtr
Definition: l2_output.h:37
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:233
struct ptr_config_t::@485::@489 raw_data
u32 l2input_intf_bitmap_enable(u32 sw_if_index, l2input_feat_masks_t feature_bitmap, u32 enable)
Enable (or disable) the feature in the bitmap for the given interface.
Definition: l2_input.c:177
u64 raw_tags
Definition: l2_vtr.h:55
static clib_error_t * int_l2_vtr(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set subinterface vtr enable/disable.
Definition: l2_vtr.c:507
vl_api_ip4_address_t hi
Definition: arp.api:37
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:2130
ptr_config_t input_pbb_vtr
Definition: l2_output.h:38
ethernet_vlan_header_tv_t tags[2]
Definition: l2_vtr.h:54
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
l2_output_config_t * configs
Definition: l2_output.h:67
ethernet_pbb_header_t macs_tags
Definition: l2_vtr.h:181
u32 l2vtr_get(vlib_main_t *vlib_main, vnet_main_t *vnet_main, u32 sw_if_index, u32 *vtr_op, u32 *push_dot1q, u32 *vtr_tag1, u32 *vtr_tag2)
Get vtag tag rewrite on the given interface.
Definition: l2_vtr.c:347
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
vnet_sw_interface_type_t type
Definition: interface.h:737
static clib_error_t * int_l2_pbb_vtr(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Set subinterface pbb vtr enable/disable.
Definition: l2_vtr.c:753
u8 si
Definition: lisp_types.api:47
u32 priority_dei_uca_res_sid
Definition: packet.h:182
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
u32 l2pbb_get(vlib_main_t *vlib_main, vnet_main_t *vnet_main, u32 sw_if_index, u32 *vtr_op, u16 *outer_tag, ethernet_header_t *eth_hdr, u16 *b_vlanid, u32 *i_sid)
Get pbb tag rewrite on the given interface.
Definition: l2_vtr.c:686
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170