LCOV - code coverage report
Current view: top level - vnet/l2 - l2_vtr.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 215 401 53.6 %
Date: 2023-10-26 01:39:38 Functions: 10 13 76.9 %

          Line data    Source code
       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         575 : l2_vtr_init (vlib_main_t * vm)
      47             : {
      48         575 :   return 0;
      49             : }
      50             : 
      51       24767 : VLIB_INIT_FUNCTION (l2_vtr_init);
      52             : 
      53             : u32
      54           0 : 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           0 :   u32 error = 0;
      60           0 :   u32 enable = 0;
      61             : 
      62           0 :   l2_output_config_t *config = 0;
      63             :   vnet_hw_interface_t *hi;
      64           0 :   hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
      65             : 
      66           0 :   if (!hi)
      67             :     {
      68           0 :       error = VNET_API_ERROR_INVALID_INTERFACE;
      69           0 :       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           0 :   config = vec_elt_at_index (l2output_main.configs, sw_if_index);
      76           0 :   in_config = &(config->input_pbb_vtr);
      77           0 :   out_config = &(config->output_pbb_vtr);
      78             : 
      79           0 :   in_config->pop_bytes = 0;
      80           0 :   in_config->push_bytes = 0;
      81           0 :   out_config->pop_bytes = 0;
      82           0 :   out_config->push_bytes = 0;
      83           0 :   enable = (vtr_op != L2_VTR_DISABLED);
      84             : 
      85           0 :   if (!enable)
      86           0 :     goto done;
      87             : 
      88           0 :   if (vtr_op == L2_VTR_POP_2)
      89             :     {
      90           0 :       in_config->pop_bytes = sizeof (ethernet_pbb_header_packed_t);
      91             :     }
      92           0 :   else if (vtr_op == L2_VTR_PUSH_2)
      93             :     {
      94           0 :       clib_memcpy_fast (in_config->macs_tags.b_dst_address, b_dmac,
      95             :                         sizeof (in_config->macs_tags.b_dst_address));
      96           0 :       clib_memcpy_fast (in_config->macs_tags.b_src_address, b_smac,
      97             :                         sizeof (in_config->macs_tags.b_src_address));
      98           0 :       in_config->macs_tags.b_type =
      99           0 :         clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AD);
     100           0 :       in_config->macs_tags.priority_dei_id =
     101           0 :         clib_net_to_host_u16 (b_vlanid & 0xFFF);
     102           0 :       in_config->macs_tags.i_type =
     103           0 :         clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AH);
     104           0 :       in_config->macs_tags.priority_dei_uca_res_sid =
     105           0 :         clib_net_to_host_u32 (i_sid & 0xFFFFF);
     106           0 :       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           0 :   out_config->raw_data = in_config->raw_data;
     119           0 :   out_config->pop_bytes = in_config->push_bytes;
     120           0 :   out_config->push_bytes = in_config->pop_bytes;
     121             : 
     122           0 : done:
     123           0 :   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
     124           0 :   if (config)
     125           0 :     config->out_vtr_flag = (u8) enable;
     126             : 
     127             :   /* output vtr enable is checked explicitly in l2_output */
     128           0 :   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         175 : 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         175 :   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         175 :   hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
     153         175 :   if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
     154             :     {
     155           0 :       error = VNET_API_ERROR_INVALID_INTERFACE; /* non-ethernet interface */
     156           0 :       goto done;
     157             :     }
     158             : 
     159             :   /* Init the config for this interface */
     160         175 :   vec_validate (l2output_main.configs, sw_if_index);
     161         175 :   config = vec_elt_at_index (l2output_main.configs, sw_if_index);
     162         175 :   in_config = &(config->input_vtr);
     163         175 :   out_config = &(config->output_vtr);
     164         175 :   in_config->raw_tags = 0;
     165         175 :   out_config->raw_tags = 0;
     166             : 
     167             :   /* Get the configured tags for the interface */
     168         175 :   si = vnet_get_sw_interface (vnet_main, sw_if_index);
     169         175 :   hw_no_tags = (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
     170             : 
     171             :   /* Construct the input tag-rewrite config */
     172             : 
     173         175 :   push_outer_et =
     174         175 :     clib_net_to_host_u16 (push_dot1q ? ETHERNET_TYPE_VLAN :
     175             :                           ETHERNET_TYPE_DOT1AD);
     176         175 :   push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
     177         175 :   vtr_tag1 = clib_net_to_host_u16 (vtr_tag1);
     178         175 :   vtr_tag2 = clib_net_to_host_u16 (vtr_tag2);
     179             : 
     180             :   /* Determine number of vlan tags with explicitly configured values */
     181         175 :   cfg_tags = 0;
     182         175 :   if (hw_no_tags || si->sub.eth.flags.no_tags)
     183             :     {
     184           4 :       cfg_tags = 0;
     185             :     }
     186         171 :   else if (si->sub.eth.flags.one_tag)
     187             :     {
     188         100 :       cfg_tags = 1;
     189         100 :       if (si->sub.eth.flags.outer_vlan_id_any)
     190             :         {
     191           0 :           cfg_tags = 0;
     192             :         }
     193             :     }
     194          71 :   else if (si->sub.eth.flags.two_tags)
     195             :     {
     196          48 :       cfg_tags = 2;
     197          48 :       if (si->sub.eth.flags.inner_vlan_id_any)
     198             :         {
     199           0 :           cfg_tags = 1;
     200             :         }
     201          48 :       if (si->sub.eth.flags.outer_vlan_id_any)
     202             :         {
     203           0 :           cfg_tags = 0;
     204             :         }
     205             :     }
     206             : 
     207         175 :   switch (vtr_op)
     208             :     {
     209         115 :     case L2_VTR_DISABLED:
     210         115 :       in_config->push_and_pop_bytes = 0;
     211         115 :       break;
     212             : 
     213          25 :     case L2_VTR_POP_1:
     214          25 :       if (cfg_tags < 1)
     215             :         {
     216             :           /* Need one or two tags */
     217           0 :           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;
     218           0 :           goto done;
     219             :         }
     220          25 :       in_config->pop_bytes = 4;
     221          25 :       in_config->push_bytes = 0;
     222          25 :       break;
     223             : 
     224          16 :     case L2_VTR_POP_2:
     225          16 :       if (cfg_tags < 2)
     226             :         {
     227           0 :           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need two tags */
     228           0 :           goto done;
     229             :         }
     230          16 :       in_config->pop_bytes = 8;
     231          16 :       in_config->push_bytes = 0;
     232          16 :       break;
     233             : 
     234           4 :     case L2_VTR_PUSH_1:
     235           4 :       in_config->pop_bytes = 0;
     236           4 :       in_config->push_bytes = 4;
     237           4 :       in_config->tags[1].priority_cfi_and_id = vtr_tag1;
     238           4 :       in_config->tags[1].type = push_outer_et;
     239           4 :       break;
     240             : 
     241           5 :     case L2_VTR_PUSH_2:
     242           5 :       in_config->pop_bytes = 0;
     243           5 :       in_config->push_bytes = 8;
     244           5 :       in_config->tags[0].priority_cfi_and_id = vtr_tag1;
     245           5 :       in_config->tags[0].type = push_outer_et;
     246           5 :       in_config->tags[1].priority_cfi_and_id = vtr_tag2;
     247           5 :       in_config->tags[1].type = push_inner_et;
     248           5 :       break;
     249             : 
     250           3 :     case L2_VTR_TRANSLATE_1_1:
     251           3 :       if (cfg_tags < 1)
     252             :         {
     253           0 :           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need one or two tags */
     254           0 :           goto done;
     255             :         }
     256           3 :       in_config->pop_bytes = 4;
     257           3 :       in_config->push_bytes = 4;
     258           3 :       in_config->tags[1].priority_cfi_and_id = vtr_tag1;
     259           3 :       in_config->tags[1].type = push_outer_et;
     260           3 :       break;
     261             : 
     262           3 :     case L2_VTR_TRANSLATE_1_2:
     263           3 :       if (cfg_tags < 1)
     264             :         {
     265           0 :           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need one or two tags */
     266           0 :           goto done;
     267             :         }
     268           3 :       in_config->pop_bytes = 4;
     269           3 :       in_config->push_bytes = 8;
     270           3 :       in_config->tags[0].priority_cfi_and_id = vtr_tag1;
     271           3 :       in_config->tags[0].type = push_outer_et;
     272           3 :       in_config->tags[1].priority_cfi_and_id = vtr_tag2;
     273           3 :       in_config->tags[1].type = push_inner_et;
     274           3 :       break;
     275             : 
     276           2 :     case L2_VTR_TRANSLATE_2_1:
     277           2 :       if (cfg_tags < 2)
     278             :         {
     279           0 :           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need two tags */
     280           0 :           goto done;
     281             :         }
     282           2 :       in_config->pop_bytes = 8;
     283           2 :       in_config->push_bytes = 4;
     284           2 :       in_config->tags[1].priority_cfi_and_id = vtr_tag1;
     285           2 :       in_config->tags[1].type = push_outer_et;
     286           2 :       break;
     287             : 
     288           2 :     case L2_VTR_TRANSLATE_2_2:
     289           2 :       if (cfg_tags < 2)
     290             :         {
     291           0 :           error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT;        /* Need two tags */
     292           0 :           goto done;
     293             :         }
     294           2 :       in_config->pop_bytes = 8;
     295           2 :       in_config->push_bytes = 8;
     296           2 :       in_config->tags[0].priority_cfi_and_id = vtr_tag1;
     297           2 :       in_config->tags[0].type = push_outer_et;
     298           2 :       in_config->tags[1].priority_cfi_and_id = vtr_tag2;
     299           2 :       in_config->tags[1].type = push_inner_et;
     300           2 :       break;
     301             :     }
     302             : 
     303             :   /*
     304             :    *  Construct the output tag-rewrite config
     305             :    *
     306             :    *  The push/pop values are always reversed
     307             :    */
     308         175 :   out_config->push_bytes = in_config->pop_bytes;
     309         175 :   out_config->pop_bytes = in_config->push_bytes;
     310             : 
     311             :   /* Any pushed tags are derived from the subinterface config */
     312         175 :   push_outer_et =
     313         175 :     clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD :
     314             :                           ETHERNET_TYPE_VLAN);
     315         175 :   push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN);
     316         175 :   vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id);
     317         175 :   vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id);
     318             : 
     319         175 :   if (out_config->push_bytes == 4)
     320             :     {
     321          31 :       out_config->tags[1].priority_cfi_and_id = vtr_tag1;
     322          31 :       out_config->tags[1].type = push_outer_et;
     323             :     }
     324         144 :   else if (out_config->push_bytes == 8)
     325             :     {
     326          20 :       out_config->tags[0].priority_cfi_and_id = vtr_tag1;
     327          20 :       out_config->tags[0].type = push_outer_et;
     328          20 :       out_config->tags[1].priority_cfi_and_id = vtr_tag2;
     329          20 :       out_config->tags[1].type = push_inner_et;
     330             :     }
     331             : 
     332             :   /* set the interface enable flags */
     333         175 :   enable = (vtr_op != L2_VTR_DISABLED);
     334         175 :   config->out_vtr_flag = (u8) enable;
     335         175 :   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable);
     336             :   /* output vtr enable is checked explicitly in l2_output */
     337             : 
     338         175 : done:
     339         175 :   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        8161 : 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             : {
     351             :   vnet_hw_interface_t *hi;
     352        8161 :   u32 error = 0;
     353             :   vtr_config_t *in_config;
     354             : 
     355        8161 :   if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2)
     356             :     {
     357           0 :       clib_warning ("invalid arguments");
     358           0 :       error = VNET_API_ERROR_INVALID_ARGUMENT;
     359           0 :       goto done;
     360             :     }
     361             : 
     362        8161 :   *vtr_op = L2_VTR_DISABLED;
     363        8161 :   *vtr_tag1 = 0;
     364        8161 :   *vtr_tag2 = 0;
     365        8161 :   *push_dot1q = 0;
     366             : 
     367        8161 :   hi = vnet_get_sup_hw_interface_api_visible_or_null (vnet_main, sw_if_index);
     368        8161 :   if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
     369             :     {
     370             :       /* non-ethernet interface */
     371         811 :       goto done;
     372             :     }
     373             : 
     374        7350 :   if (sw_if_index >= vec_len (l2output_main.configs))
     375             :     {
     376             :       /* no specific config (return disabled) */
     377         137 :       goto done;
     378             :     }
     379             : 
     380             :   /* Get the config for this interface */
     381        7213 :   in_config =
     382        7213 :     &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr);
     383             : 
     384             :   /* DISABLED */
     385        7213 :   if (in_config->push_and_pop_bytes == 0)
     386             :     {
     387        7178 :       goto done;
     388             :     }
     389             : 
     390             :   /* find out vtr_op */
     391          35 :   switch (in_config->pop_bytes)
     392             :     {
     393          11 :     case 0:
     394          11 :       switch (in_config->push_bytes)
     395             :         {
     396           0 :         case 0:
     397             :           /* DISABLED */
     398           0 :           goto done;
     399           5 :         case 4:
     400           5 :           *vtr_op = L2_VTR_PUSH_1;
     401           5 :           *vtr_tag1 =
     402           5 :             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
     403           5 :           *push_dot1q =
     404           5 :             (ETHERNET_TYPE_VLAN ==
     405           5 :              clib_host_to_net_u16 (in_config->tags[1].type));
     406           5 :           break;
     407           6 :         case 8:
     408           6 :           *vtr_op = L2_VTR_PUSH_2;
     409           6 :           *vtr_tag1 =
     410           6 :             clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
     411           6 :           *vtr_tag2 =
     412           6 :             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
     413           6 :           *push_dot1q =
     414           6 :             (ETHERNET_TYPE_VLAN ==
     415           6 :              clib_host_to_net_u16 (in_config->tags[0].type));
     416           6 :           break;
     417           0 :         default:
     418           0 :           clib_warning ("invalid push_bytes count: %d",
     419             :                         in_config->push_bytes);
     420           0 :           error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
     421           0 :           goto done;
     422             :         }
     423          11 :       break;
     424             : 
     425          11 :     case 4:
     426          11 :       switch (in_config->push_bytes)
     427             :         {
     428           2 :         case 0:
     429           2 :           *vtr_op = L2_VTR_POP_1;
     430           2 :           break;
     431           3 :         case 4:
     432           3 :           *vtr_op = L2_VTR_TRANSLATE_1_1;
     433           3 :           *vtr_tag1 =
     434           3 :             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
     435           3 :           *push_dot1q =
     436           3 :             (ETHERNET_TYPE_VLAN ==
     437           3 :              clib_host_to_net_u16 (in_config->tags[1].type));
     438           3 :           break;
     439           6 :         case 8:
     440           6 :           *vtr_op = L2_VTR_TRANSLATE_1_2;
     441           6 :           *vtr_tag1 =
     442           6 :             clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
     443           6 :           *vtr_tag2 =
     444           6 :             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
     445           6 :           *push_dot1q =
     446           6 :             (ETHERNET_TYPE_VLAN ==
     447           6 :              clib_host_to_net_u16 (in_config->tags[0].type));
     448           6 :           break;
     449           0 :         default:
     450           0 :           clib_warning ("invalid push_bytes count: %d",
     451             :                         in_config->push_bytes);
     452           0 :           error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
     453           0 :           goto done;
     454             :         }
     455          11 :       break;
     456             : 
     457          13 :     case 8:
     458          13 :       switch (in_config->push_bytes)
     459             :         {
     460           1 :         case 0:
     461           1 :           *vtr_op = L2_VTR_POP_2;
     462           1 :           break;
     463           2 :         case 4:
     464           2 :           *vtr_op = L2_VTR_TRANSLATE_2_1;
     465           2 :           *vtr_tag1 =
     466           2 :             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
     467           2 :           *push_dot1q =
     468           2 :             (ETHERNET_TYPE_VLAN ==
     469           2 :              clib_host_to_net_u16 (in_config->tags[1].type));
     470           2 :           break;
     471          10 :         case 8:
     472          10 :           *vtr_op = L2_VTR_TRANSLATE_2_2;
     473          10 :           *vtr_tag1 =
     474          10 :             clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id);
     475          10 :           *vtr_tag2 =
     476          10 :             clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id);
     477          10 :           *push_dot1q =
     478          10 :             (ETHERNET_TYPE_VLAN ==
     479          10 :              clib_host_to_net_u16 (in_config->tags[0].type));
     480          10 :           break;
     481           0 :         default:
     482           0 :           clib_warning ("invalid push_bytes count: %d",
     483             :                         in_config->push_bytes);
     484           0 :           error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
     485           0 :           goto done;
     486             :         }
     487          13 :       break;
     488             : 
     489           0 :     default:
     490           0 :       clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes);
     491           0 :       error = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
     492           0 :       goto done;
     493             :     }
     494             : 
     495        8161 : done:
     496        8161 :   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 *
     507           0 : int_l2_vtr (vlib_main_t * vm,
     508             :             unformat_input_t * input, vlib_cli_command_t * cmd)
     509             : {
     510           0 :   vnet_main_t *vnm = vnet_get_main ();
     511           0 :   clib_error_t *error = 0;
     512             :   u32 sw_if_index;
     513             :   u32 vtr_op;
     514           0 :   u32 push_dot1q = 0;
     515           0 :   u32 tag1 = 0, tag2 = 0;
     516             : 
     517           0 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     518             :     {
     519           0 :       error = clib_error_return (0, "unknown interface `%U'",
     520             :                                  format_unformat_error, input);
     521           0 :       goto done;
     522             :     }
     523             : 
     524           0 :   vtr_op = L2_VTR_DISABLED;
     525             : 
     526           0 :   if (unformat (input, "disable"))
     527             :     {
     528           0 :       vtr_op = L2_VTR_DISABLED;
     529             :     }
     530           0 :   else if (unformat (input, "pop 1"))
     531             :     {
     532           0 :       vtr_op = L2_VTR_POP_1;
     533             :     }
     534           0 :   else if (unformat (input, "pop 2"))
     535             :     {
     536           0 :       vtr_op = L2_VTR_POP_2;
     537             : 
     538             :     }
     539           0 :   else if (unformat (input, "push dot1q %d %d", &tag1, &tag2))
     540             :     {
     541           0 :       vtr_op = L2_VTR_PUSH_2;
     542           0 :       push_dot1q = 1;
     543             :     }
     544           0 :   else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2))
     545             :     {
     546           0 :       vtr_op = L2_VTR_PUSH_2;
     547             : 
     548             :     }
     549           0 :   else if (unformat (input, "push dot1q %d", &tag1))
     550             :     {
     551           0 :       vtr_op = L2_VTR_PUSH_1;
     552           0 :       push_dot1q = 1;
     553             :     }
     554           0 :   else if (unformat (input, "push dot1ad %d", &tag1))
     555             :     {
     556           0 :       vtr_op = L2_VTR_PUSH_1;
     557             : 
     558             :     }
     559           0 :   else if (unformat (input, "translate 1-1 dot1q %d", &tag1))
     560             :     {
     561           0 :       vtr_op = L2_VTR_TRANSLATE_1_1;
     562           0 :       push_dot1q = 1;
     563             :     }
     564           0 :   else if (unformat (input, "translate 1-1 dot1ad %d", &tag1))
     565             :     {
     566           0 :       vtr_op = L2_VTR_TRANSLATE_1_1;
     567             : 
     568             :     }
     569           0 :   else if (unformat (input, "translate 2-1 dot1q %d", &tag1))
     570             :     {
     571           0 :       vtr_op = L2_VTR_TRANSLATE_2_1;
     572           0 :       push_dot1q = 1;
     573             :     }
     574           0 :   else if (unformat (input, "translate 2-1 dot1ad %d", &tag1))
     575             :     {
     576           0 :       vtr_op = L2_VTR_TRANSLATE_2_1;
     577             : 
     578             :     }
     579           0 :   else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2))
     580             :     {
     581           0 :       vtr_op = L2_VTR_TRANSLATE_2_2;
     582           0 :       push_dot1q = 1;
     583             :     }
     584           0 :   else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2))
     585             :     {
     586           0 :       vtr_op = L2_VTR_TRANSLATE_2_2;
     587             : 
     588             :     }
     589           0 :   else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2))
     590             :     {
     591           0 :       vtr_op = L2_VTR_TRANSLATE_1_2;
     592           0 :       push_dot1q = 1;
     593             :     }
     594           0 :   else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2))
     595             :     {
     596           0 :       vtr_op = L2_VTR_TRANSLATE_1_2;
     597             : 
     598             :     }
     599             :   else
     600             :     {
     601             :       error =
     602           0 :         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);
     606           0 :       goto done;
     607             :     }
     608             : 
     609           0 :   if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2))
     610             :     {
     611             :       error =
     612           0 :         clib_error_return (0,
     613             :                            "vlan tag rewrite is not compatible with interface");
     614           0 :       goto done;
     615             :     }
     616             : 
     617           0 : done:
     618           0 :   return error;
     619             : }
     620             : 
     621             : /*?
     622             :  * VLAN tag rewrite provides the ability to change the VLAN tags on a packet.
     623             :  * Existing tags can be popped, new tags can be pushed, and existing tags can
     624             :  * be swapped with new tags. The rewrite feature is attached to a subinterface
     625             :  * as input and output operations. The input operation is explicitly configured.
     626             :  * The output operation is the symmetric opposite and is automatically derived
     627             :  * from the input operation.
     628             :  *
     629             :  * <b>POP:</b> For pop operations, the subinterface encapsulation (the vlan
     630             :  * tags specified when it was created) must have at least the number of popped
     631             :  * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface.
     632             :  * The output tag-rewrite operation for pops is to push the specified number of
     633             :  * vlan tags onto the packet. The pushed tag values are the ones in the
     634             :  * subinterface encapsulation.
     635             :  *
     636             :  * <b>PUSH:</b> For push operations, the ethertype is also specified. The
     637             :  * output tag-rewrite operation for pushes is to pop the same number of tags
     638             :  * off the packet. If the packet doesn't have enough tags it is dropped.
     639             :  *
     640             :  *
     641             :  * @cliexpar
     642             :  * @parblock
     643             :  * By default a subinterface has no tag-rewrite. To return a subinterface to
     644             :  * this state use:
     645             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable}
     646             :  *
     647             :  * To pop vlan tags off packets received from a subinterface, use:
     648             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1}
     649             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2}
     650             :  *
     651             :  * To push one or two vlan tags onto packets received from an interface, use:
     652             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100}
     653             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150}
     654             :  *
     655             :  * Tags can also be translated, which is basically a combination of a pop and push.
     656             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100}
     657             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150}
     658             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100}
     659             :  * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150}
     660             :  *
     661             :  * To display the VLAN Tag settings, show the associate bridge-domain:
     662             :  * @cliexstart{show bridge-domain 200 detail}
     663             :  *  ID   Index   Learning   U-Forwrd   UU-Flood   Flooding   ARP-Term     BVI-Intf
     664             :  * 200     1        on         on         on         on         off          N/A
     665             :  *
     666             :  *          Interface           Index  SHG  BVI        VLAN-Tag-Rewrite
     667             :  *  GigabitEthernet0/8/0.200      5     0    -       trans-1-1 dot1ad 100
     668             :  *  GigabitEthernet0/9/0.200      4     0    -               none
     669             :  *  GigabitEthernet0/a/0.200      6     0    -               none
     670             :  * @cliexend
     671             :  * @endparblock
     672             : ?*/
     673             : /* *INDENT-OFF* */
     674      285289 : VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = {
     675             :   .path = "set interface l2 tag-rewrite",
     676             :   .short_help = "set interface l2 tag-rewrite <interface> [disable | pop {1|2} | push {dot1q|dot1ad} <tag> <tag>]",
     677             :   .function = int_l2_vtr,
     678             : };
     679             : /* *INDENT-ON* */
     680             : 
     681             : /**
     682             :  * Get pbb tag rewrite on the given interface.
     683             :  * Return 1 if there is an error, 0 if ok
     684             :  */
     685             : u32
     686        7007 : 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)
     689             : {
     690        7007 :   u32 error = 1;
     691             :   ptr_config_t *in_config;
     692             : 
     693        7007 :   if (!vtr_op || !outer_tag || !b_vlanid || !i_sid)
     694             :     {
     695           0 :       clib_warning ("invalid arguments");
     696           0 :       error = VNET_API_ERROR_INVALID_ARGUMENT;
     697           0 :       goto done;
     698             :     }
     699             : 
     700        7007 :   *vtr_op = L2_VTR_DISABLED;
     701        7007 :   *outer_tag = 0;
     702        7007 :   *b_vlanid = 0;
     703        7007 :   *i_sid = 0;
     704             : 
     705        7007 :   if (sw_if_index >= vec_len (l2output_main.configs))
     706             :     {
     707             :       /* no specific config (return disabled) */
     708         241 :       goto done;
     709             :     }
     710             : 
     711             :   /* Get the config for this interface */
     712        6766 :   in_config =
     713        6766 :     &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_pbb_vtr);
     714             : 
     715        6766 :   if (in_config->push_and_pop_bytes == 0)
     716             :     {
     717             :       /* DISABLED */
     718        6766 :       goto done;
     719             :     }
     720             :   else
     721             :     {
     722           0 :       if (in_config->pop_bytes && in_config->push_bytes)
     723           0 :         *vtr_op = L2_VTR_TRANSLATE_2_1;
     724           0 :       else if (in_config->pop_bytes)
     725           0 :         *vtr_op = L2_VTR_POP_2;
     726           0 :       else if (in_config->push_bytes)
     727           0 :         *vtr_op = L2_VTR_PUSH_2;
     728             : 
     729           0 :       clib_memcpy_fast (&eth_hdr->dst_address,
     730           0 :                         in_config->macs_tags.b_dst_address,
     731             :                         sizeof (eth_hdr->dst_address));
     732           0 :       clib_memcpy_fast (&eth_hdr->src_address,
     733           0 :                         in_config->macs_tags.b_src_address,
     734             :                         sizeof (eth_hdr->src_address));
     735             : 
     736           0 :       *b_vlanid =
     737           0 :         clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF;
     738           0 :       *i_sid =
     739           0 :         clib_host_to_net_u32 (in_config->macs_tags.
     740           0 :                               priority_dei_uca_res_sid) & 0xFFFFF;
     741           0 :       error = 0;
     742             :     }
     743        7007 : done:
     744        7007 :   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 *
     753           0 : int_l2_pbb_vtr (vlib_main_t * vm,
     754             :                 unformat_input_t * input, vlib_cli_command_t * cmd)
     755             : {
     756           0 :   vnet_main_t *vnm = vnet_get_main ();
     757           0 :   clib_error_t *error = 0;
     758             :   u32 sw_if_index, tmp;
     759           0 :   u32 vtr_op = L2_VTR_DISABLED;
     760           0 :   u32 outer_tag = 0;
     761             :   u8 dmac[6];
     762             :   u8 smac[6];
     763           0 :   u8 dmac_set = 0, smac_set = 0;
     764           0 :   u16 b_vlanid = 0;
     765           0 :   u32 s_id = ~0;
     766             : 
     767           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     768             :     {
     769           0 :       if (unformat_user
     770             :           (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     771             :         ;
     772           0 :       else if (unformat (input, "disable"))
     773           0 :         vtr_op = L2_VTR_DISABLED;
     774           0 :       else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop"))
     775           0 :         vtr_op = L2_VTR_POP_2;
     776           0 :       else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push"))
     777           0 :         vtr_op = L2_VTR_PUSH_2;
     778           0 :       else if (vtr_op == L2_VTR_DISABLED
     779           0 :                && unformat (input, "translate_pbb_stag %d", &outer_tag))
     780           0 :         vtr_op = L2_VTR_TRANSLATE_2_1;
     781           0 :       else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac))
     782           0 :         dmac_set = 1;
     783           0 :       else if (unformat (input, "smac %U", unformat_ethernet_address, smac))
     784           0 :         smac_set = 1;
     785           0 :       else if (unformat (input, "b_vlanid %d", &tmp))
     786           0 :         b_vlanid = tmp;
     787           0 :       else if (unformat (input, "s_id %d", &s_id))
     788             :         ;
     789             :       else
     790             :         {
     791           0 :           error = clib_error_return (0,
     792             :                                      "expecting [disable | pop | push | translate_pbb_stag <outer_tag>\n"
     793             :                                      "dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]");
     794           0 :           goto done;
     795             :         }
     796             :     }
     797             : 
     798           0 :   if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1)
     799           0 :       && (!dmac_set || !smac_set || s_id == ~0))
     800             :     {
     801           0 :       error = clib_error_return (0,
     802             :                                  "expecting dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]");
     803           0 :       goto done;
     804             :     }
     805             : 
     806           0 :   if (l2pbb_configure
     807             :       (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag))
     808             :     {
     809             :       error =
     810           0 :         clib_error_return (0,
     811             :                            "pbb tag rewrite is not compatible with interface");
     812           0 :       goto done;
     813             :     }
     814             : 
     815           0 : done:
     816           0 :   return error;
     817             : }
     818             : 
     819             : /* *INDENT-OFF* */
     820      285289 : VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = {
     821             :   .path = "set interface l2 pbb-tag-rewrite",
     822             :   .short_help = "set interface l2 pbb-tag-rewrite <interface> [disable | pop | push | translate_pbb_stag <outer_tag> dmac <address> smac <address> s_id <nn> [b_vlanid <nn>]]",
     823             :   .function = int_l2_pbb_vtr,
     824             : };
     825             : /* *INDENT-ON* */
     826             : 
     827             : /*
     828             :  * fd.io coding-style-patch-verification: ON
     829             :  *
     830             :  * Local Variables:
     831             :  * eval: (c-set-style "gnu")
     832             :  * End:
     833             :  */

Generated by: LCOV version 1.14