dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / src / vnet / l2 / l2_vtr.c
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. */
45 clib_error_t *
46 l2_vtr_init (vlib_main_t * vm)
47 {
48   return 0;
49 }
50
51 VLIB_INIT_FUNCTION (l2_vtr_init);
52
53 u32
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)
58 {
59   u32 error = 0;
60   u32 enable = 0;
61
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);
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 (in_config->macs_tags.b_dst_address, b_dmac,
95                    sizeof (in_config->macs_tags.b_dst_address));
96       clib_memcpy (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);
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 {
140   vnet_hw_interface_t *hi;
141   vnet_sw_interface_t *si;
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 (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 explictly 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
233       out_config->push_bytes = in_config->pop_bytes;
234       out_config->pop_bytes = in_config->push_bytes;
235       break;
236
237     case L2_VTR_PUSH_1:
238       in_config->pop_bytes = 0;
239       in_config->push_bytes = 4;
240       in_config->tags[1].priority_cfi_and_id = vtr_tag1;
241       in_config->tags[1].type = push_outer_et;
242       break;
243
244     case L2_VTR_PUSH_2:
245       in_config->pop_bytes = 0;
246       in_config->push_bytes = 8;
247       in_config->tags[0].priority_cfi_and_id = vtr_tag1;
248       in_config->tags[0].type = push_outer_et;
249       in_config->tags[1].priority_cfi_and_id = vtr_tag2;
250       in_config->tags[1].type = push_inner_et;
251       break;
252
253     case L2_VTR_TRANSLATE_1_1:
254       if (cfg_tags < 1)
255         {
256           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need one or two tags */
257           goto done;
258         }
259       in_config->pop_bytes = 4;
260       in_config->push_bytes = 4;
261       in_config->tags[1].priority_cfi_and_id = vtr_tag1;
262       in_config->tags[1].type = push_outer_et;
263       break;
264
265     case L2_VTR_TRANSLATE_1_2:
266       if (cfg_tags < 1)
267         {
268           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need one or two tags */
269           goto done;
270         }
271       in_config->pop_bytes = 4;
272       in_config->push_bytes = 8;
273       in_config->tags[0].priority_cfi_and_id = vtr_tag1;
274       in_config->tags[0].type = push_outer_et;
275       in_config->tags[1].priority_cfi_and_id = vtr_tag2;
276       in_config->tags[1].type = push_inner_et;
277       break;
278
279     case L2_VTR_TRANSLATE_2_1:
280       if (cfg_tags < 2)
281         {
282           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need two tags */
283           goto done;
284         }
285       in_config->pop_bytes = 8;
286       in_config->push_bytes = 4;
287       in_config->tags[1].priority_cfi_and_id = vtr_tag1;
288       in_config->tags[1].type = push_outer_et;
289       break;
290
291     case L2_VTR_TRANSLATE_2_2:
292       if (cfg_tags < 2)
293         {
294           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need two tags */
295           goto done;
296         }
297       in_config->pop_bytes = 8;
298       in_config->push_bytes = 8;
299       in_config->tags[0].priority_cfi_and_id = vtr_tag1;
300       in_config->tags[0].type = push_outer_et;
301       in_config->tags[1].priority_cfi_and_id = vtr_tag2;
302       in_config->tags[1].type = push_inner_et;
303       break;
304     }
305
306   /*
307    *  Construct the output tag-rewrite config
308    *
309    *  The push/pop values are always reversed
310    */
311   out_config->push_bytes = in_config->pop_bytes;
312   out_config->pop_bytes = in_config->push_bytes;
313
314   /* Any pushed tags are derived from the subinterface config */
315   push_outer_et =
316     clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
317                           ETHERNET_TYPE_VLAN);
318   push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
319   vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id);
320   vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id);
321
322   if (out_config->push_bytes == 4)
323     {
324       out_config->tags[1].priority_cfi_and_id = vtr_tag1;
325       out_config->tags[1].type = push_outer_et;
326     }
327   else if (out_config->push_bytes == 8)
328     {
329       out_config->tags[0].priority_cfi_and_id = vtr_tag1;
330       out_config->tags[0].type = push_outer_et;
331       out_config->tags[1].priority_cfi_and_id = vtr_tag2;
332       out_config->tags[1].type = push_inner_et;
333     }
334
335   /* set the interface enable flags */
336   enable = (vtr_op != L2_VTR_DISABLED);
337   config->out_vtr_flag = (u8) enable;
338   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
339   /* output vtr enable is checked explicitly in l2_output */
340
341 done:
342   return error;
343 }
344
345 /**
346  * Get vtag tag rewrite on the given interface.
347  * Return 1 if there is an error, 0 if ok
348  */
349 u32
350 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 */
351            u32 * vtr_tag1,      /* first pushed tag */
352            u32 * vtr_tag2)      /* second pushed tag */
353 {
354   vnet_hw_interface_t *hi;
355   u32 error = 0;
356   vtr_config_t *in_config;
357
358   if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
359     {
360       clib_warning ("invalid arguments");
361       error = VNET_API_ERROR_INVALID_ARGUMENT;
362       goto done;
363     }
364
365   *vtr_op = L2_VTR_DISABLED;
366   *vtr_tag1 = 0;
367   *vtr_tag2 = 0;
368   *push_dot1q = 0;
369
370   hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
371   if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
372     {
373       /* non-ethernet interface */
374       goto done;
375     }
376
377   if (sw_if_index >= vec_len (l2output_main.configs))
378     {
379       /* no specific config (return disabled) */
380       goto done;
381     }
382
383   /* Get the config for this interface */
384   in_config =
385     &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
386
387   /* DISABLED */
388   if (in_config->push_and_pop_bytes == 0)
389     {
390       goto done;
391     }
392
393   /* find out vtr_op */
394   switch (in_config->pop_bytes)
395     {
396     case 0:
397       switch (in_config->push_bytes)
398         {
399         case 0:
400           /* DISABLED */
401           goto done;
402         case 4:
403           *vtr_op = L2_VTR_PUSH_1;
404           *vtr_tag1 =
405             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
406           *push_dot1q =
407             (ETHERNET_TYPE_VLAN ==
408              clib_host_to_net_u16 (in_config->tags[1].type));
409           break;
410         case 8:
411           *vtr_op = L2_VTR_PUSH_2;
412           *vtr_tag1 =
413             clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
414           *vtr_tag2 =
415             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
416           *push_dot1q =
417             (ETHERNET_TYPE_VLAN ==
418              clib_host_to_net_u16 (in_config->tags[0].type));
419           break;
420         default:
421           clib_warning ("invalid push_bytes count: %d",
422                         in_config->push_bytes);
423           error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
424           goto done;
425         }
426       break;
427
428     case 4:
429       switch (in_config->push_bytes)
430         {
431         case 0:
432           *vtr_op = L2_VTR_POP_1;
433           break;
434         case 4:
435           *vtr_op = L2_VTR_TRANSLATE_1_1;
436           *vtr_tag1 =
437             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
438           *push_dot1q =
439             (ETHERNET_TYPE_VLAN ==
440              clib_host_to_net_u16 (in_config->tags[1].type));
441           break;
442         case 8:
443           *vtr_op = L2_VTR_TRANSLATE_1_2;
444           *vtr_tag1 =
445             clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
446           *vtr_tag2 =
447             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
448           *push_dot1q =
449             (ETHERNET_TYPE_VLAN ==
450              clib_host_to_net_u16 (in_config->tags[0].type));
451           break;
452         default:
453           clib_warning ("invalid push_bytes count: %d",
454                         in_config->push_bytes);
455           error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
456           goto done;
457         }
458       break;
459
460     case 8:
461       switch (in_config->push_bytes)
462         {
463         case 0:
464           *vtr_op = L2_VTR_POP_2;
465           break;
466         case 4:
467           *vtr_op = L2_VTR_TRANSLATE_2_1;
468           *vtr_tag1 =
469             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
470           *push_dot1q =
471             (ETHERNET_TYPE_VLAN ==
472              clib_host_to_net_u16 (in_config->tags[1].type));
473           break;
474         case 8:
475           *vtr_op = L2_VTR_TRANSLATE_2_2;
476           *vtr_tag1 =
477             clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
478           *vtr_tag2 =
479             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
480           *push_dot1q =
481             (ETHERNET_TYPE_VLAN ==
482              clib_host_to_net_u16 (in_config->tags[0].type));
483           break;
484         default:
485           clib_warning ("invalid push_bytes count: %d",
486                         in_config->push_bytes);
487           error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
488           goto done;
489         }
490       break;
491
492     default:
493       clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
494       error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
495       goto done;
496     }
497
498 done:
499   return error;
500 }
501
502 /**
503  * Set subinterface vtr enable/disable.
504  * The CLI format is:
505  *    set interface l2 tag-rewrite <interface> [disable | pop 1 | pop 2 | push {dot1q|dot1ad} <tag> [<tag>]]
506  *
507  *  "push" can also be replaced by "translate-{1|2}-{1|2}"
508  */
509 static clib_error_t *
510 int_l2_vtr (vlib_main_t * vm,
511             unformat_input_t * input, vlib_cli_command_t * cmd)
512 {
513   vnet_main_t *vnm = vnet_get_main ();
514   clib_error_t *error = 0;
515   u32 sw_if_index;
516   u32 vtr_op;
517   u32 push_dot1q = 0;
518   u32 tag1 = 0, tag2 = 0;
519
520   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
521     {
522       error = clib_error_return (0, "unknown interface `%U'",
523                                  format_unformat_error, input);
524       goto done;
525     }
526
527   vtr_op = L2_VTR_DISABLED;
528
529   if (unformat (input, "disable"))
530     {
531       vtr_op = L2_VTR_DISABLED;
532     }
533   else if (unformat (input, "pop 1"))
534     {
535       vtr_op = L2_VTR_POP_1;
536     }
537   else if (unformat (input, "pop 2"))
538     {
539       vtr_op = L2_VTR_POP_2;
540
541     }
542   else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
543     {
544       vtr_op = L2_VTR_PUSH_2;
545       push_dot1q = 1;
546     }
547   else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
548     {
549       vtr_op = L2_VTR_PUSH_2;
550
551     }
552   else if (unformat (input, "push dot1q %d", &tag1))
553     {
554       vtr_op = L2_VTR_PUSH_1;
555       push_dot1q = 1;
556     }
557   else if (unformat (input, "push dot1ad %d", &tag1))
558     {
559       vtr_op = L2_VTR_PUSH_1;
560
561     }
562   else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
563     {
564       vtr_op = L2_VTR_TRANSLATE_1_1;
565       push_dot1q = 1;
566     }
567   else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
568     {
569       vtr_op = L2_VTR_TRANSLATE_1_1;
570
571     }
572   else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
573     {
574       vtr_op = L2_VTR_TRANSLATE_2_1;
575       push_dot1q = 1;
576     }
577   else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
578     {
579       vtr_op = L2_VTR_TRANSLATE_2_1;
580
581     }
582   else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
583     {
584       vtr_op = L2_VTR_TRANSLATE_2_2;
585       push_dot1q = 1;
586     }
587   else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
588     {
589       vtr_op = L2_VTR_TRANSLATE_2_2;
590
591     }
592   else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
593     {
594       vtr_op = L2_VTR_TRANSLATE_1_2;
595       push_dot1q = 1;
596     }
597   else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
598     {
599       vtr_op = L2_VTR_TRANSLATE_1_2;
600
601     }
602   else
603     {
604       error =
605         clib_error_return (0,
606                            "expecting [disable | pop 1 | pop 2 | push {dot1q|dot1ah} <tag> [<tag>]\n"
607                            " | translate {1|2}-{1|2} {dot1q|dot1ah} <tag> [<tag>]] but got `%U'",
608                            format_unformat_error, input);
609       goto done;
610     }
611
612   if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
613     {
614       error =
615         clib_error_return (0,
616                            "vlan tag rewrite is not compatible with interface");
617       goto done;
618     }
619
620 done:
621   return error;
622 }
623
624 /*?
625  * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
626  * Existing tags can be popped, new tags can be pushed, and existing tags can
627  * be swapped with new tags. The rewrite feature is attached to a subinterface
628  * as input and output operations. The input operation is explicitly configured.
629  * The output operation is the symmetric opposite and is automatically derived
630  * from the input operation.
631  *
632  * <b>POP:</b> For pop operations, the subinterface encapsulation (the vlan
633  * tags specified when it was created) must have at least the number of popped
634  * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface.
635  * The output tag-rewrite operation for pops is to push the specified number of
636  * vlan tags onto the packet. The pushed tag values are the ones in the
637  * subinterface encapsulation.
638  *
639  * <b>PUSH:</b> For push operations, the ethertype is also specified. The
640  * output tag-rewrite operation for pushes is to pop the same number of tags
641  * off the packet. If the packet doesn't have enough tags it is dropped.
642  *
643  *
644  * @cliexpar
645  * @parblock
646  * By default a subinterface has no tag-rewrite. To return a subinterface to
647  * this state use:
648  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
649  *
650  * To pop vlan tags off packets received from a subinterface, use:
651  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1}
652  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2}
653  *
654  * To push one or two vlan tags onto packets received from an interface, use:
655  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100}
656  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150}
657  *
658  * Tags can also be translated, which is basically a combination of a pop and push.
659  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100}
660  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150}
661  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100}
662  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150}
663  *
664  * To display the VLAN Tag settings, show the associate bridge-domain:
665  * @cliexstart{show bridge-domain 200 detail}
666  *  ID   Index   Learning   U-Forwrd   UU-Flood   Flooding   ARP-Term     BVI-Intf
667  * 200     1        on         on         on         on         off          N/A
668  *
669  *          Interface           Index  SHG  BVI        VLAN-Tag-Rewrite
670  *  GigabitEthernet0/8/0.200      5     0    -       trans-1-1 dot1ad 100
671  *  GigabitEthernet0/9/0.200      4     0    -               none
672  *  GigabitEthernet0/a/0.200      6     0    -               none
673  * @cliexend
674  * @endparblock
675 ?*/
676 /* *INDENT-OFF* */
677 VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
678   .path = "set interface l2 tag-rewrite",
679   .short_help = "set interface l2 tag-rewrite <interface> [disable | pop {1|2} | push {dot1q|dot1ad} <tag> <tag>]",
680   .function = int_l2_vtr,
681 };
682 /* *INDENT-ON* */
683
684 /**
685  * Set subinterface pbb vtr enable/disable.
686  * The CLI format is:
687  *    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>]]
688  */
689 static clib_error_t *
690 int_l2_pbb_vtr (vlib_main_t * vm,
691                 unformat_input_t * input, vlib_cli_command_t * cmd)
692 {
693   vnet_main_t *vnm = vnet_get_main ();
694   clib_error_t *error = 0;
695   u32 sw_if_index, tmp;
696   u32 vtr_op = L2_VTR_DISABLED;
697   u32 outer_tag = 0;
698   u8 dmac[6];
699   u8 smac[6];
700   u8 dmac_set = 0, smac_set = 0;
701   u16 b_vlanid = 0;
702   u32 s_id = ~0;
703
704   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
705     {
706       if (unformat_user
707           (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
708         ;
709       else if (unformat (input, "disable"))
710         vtr_op = L2_VTR_DISABLED;
711       else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop"))
712         vtr_op = L2_VTR_POP_2;
713       else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push"))
714         vtr_op = L2_VTR_PUSH_2;
715       else if (vtr_op == L2_VTR_DISABLED
716                && unformat (input, "translate_pbb_stag %d", &outer_tag))
717         vtr_op = L2_VTR_TRANSLATE_2_1;
718       else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac))
719         dmac_set = 1;
720       else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
721         smac_set = 1;
722       else if (unformat (input, "b_vlanid %d", &tmp))
723         b_vlanid = tmp;
724       else if (unformat (input, "s_id %d", &s_id))
725         ;
726       else
727         {
728           error = clib_error_return (0,
729                                      "expecting [disable | pop | push | translate_pbb_stag <outer_tag>\n"
730                                      "dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]");
731           goto done;
732         }
733     }
734
735   if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
736       && (!dmac_set || !smac_set || s_id == ~0))
737     {
738       error = clib_error_return (0,
739                                  "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
740       goto done;
741     }
742
743   if (l2pbb_configure
744       (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
745     {
746       error =
747         clib_error_return (0,
748                            "pbb tag rewrite is not compatible with interface");
749       goto done;
750     }
751
752 done:
753   return error;
754 }
755
756 /* *INDENT-OFF* */
757 VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = {
758   .path = "set interface l2 pbb-tag-rewrite",
759   .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>]]",
760   .function = int_l2_pbb_vtr,
761 };
762 /* *INDENT-ON* */
763
764 /*
765  * fd.io coding-style-patch-verification: ON
766  *
767  * Local Variables:
768  * eval: (c-set-style "gnu")
769  * End:
770  */