2 * l2_vtr.c : layer 2 vlan tag rewrite configuration
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
29 #include <vppinfra/error.h>
34 * @brief Ethernet VLAN Tag Rewrite.
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.
44 /** Just a placeholder; ensures file is not eliminated by linker. */
46 l2_vtr_init (vlib_main_t * vm)
51 VLIB_INIT_FUNCTION (l2_vtr_init);
54 l2pbb_configure (vlib_main_t * vlib_main,
55 vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op,
56 u8 * b_dmac, u8 * b_smac,
57 u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag)
62 l2_output_config_t *config = 0;
63 vnet_hw_interface_t *hi;
64 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
68 error = VNET_API_ERROR_INVALID_INTERFACE;
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);
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);
88 if (vtr_op == L2_VTR_POP_2)
90 in_config->pop_bytes = sizeof (ethernet_pbb_header_packed_t);
92 else if (vtr_op == L2_VTR_PUSH_2)
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);
104 in_config->macs_tags.priority_dei_uca_res_sid =
105 clib_net_to_host_u32 (i_sid & 0xFFFFF);
106 in_config->push_bytes = sizeof (ethernet_pbb_header_packed_t);
108 else if (vtr_op == L2_VTR_TRANSLATE_2_2)
114 * Construct the output tag-rewrite config
116 * The push/pop values are always reversed
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;
123 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
125 config->out_vtr_flag = (u8) enable;
127 /* output vtr enable is checked explicitly in l2_output */
132 * Configure vtag tag rewrite on the given interface.
133 * Return 1 if there is an error, 0 if ok
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 */
140 vnet_hw_interface_t *hi;
141 vnet_sw_interface_t *si;
144 l2_output_config_t *config;
145 vtr_config_t *in_config;
146 vtr_config_t *out_config;
152 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
153 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
155 error = VNET_API_ERROR_INVALID_INTERFACE; /* non-ethernet interface */
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;
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);
171 /* Construct the input tag-rewrite config */
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);
180 /* Determine number of vlan tags with explicitly configured values */
182 if (hw_no_tags || si->sub.eth.flags.no_tags)
186 else if (si->sub.eth.flags.one_tag)
189 if (si->sub.eth.flags.outer_vlan_id_any)
194 else if (si->sub.eth.flags.two_tags)
197 if (si->sub.eth.flags.inner_vlan_id_any)
201 if (si->sub.eth.flags.outer_vlan_id_any)
209 case L2_VTR_DISABLED:
210 in_config->push_and_pop_bytes = 0;
216 /* Need one or two tags */
217 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;
220 in_config->pop_bytes = 4;
221 in_config->push_bytes = 0;
227 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
230 in_config->pop_bytes = 8;
231 in_config->push_bytes = 0;
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;
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;
250 case L2_VTR_TRANSLATE_1_1:
253 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
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;
262 case L2_VTR_TRANSLATE_1_2:
265 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
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;
276 case L2_VTR_TRANSLATE_2_1:
279 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
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;
288 case L2_VTR_TRANSLATE_2_2:
291 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
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;
304 * Construct the output tag-rewrite config
306 * The push/pop values are always reversed
308 out_config->push_bytes = in_config->pop_bytes;
309 out_config->pop_bytes = in_config->push_bytes;
311 /* Any pushed tags are derived from the subinterface config */
313 clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
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);
319 if (out_config->push_bytes == 4)
321 out_config->tags[1].priority_cfi_and_id = vtr_tag1;
322 out_config->tags[1].type = push_outer_et;
324 else if (out_config->push_bytes == 8)
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;
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 */
343 * Get vtag tag rewrite on the given interface.
344 * Return 1 if there is an error, 0 if ok
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 */
351 vnet_hw_interface_t *hi;
353 vtr_config_t *in_config;
355 if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
357 clib_warning ("invalid arguments");
358 error = VNET_API_ERROR_INVALID_ARGUMENT;
362 *vtr_op = L2_VTR_DISABLED;
367 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
368 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
370 /* non-ethernet interface */
374 if (sw_if_index >= vec_len (l2output_main.configs))
376 /* no specific config (return disabled) */
380 /* Get the config for this interface */
382 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
385 if (in_config->push_and_pop_bytes == 0)
390 /* find out vtr_op */
391 switch (in_config->pop_bytes)
394 switch (in_config->push_bytes)
400 *vtr_op = L2_VTR_PUSH_1;
402 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
404 (ETHERNET_TYPE_VLAN ==
405 clib_host_to_net_u16 (in_config->tags[1].type));
408 *vtr_op = L2_VTR_PUSH_2;
410 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
412 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
414 (ETHERNET_TYPE_VLAN ==
415 clib_host_to_net_u16 (in_config->tags[0].type));
418 clib_warning ("invalid push_bytes count: %d",
419 in_config->push_bytes);
420 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
426 switch (in_config->push_bytes)
429 *vtr_op = L2_VTR_POP_1;
432 *vtr_op = L2_VTR_TRANSLATE_1_1;
434 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
436 (ETHERNET_TYPE_VLAN ==
437 clib_host_to_net_u16 (in_config->tags[1].type));
440 *vtr_op = L2_VTR_TRANSLATE_1_2;
442 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
444 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
446 (ETHERNET_TYPE_VLAN ==
447 clib_host_to_net_u16 (in_config->tags[0].type));
450 clib_warning ("invalid push_bytes count: %d",
451 in_config->push_bytes);
452 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
458 switch (in_config->push_bytes)
461 *vtr_op = L2_VTR_POP_2;
464 *vtr_op = L2_VTR_TRANSLATE_2_1;
466 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
468 (ETHERNET_TYPE_VLAN ==
469 clib_host_to_net_u16 (in_config->tags[1].type));
472 *vtr_op = L2_VTR_TRANSLATE_2_2;
474 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
476 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
478 (ETHERNET_TYPE_VLAN ==
479 clib_host_to_net_u16 (in_config->tags[0].type));
482 clib_warning ("invalid push_bytes count: %d",
483 in_config->push_bytes);
484 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
490 clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
491 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
500 * Set subinterface vtr enable/disable.
502 * set interface l2 tag-rewrite <interface> [disable | pop 1 | pop 2 | push {dot1q|dot1ad} <tag> [<tag>]]
504 * "push" can also be replaced by "translate-{1|2}-{1|2}"
506 static clib_error_t *
507 int_l2_vtr (vlib_main_t * vm,
508 unformat_input_t * input, vlib_cli_command_t * cmd)
510 vnet_main_t *vnm = vnet_get_main ();
511 clib_error_t *error = 0;
515 u32 tag1 = 0, tag2 = 0;
517 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
519 error = clib_error_return (0, "unknown interface `%U'",
520 format_unformat_error, input);
524 vtr_op = L2_VTR_DISABLED;
526 if (unformat (input, "disable"))
528 vtr_op = L2_VTR_DISABLED;
530 else if (unformat (input, "pop 1"))
532 vtr_op = L2_VTR_POP_1;
534 else if (unformat (input, "pop 2"))
536 vtr_op = L2_VTR_POP_2;
539 else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
541 vtr_op = L2_VTR_PUSH_2;
544 else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
546 vtr_op = L2_VTR_PUSH_2;
549 else if (unformat (input, "push dot1q %d", &tag1))
551 vtr_op = L2_VTR_PUSH_1;
554 else if (unformat (input, "push dot1ad %d", &tag1))
556 vtr_op = L2_VTR_PUSH_1;
559 else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
561 vtr_op = L2_VTR_TRANSLATE_1_1;
564 else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
566 vtr_op = L2_VTR_TRANSLATE_1_1;
569 else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
571 vtr_op = L2_VTR_TRANSLATE_2_1;
574 else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
576 vtr_op = L2_VTR_TRANSLATE_2_1;
579 else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
581 vtr_op = L2_VTR_TRANSLATE_2_2;
584 else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
586 vtr_op = L2_VTR_TRANSLATE_2_2;
589 else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
591 vtr_op = L2_VTR_TRANSLATE_1_2;
594 else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
596 vtr_op = L2_VTR_TRANSLATE_1_2;
602 clib_error_return (0,
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);
609 if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
612 clib_error_return (0,
613 "vlan tag rewrite is not compatible with interface");
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.
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.
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.
643 * By default a subinterface has no tag-rewrite. To return a subinterface to
645 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
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}
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}
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}
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
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
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,
682 * Get pbb tag rewrite on the given interface.
683 * Return 1 if there is an error, 0 if ok
686 l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index,
687 u32 * vtr_op, u16 * outer_tag, ethernet_header_t * eth_hdr,
688 u16 * b_vlanid, u32 * i_sid)
691 ptr_config_t *in_config;
693 if (!vtr_op || !outer_tag || !b_vlanid || !i_sid)
695 clib_warning ("invalid arguments");
696 error = VNET_API_ERROR_INVALID_ARGUMENT;
700 *vtr_op = L2_VTR_DISABLED;
705 if (sw_if_index >= vec_len (l2output_main.configs))
707 /* no specific config (return disabled) */
711 /* Get the config for this interface */
713 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_pbb_vtr);
715 if (in_config->push_and_pop_bytes == 0)
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;
729 clib_memcpy_fast (ð_hdr->dst_address,
730 in_config->macs_tags.b_dst_address,
731 sizeof (eth_hdr->dst_address));
732 clib_memcpy_fast (ð_hdr->src_address,
733 in_config->macs_tags.b_src_address,
734 sizeof (eth_hdr->src_address));
737 clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF;
739 clib_host_to_net_u32 (in_config->macs_tags.
740 priority_dei_uca_res_sid) & 0xFFFFF;
748 * Set subinterface pbb vtr enable/disable.
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>]]
752 static clib_error_t *
753 int_l2_pbb_vtr (vlib_main_t * vm,
754 unformat_input_t * input, vlib_cli_command_t * cmd)
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;
763 u8 dmac_set = 0, smac_set = 0;
767 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
770 (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
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))
783 else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
785 else if (unformat (input, "b_vlanid %d", &tmp))
787 else if (unformat (input, "s_id %d", &s_id))
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>]]");
798 if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
799 && (!dmac_set || !smac_set || s_id == ~0))
801 error = clib_error_return (0,
802 "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
807 (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
810 clib_error_return (0,
811 "pbb tag rewrite is not compatible with interface");
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,
828 * fd.io coding-style-patch-verification: ON
831 * eval: (c-set-style "gnu")