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);
55 * Configure vtag tag rewrite on the given interface.
56 * Return 1 if there is an error, 0 if ok
59 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 */
60 u32 vtr_tag1, /* first pushed tag */
61 u32 vtr_tag2) /* second pushed tag */
63 vnet_hw_interface_t *hi;
64 vnet_sw_interface_t *si;
67 vtr_config_t *in_config;
68 vtr_config_t *out_config;
74 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
75 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
77 error = VNET_API_ERROR_INVALID_INTERFACE; /* non-ethernet interface */
81 /* Init the config for this interface */
82 vec_validate (l2output_main.configs, sw_if_index);
84 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
86 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->output_vtr);
87 in_config->raw_tags = 0;
88 out_config->raw_tags = 0;
90 /* Get the configured tags for the interface */
91 si = vnet_get_sw_interface (vnet_main, sw_if_index);
92 hw_no_tags = (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
94 /* Construct the input tag-rewrite config */
97 clib_net_to_host_u16 (push_dot1q ? ETHERNET_TYPE_VLAN :
98 ETHERNET_TYPE_DOT1AD);
99 push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
100 vtr_tag1 = clib_net_to_host_u16 (vtr_tag1);
101 vtr_tag2 = clib_net_to_host_u16 (vtr_tag2);
103 /* Determine number of vlan tags with explictly configured values */
105 if (hw_no_tags || si->sub.eth.flags.no_tags)
109 else if (si->sub.eth.flags.one_tag)
112 if (si->sub.eth.flags.outer_vlan_id_any)
117 else if (si->sub.eth.flags.two_tags)
120 if (si->sub.eth.flags.inner_vlan_id_any)
124 if (si->sub.eth.flags.outer_vlan_id_any)
132 case L2_VTR_DISABLED:
133 in_config->push_and_pop_bytes = 0;
139 /* Need one or two tags */
140 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;
143 in_config->pop_bytes = 4;
144 in_config->push_bytes = 0;
150 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
153 in_config->pop_bytes = 8;
154 in_config->push_bytes = 0;
156 out_config->push_bytes = in_config->pop_bytes;
157 out_config->pop_bytes = in_config->push_bytes;
161 in_config->pop_bytes = 0;
162 in_config->push_bytes = 4;
163 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
164 in_config->tags[1].type = push_outer_et;
168 in_config->pop_bytes = 0;
169 in_config->push_bytes = 8;
170 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
171 in_config->tags[0].type = push_outer_et;
172 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
173 in_config->tags[1].type = push_inner_et;
176 case L2_VTR_TRANSLATE_1_1:
179 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
182 in_config->pop_bytes = 4;
183 in_config->push_bytes = 4;
184 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
185 in_config->tags[1].type = push_outer_et;
188 case L2_VTR_TRANSLATE_1_2:
191 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */
194 in_config->pop_bytes = 4;
195 in_config->push_bytes = 8;
196 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
197 in_config->tags[0].type = push_outer_et;
198 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
199 in_config->tags[1].type = push_inner_et;
202 case L2_VTR_TRANSLATE_2_1:
205 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
208 in_config->pop_bytes = 8;
209 in_config->push_bytes = 4;
210 in_config->tags[1].priority_cfi_and_id = vtr_tag1;
211 in_config->tags[1].type = push_outer_et;
214 case L2_VTR_TRANSLATE_2_2:
217 error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */
220 in_config->pop_bytes = 8;
221 in_config->push_bytes = 8;
222 in_config->tags[0].priority_cfi_and_id = vtr_tag1;
223 in_config->tags[0].type = push_outer_et;
224 in_config->tags[1].priority_cfi_and_id = vtr_tag2;
225 in_config->tags[1].type = push_inner_et;
230 * Construct the output tag-rewrite config
232 * The push/pop values are always reversed
234 out_config->push_bytes = in_config->pop_bytes;
235 out_config->pop_bytes = in_config->push_bytes;
237 /* Any pushed tags are derived from the subinterface config */
239 clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
241 push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
242 vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id);
243 vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id);
245 if (out_config->push_bytes == 4)
247 out_config->tags[1].priority_cfi_and_id = vtr_tag1;
248 out_config->tags[1].type = push_outer_et;
250 else if (out_config->push_bytes == 8)
252 out_config->tags[0].priority_cfi_and_id = vtr_tag1;
253 out_config->tags[0].type = push_outer_et;
254 out_config->tags[1].priority_cfi_and_id = vtr_tag2;
255 out_config->tags[1].type = push_inner_et;
258 /* set the interface enable flags */
259 enable = (vtr_op != L2_VTR_DISABLED);
260 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
261 /* output vtr enable is checked explicitly in l2_output */
268 * Get vtag tag rewrite on the given interface.
269 * Return 1 if there is an error, 0 if ok
272 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 */
273 u32 * vtr_tag1, /* first pushed tag */
274 u32 * vtr_tag2) /* second pushed tag */
276 vnet_hw_interface_t *hi;
278 vtr_config_t *in_config;
280 if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
282 clib_warning ("invalid arguments");
283 error = VNET_API_ERROR_INVALID_ARGUMENT;
287 *vtr_op = L2_VTR_DISABLED;
292 hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
293 if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
295 /* non-ethernet interface */
299 if (sw_if_index >= vec_len (l2output_main.configs))
301 /* no specific config (return disabled) */
305 /* Get the config for this interface */
307 &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
310 if (in_config->push_and_pop_bytes == 0)
315 /* find out vtr_op */
316 switch (in_config->pop_bytes)
319 switch (in_config->push_bytes)
325 *vtr_op = L2_VTR_PUSH_1;
327 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
329 (ETHERNET_TYPE_VLAN ==
330 clib_host_to_net_u16 (in_config->tags[1].type));
333 *vtr_op = L2_VTR_PUSH_2;
335 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
337 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
339 (ETHERNET_TYPE_VLAN ==
340 clib_host_to_net_u16 (in_config->tags[0].type));
343 clib_warning ("invalid push_bytes count: %d",
344 in_config->push_bytes);
345 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
351 switch (in_config->push_bytes)
354 *vtr_op = L2_VTR_POP_1;
357 *vtr_op = L2_VTR_TRANSLATE_1_1;
359 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
361 (ETHERNET_TYPE_VLAN ==
362 clib_host_to_net_u16 (in_config->tags[1].type));
365 *vtr_op = L2_VTR_TRANSLATE_1_2;
367 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
369 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
371 (ETHERNET_TYPE_VLAN ==
372 clib_host_to_net_u16 (in_config->tags[0].type));
375 clib_warning ("invalid push_bytes count: %d",
376 in_config->push_bytes);
377 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
383 switch (in_config->push_bytes)
386 *vtr_op = L2_VTR_POP_2;
389 *vtr_op = L2_VTR_TRANSLATE_2_1;
391 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
393 (ETHERNET_TYPE_VLAN ==
394 clib_host_to_net_u16 (in_config->tags[1].type));
397 *vtr_op = L2_VTR_TRANSLATE_2_2;
399 clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
401 clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
403 (ETHERNET_TYPE_VLAN ==
404 clib_host_to_net_u16 (in_config->tags[0].type));
407 clib_warning ("invalid push_bytes count: %d",
408 in_config->push_bytes);
409 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
415 clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
416 error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
425 * Set subinterface vtr enable/disable.
427 * set interface l2 tag-rewrite <interface> [disable | pop 1 | pop 2 | push {dot1q|dot1ad} <tag> [<tag>]]
429 * "push" can also be replaced by "translate-{1|2}-{1|2}"
431 static clib_error_t *
432 int_l2_vtr (vlib_main_t * vm,
433 unformat_input_t * input, vlib_cli_command_t * cmd)
435 vnet_main_t *vnm = vnet_get_main ();
436 clib_error_t *error = 0;
440 u32 tag1 = 0, tag2 = 0;
442 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
444 error = clib_error_return (0, "unknown interface `%U'",
445 format_unformat_error, input);
449 vtr_op = L2_VTR_DISABLED;
451 if (unformat (input, "disable"))
453 vtr_op = L2_VTR_DISABLED;
455 else if (unformat (input, "pop 1"))
457 vtr_op = L2_VTR_POP_1;
459 else if (unformat (input, "pop 2"))
461 vtr_op = L2_VTR_POP_2;
464 else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
466 vtr_op = L2_VTR_PUSH_2;
469 else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
471 vtr_op = L2_VTR_PUSH_2;
474 else if (unformat (input, "push dot1q %d", &tag1))
476 vtr_op = L2_VTR_PUSH_1;
479 else if (unformat (input, "push dot1ad %d", &tag1))
481 vtr_op = L2_VTR_PUSH_1;
484 else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
486 vtr_op = L2_VTR_TRANSLATE_1_1;
489 else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
491 vtr_op = L2_VTR_TRANSLATE_1_1;
494 else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
496 vtr_op = L2_VTR_TRANSLATE_2_1;
499 else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
501 vtr_op = L2_VTR_TRANSLATE_2_1;
504 else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
506 vtr_op = L2_VTR_TRANSLATE_2_2;
509 else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
511 vtr_op = L2_VTR_TRANSLATE_2_2;
514 else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
516 vtr_op = L2_VTR_TRANSLATE_1_2;
519 else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
521 vtr_op = L2_VTR_TRANSLATE_1_2;
527 clib_error_return (0,
528 "expecting [disable | pop 1 | pop 2 | push {dot1q|dot1ah} <tag> [<tag>]\n"
529 " | translate {1|2}-{1|2} {dot1q|dot1ah} <tag> [<tag>]] but got `%U'",
530 format_unformat_error, input);
534 if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
537 clib_error_return (0,
538 "vlan tag rewrite is not compatible with interface");
547 * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
548 * Existing tags can be popped, new tags can be pushed, and existing tags can
549 * be swapped with new tags. The rewrite feature is attached to a subinterface
550 * as input and output operations. The input operation is explicitly configured.
551 * The output operation is the symmetric opposite and is automatically derived
552 * from the input operation.
554 * <b>POP:</b> For pop operations, the subinterface encapsulation (the vlan
555 * tags specified when it was created) must have at least the number of popped
556 * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface.
557 * The output tag-rewrite operation for pops is to push the specified number of
558 * vlan tags onto the packet. The pushed tag values are the ones in the
559 * subinterface encapsulation.
561 * <b>PUSH:</b> For push operations, the ethertype is also specified. The
562 * output tag-rewrite operation for pushes is to pop the same number of tags
563 * off the packet. If the packet doesn't have enough tags it is dropped.
568 * By default a subinterface has no tag-rewrite. To return a subinterface to
570 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
572 * To pop vlan tags off packets received from a subinterface, use:
573 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1}
574 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2}
576 * To push one or two vlan tags onto packets received from an interface, use:
577 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100}
578 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150}
580 * Tags can also be translated, which is basically a combination of a pop and push.
581 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100}
582 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150}
583 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100}
584 * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150}
586 * To display the VLAN Tag settings, show the associate bridge-domain:
587 * @cliexstart{show bridge-domain 200 detail}
588 * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf
589 * 200 1 on on on on off N/A
591 * Interface Index SHG BVI VLAN-Tag-Rewrite
592 * GigabitEthernet0/8/0.200 5 0 - trans-1-1 dot1ad 100
593 * GigabitEthernet0/9/0.200 4 0 - none
594 * GigabitEthernet0/a/0.200 6 0 - none
599 VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
600 .path = "set interface l2 tag-rewrite",
601 .short_help = "set interface l2 tag-rewrite <interface> [disable | pop {1|2} | push {dot1q|dot1ad} <tag> <tag>]",
602 .function = int_l2_vtr,
608 * fd.io coding-style-patch-verification: ON
611 * eval: (c-set-style "gnu")