FD.io VPP  v21.06-3-gbb25fbf28
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;
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;
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 
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 */
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 */
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 
368  if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
369  {
370  /* non-ethernet interface */
371  goto done;
372  }
373 
375  {
376  /* no specific config (return disabled) */
377  goto done;
378  }
379 
380  /* Get the config for this interface */
381  in_config =
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 
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* */
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 
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;
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  {
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  {
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* */
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  */
vlib.h
tmp
u32 * tmp
Definition: interface_output.c:1078
ethernet_vlan_header_tv_t::priority_cfi_and_id
u16 priority_cfi_and_id
Definition: packet.h:164
L2_VTR_TRANSLATE_2_2
@ L2_VTR_TRANSLATE_2_2
Definition: l2_vtr.h:38
unformat_ethernet_address
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:233
unformat_user
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
l2_output_config_t::output_pbb_vtr
ptr_config_t output_pbb_vtr
Definition: l2_output.h:39
ptr_config_t::macs_tags
ethernet_pbb_header_t macs_tags
Definition: l2_vtr.h:181
vnet_sw_interface_t::type
vnet_sw_interface_type_t type
Definition: interface.h:870
vnet_sw_interface_t
Definition: interface.h:868
vnet_sub_interface_t::outer_vlan_id
u16 outer_vlan_id
Definition: interface.h:782
l2pbb_get
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
int_l2_vtr_cli
static vlib_cli_command_t int_l2_vtr_cli
(constructor) VLIB_CLI_COMMAND (int_l2_vtr_cli)
Definition: l2_vtr.c:674
vnet_sub_interface_t::inner_vlan_id
u16 inner_vlan_id
Definition: interface.h:783
ethernet_header_t::dst_address
u8 dst_address[6]
Definition: packet.h:55
ethernet_header_t::src_address
u8 src_address[6]
Definition: packet.h:56
vtr_config_t::push_and_pop_bytes
u16 push_and_pop_bytes
Definition: l2_vtr.h:65
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
u8
#define u8
Padding.
Definition: clib.h:121
vlib_cli_command_t::path
char * path
Definition: cli.h:96
ptr_config_t::push_and_pop_bytes
u16 push_and_pop_bytes
Definition: l2_vtr.h:197
u16
unsigned short u16
Definition: types.h:57
ethernet_pbb_header_t::priority_dei_id
u16 priority_dei_id
Definition: packet.h:177
ethernet_hw_interface_class
vnet_hw_interface_class_t ethernet_hw_interface_class
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
l2vtr_configure
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
vnet_get_sw_interface
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
Definition: interface_funcs.h:58
vtr_config_t
Per-interface vlan tag rewrite configuration There will be one instance of this struct for each sw_if...
Definition: l2_vtr.h:46
hi
vl_api_ip4_address_t hi
Definition: arp.api:37
L2_VTR_TRANSLATE_1_1
@ L2_VTR_TRANSLATE_1_1
Definition: l2_vtr.h:35
unformat_input_t
struct _unformat_input_t unformat_input_t
vtr_config_t::push_bytes
u8 push_bytes
Definition: l2_vtr.h:62
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
ethernet.h
error
Definition: cJSON.c:88
vtr_config_t::pop_bytes
u8 pop_bytes
Definition: l2_vtr.h:63
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
l2_output_config_t::input_pbb_vtr
ptr_config_t input_pbb_vtr
Definition: l2_output.h:38
ethernet_pbb_header_t::b_type
u16 b_type
Definition: packet.h:175
vnet_sub_interface_t::eth
struct vnet_sub_interface_t::@368 eth
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
packet.h
l2_output_config_t::out_vtr_flag
u8 out_vtr_flag
Definition: l2_output.h:47
error.h
vnet_sw_interface_t::sub
vnet_sub_interface_t sub
Definition: interface.h:892
ethernet_pbb_header_t::i_type
u16 i_type
Definition: packet.h:180
l2_output.h
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
vnet_get_main
vnet_main_t * vnet_get_main(void)
Definition: pnat_test_stubs.h:56
unformat_check_input
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
vnet_get_sup_hw_interface_api_visible_or_null
static vnet_hw_interface_t * vnet_get_sup_hw_interface_api_visible_or_null(vnet_main_t *vnm, u32 sw_if_index)
Definition: interface_funcs.h:101
L2_VTR_DISABLED
@ L2_VTR_DISABLED
Definition: l2_vtr.h:30
ethernet_pbb_header_t::b_dst_address
u8 b_dst_address[6]
Definition: packet.h:171
ethernet_pbb_header_t::b_src_address
u8 b_src_address[6]
Definition: packet.h:172
l2_output_config_t::output_vtr
vtr_config_t output_vtr
Definition: l2_output.h:37
l2_vtr.h
ethernet_header_t
Definition: packet.h:52
l2input_intf_bitmap_enable
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
L2_VTR_POP_1
@ L2_VTR_POP_1
Definition: l2_vtr.h:33
format_unformat_error
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
L2_VTR_PUSH_1
@ L2_VTR_PUSH_1
Definition: l2_vtr.h:31
ptr_config_t::push_bytes
u8 push_bytes
Definition: l2_vtr.h:194
l2pbb_configure
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
ptr_config_t::raw_data
struct ptr_config_t::@477::@481 raw_data
l2_input.h
vnet_sub_interface_t::flags
struct vnet_sub_interface_t::@368::@369::@371 flags
vnet_hw_interface_t
Definition: interface.h:638
vnet_main_t
Definition: vnet.h:76
vtr_config_t::raw_tags
u64 raw_tags
Definition: l2_vtr.h:55
int_l2_pbb_vtr_cli
static vlib_cli_command_t int_l2_pbb_vtr_cli
(constructor) VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli)
Definition: l2_vtr.c:820
unformat_vnet_sw_interface
unformat_function_t unformat_vnet_sw_interface
Definition: interface_funcs.h:459
u32
unsigned int u32
Definition: types.h:88
VLIB_INIT_FUNCTION
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
l2output_main
l2output_main_t l2output_main
Definition: l2_output.c:77
l2vtr_get
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
ptr_config_t
Definition: l2_vtr.h:177
ptr_config_t::pop_bytes
u8 pop_bytes
Definition: l2_vtr.h:195
cli.h
si
vnet_sw_interface_t * si
Definition: interface_output.c:398
L2_VTR_TRANSLATE_2_1
@ L2_VTR_TRANSLATE_2_1
Definition: l2_vtr.h:37
l2_output_config_t
Definition: l2_output.h:28
ethernet_vlan_header_tv_t::type
u16 type
Definition: packet.h:161
vnet_main
vnet_main_t vnet_main
Definition: misc.c:43
vlib_main_t
Definition: main.h:102
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
feat_bitmap.h
vlib_init_function_t
clib_error_t *() vlib_init_function_t(struct vlib_main_t *vm)
Definition: init.h:51
L2_VTR_PUSH_2
@ L2_VTR_PUSH_2
Definition: l2_vtr.h:32
ethernet_pbb_header_t::priority_dei_uca_res_sid
u32 priority_dei_uca_res_sid
Definition: packet.h:182
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
int_l2_pbb_vtr
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
L2_VTR_TRANSLATE_1_2
@ L2_VTR_TRANSLATE_1_2
Definition: l2_vtr.h:36
vlib_main
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:1914
vnet.h
VNET_SW_INTERFACE_TYPE_HARDWARE
@ VNET_SW_INTERFACE_TYPE_HARDWARE
Definition: interface.h:763
vtr_config_t::tags
ethernet_vlan_header_tv_t tags[2]
Definition: l2_vtr.h:54
int_l2_vtr
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
vlib_cli_command_t
Definition: cli.h:92
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
l2_vtr_init
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
L2_VTR_POP_2
@ L2_VTR_POP_2
Definition: l2_vtr.h:34
l2output_main_t::configs
l2_output_config_t * configs
Definition: l2_output.h:67
l2_input_vtr.h
UNFORMAT_END_OF_INPUT
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
l2_output_config_t::input_vtr
vtr_config_t input_vtr
Definition: l2_output.h:36