LCOV - code coverage report
Current view: top level - vnet/srmpls - sr_mpls_policy.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 83 364 22.8 %
Date: 2023-10-26 01:39:38 Functions: 12 17 70.6 %

          Line data    Source code
       1             : /*
       2             :  * sr_mpls_policy.c: SR-MPLS policies
       3             :  *
       4             :  * Copyright (c) 2016 Cisco and/or its affiliates. Licensed under the Apache
       5             :  * License, Version 2.0 (the "License"); you may not use this file except in
       6             :  * compliance with the License. You may obtain a copy of the License at:
       7             :  *
       8             :  * http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
      12             :  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
      13             :  * License for the specific language governing permissions and limitations
      14             :  * under the License.
      15             :  */
      16             : 
      17             : /**
      18             :  * @file
      19             :  * @brief SR MPLS policy creation and application
      20             :  *
      21             :  * Create an SR policy.
      22             :  * An SR policy can be either of 'default' type or 'spray' type
      23             :  * An SR policy has attached a list of SID lists.
      24             :  * In case the SR policy is a default one it will load balance among them.
      25             :  * An SR policy has associated a BindingSID.
      26             :  * In case any packet arrives with MPLS_label == BindingSID then the SR policy
      27             :  * associated to such bindingSID will be applied to such packet.
      28             :  * Also, a BSID can be associated with a (Next-Hop, Color)
      29             :  *
      30             :  */
      31             : 
      32             : #include <vlib/vlib.h>
      33             : #include <vnet/vnet.h>
      34             : #include <vnet/srmpls/sr_mpls.h>
      35             : #include <vnet/fib/mpls_fib.h>
      36             : #include <vnet/dpo/dpo.h>
      37             : #include <vnet/ip/ip.h>
      38             : 
      39             : #include <vppinfra/error.h>
      40             : #include <vppinfra/elog.h>
      41             : 
      42             : mpls_sr_main_t sr_mpls_main;
      43             : 
      44             : /***************************  SR LB helper functions **************************/
      45             : /**
      46             :  * @brief Creates a Segment List and adds it to an SR policy
      47             :  *
      48             :  * Creates a Segment List and adds it to the SR policy. Notice that the SL are
      49             :  * not necessarily unique. Hence there might be two Segment List within the
      50             :  * same SR Policy with exactly the same segments and same weight.
      51             :  *
      52             :  * @param sr_policy is the SR policy where the SL will be added
      53             :  * @param sl is a vector of IPv6 addresses composing the Segment List
      54             :  * @param weight is the weight of the SegmentList (for load-balancing purposes)
      55             :  * @param is_encap represents the mode (SRH insertion vs Encapsulation)
      56             :  *
      57             :  * @return pointer to the just created segment list
      58             :  */
      59             : static inline mpls_sr_sl_t *
      60           2 : create_sl (mpls_sr_policy_t * sr_policy, mpls_label_t * sl, u32 weight)
      61             : {
      62           2 :   mpls_sr_main_t *sm = &sr_mpls_main;
      63             :   mpls_sr_sl_t *segment_list;
      64             :   u32 ii;
      65             : 
      66           2 :   pool_get (sm->sid_lists, segment_list);
      67           2 :   clib_memset (segment_list, 0, sizeof (*segment_list));
      68             : 
      69           2 :   vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
      70             : 
      71             :   /* Fill in segment list */
      72           2 :   segment_list->weight =
      73           2 :     (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
      74           2 :   segment_list->segments = vec_dup (sl);
      75             : 
      76             :   mpls_eos_bit_t eos;
      77           6 :   FOR_EACH_MPLS_EOS_BIT (eos)
      78             :   {
      79           4 :     fib_route_path_t path = {
      80             :       .frp_proto = DPO_PROTO_MPLS,
      81             :       .frp_sw_if_index = ~0,
      82             :       .frp_fib_index = 0,
      83           4 :       .frp_weight = segment_list->weight,
      84             :       .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
      85             :       .frp_label_stack = NULL,
      86           4 :       .frp_local_label = sl[0],
      87             :     };
      88             : 
      89           4 :     if (vec_len (sl) > 1)
      90             :       {
      91           2 :         vec_validate (path.frp_label_stack, vec_len (sl) - 2);
      92           6 :         for (ii = 1; ii < vec_len (sl); ii++)
      93             :           {
      94           4 :             path.frp_label_stack[ii - 1].fml_value = sl[ii];
      95             :           }
      96             :       }
      97             :     else
      98             :       {
      99             :         /*
     100             :          * add an impliciet NULL label to allow non-eos recursion
     101             :          */
     102           2 :         fib_mpls_label_t lbl = {
     103             :           .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
     104             :         };
     105           2 :         vec_add1 (path.frp_label_stack, lbl);
     106             :       }
     107             : 
     108           4 :     fib_route_path_t *paths = NULL;
     109           4 :     vec_add1 (paths, path);
     110             : 
     111             :     /* *INDENT-OFF* */
     112           4 :     fib_prefix_t pfx = {
     113             :         .fp_len = 21,
     114             :         .fp_proto = FIB_PROTOCOL_MPLS,
     115           4 :         .fp_label = sr_policy->bsid,
     116             :         .fp_eos = eos,
     117             :         .fp_payload_proto = DPO_PROTO_MPLS,
     118             :     };
     119             :     /* *INDENT-ON* */
     120             : 
     121           4 :     fib_table_entry_path_add2 (0,
     122             :                                &pfx,
     123             :                                FIB_SOURCE_SR,
     124           4 :                                (sr_policy->type == SR_POLICY_TYPE_DEFAULT ?
     125             :                                 FIB_ENTRY_FLAG_NONE :
     126             :                                 FIB_ENTRY_FLAG_MULTICAST), paths);
     127           4 :     vec_free (paths);
     128             :   }
     129             : 
     130           2 :   return segment_list;
     131             : }
     132             : 
     133             : /******************************* SR rewrite API *******************************/
     134             : /*
     135             :  * Three functions for handling sr policies: -> sr_mpls_policy_add ->
     136             :  * sr_mpls_policy_del -> sr_mpls_policy_mod All of them are API. CLI function
     137             :  * on sr_policy_command_fn
     138             :  */
     139             : 
     140             : /**
     141             :  * @brief Create a new SR policy
     142             :  *
     143             :  * @param bsid is the bindingSID of the SR Policy
     144             :  * @param segments is a vector of MPLS labels composing the segment list
     145             :  * @param behavior is the behavior of the SR policy. (default//spray)
     146             :  * @param fib_table is the VRF where to install the FIB entry for the BSID
     147             :  * @param weight is the weight of this specific SID list
     148             :  *
     149             :  * @return 0 if correct, else error
     150             :  */
     151             : int
     152           2 : sr_mpls_policy_add (mpls_label_t bsid, mpls_label_t * segments,
     153             :                     u8 behavior, u32 weight)
     154             : {
     155           2 :   mpls_sr_main_t *sm = &sr_mpls_main;
     156           2 :   mpls_sr_policy_t *sr_policy = 0;
     157             :   uword *p;
     158             : 
     159           2 :   if (!sm->sr_policies_index_hash)
     160           1 :     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
     161             : 
     162             :   /* MPLS SR policies cannot be created unless the MPLS table is present */
     163           2 :   if (~0 == fib_table_find (FIB_PROTOCOL_MPLS, MPLS_FIB_DEFAULT_TABLE_ID))
     164           0 :     return (VNET_API_ERROR_NO_SUCH_TABLE);
     165             : 
     166             :   /* Search for existing keys (BSID) */
     167           2 :   p = hash_get (sm->sr_policies_index_hash, bsid);
     168           2 :   if (p)
     169             :     {
     170             :       /* Add SR policy that already exists; complain */
     171           0 :       return -12;
     172             :     }
     173             :   /* Add an SR policy object */
     174           2 :   pool_get (sm->sr_policies, sr_policy);
     175           2 :   clib_memset (sr_policy, 0, sizeof (*sr_policy));
     176             : 
     177             :   /* the first policy needs to lock the MPLS table so it doesn't
     178             :    * disappear with policies in it */
     179           2 :   if (1 == pool_elts (sm->sr_policies))
     180           2 :     fib_table_find_or_create_and_lock (FIB_PROTOCOL_MPLS,
     181             :                                        MPLS_FIB_DEFAULT_TABLE_ID,
     182             :                                        FIB_SOURCE_SR);
     183           2 :   sr_policy->bsid = bsid;
     184           2 :   sr_policy->type = behavior;
     185           2 :   sr_policy->endpoint_type = 0;
     186           2 :   ip6_address_set_zero (&sr_policy->endpoint.ip6);
     187           2 :   sr_policy->color = (u32) ~ 0;
     188             : 
     189             :   /* Copy the key */
     190           2 :   hash_set (sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies);
     191             : 
     192             :   /* Create a segment list and add the index to the SR policy */
     193           2 :   create_sl (sr_policy, segments, weight);
     194             : 
     195           2 :   return 0;
     196             : }
     197             : 
     198             : /**
     199             :  * @brief Delete a SR policy
     200             :  *
     201             :  * @param bsid is the bindingSID of the SR Policy
     202             :  * @param index is the index of the SR policy
     203             :  *
     204             :  * @return 0 if correct, else error
     205             :  */
     206             : int
     207           2 : sr_mpls_policy_del (mpls_label_t bsid)
     208             : {
     209           2 :   mpls_sr_main_t *sm = &sr_mpls_main;
     210           2 :   mpls_sr_policy_t *sr_policy = 0;
     211             :   mpls_sr_sl_t *segment_list;
     212             :   mpls_eos_bit_t eos;
     213             :   u32 *sl_index;
     214             :   uword *p;
     215             : 
     216           2 :   if (!sm->sr_policies_index_hash)
     217           0 :     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
     218             : 
     219           2 :   p = hash_get (sm->sr_policies_index_hash, bsid);
     220           2 :   if (p)
     221           2 :     sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
     222             :   else
     223           0 :     return -1;
     224             : 
     225             :   /* Clean SID Lists */
     226           4 :   vec_foreach (sl_index, sr_policy->segments_lists)
     227             :   {
     228           2 :     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
     229             : 
     230           2 :     fib_route_path_t path = {
     231             :       .frp_proto = DPO_PROTO_MPLS,
     232             :       .frp_sw_if_index = ~0,
     233             :       .frp_fib_index = 0,
     234           2 :       .frp_weight = segment_list->weight,
     235             :       .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
     236           2 :       .frp_local_label = segment_list->segments[0],
     237             :     };
     238             : 
     239           2 :     vec_add (path.frp_label_stack, segment_list + 1,
     240             :              vec_len (segment_list) - 1);
     241             : 
     242           2 :     fib_route_path_t *paths = NULL;
     243           2 :     vec_add1 (paths, path);
     244             : 
     245             :     /* remove each of the MPLS routes */
     246           6 :     FOR_EACH_MPLS_EOS_BIT (eos)
     247             :     {
     248             :                         /* *INDENT-OFF* */
     249           4 :                         fib_prefix_t    pfx = {
     250             :                                 .fp_len = 21,
     251             :                                 .fp_proto = FIB_PROTOCOL_MPLS,
     252           4 :                                 .fp_label = sr_policy->bsid,
     253             :                                 .fp_eos = eos,
     254             :                                 .fp_payload_proto = DPO_PROTO_MPLS,
     255             :                         };
     256             :                         /* *INDENT-ON* */
     257             : 
     258           4 :       fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
     259             :     }
     260           2 :     vec_free (paths);
     261           2 :     vec_free (segment_list->segments);
     262           2 :     pool_put_index (sm->sid_lists, *sl_index);
     263             :   }
     264             : 
     265             :   /* If there is still traces of TE, make sure locks are released */
     266           2 :   if (sr_policy->endpoint_type != 0 && sr_policy->color != (u32) ~ 0)
     267             :     {
     268           0 :       sr_mpls_policy_assign_endpoint_color (bsid, NULL, 0, (u32) ~ 0);
     269             :     }
     270             : 
     271             :   /* Remove SR policy entry */
     272           2 :   hash_unset (sm->sr_policies_index_hash, sr_policy->bsid);
     273           2 :   pool_put (sm->sr_policies, sr_policy);
     274             : 
     275           2 :   if (0 == pool_elts (sm->sr_policies))
     276           2 :     fib_table_unlock (MPLS_FIB_DEFAULT_TABLE_ID,
     277             :                       FIB_PROTOCOL_MPLS, FIB_SOURCE_SR);
     278             : 
     279           2 :   return 0;
     280             : }
     281             : 
     282             : /**
     283             :  * @brief Modify an existing SR policy
     284             :  *
     285             :  * The possible modifications are adding a new Segment List, modifying an
     286             :  * existing Segment List (modify the weight only) and delete a given
     287             :  * Segment List from the SR Policy.
     288             :  *
     289             :  * @param bsid is the bindingSID of the SR Policy
     290             :  * @param fib_table is the VRF where to install the FIB entry for the BSID
     291             :  * @param operation is the operation to perform (among the top ones)
     292             :  * @param segments is a vector of IPv6 address composing the segment list
     293             :  * @param sl_index is the index of the Segment List to modify/delete
     294             :  * @param weight is the weight of the sid list. optional.
     295             :  *
     296             :  * @return 0 ok, >0 index of SL, <0 error
     297             :  */
     298             : int
     299           0 : sr_mpls_policy_mod (mpls_label_t bsid, u8 operation,
     300             :                     mpls_label_t * segments, u32 sl_index, u32 weight)
     301             : {
     302           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     303           0 :   mpls_sr_policy_t *sr_policy = 0;
     304             :   mpls_sr_sl_t *segment_list;
     305             :   u32 *sl_index_iterate;
     306             :   uword *p;
     307             : 
     308           0 :   if (!sm->sr_policies_index_hash)
     309           0 :     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
     310             : 
     311           0 :   p = hash_get (sm->sr_policies_index_hash, bsid);
     312           0 :   if (p)
     313           0 :     sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
     314             :   else
     315           0 :     return -1;
     316             : 
     317           0 :   if (operation == 1)
     318             :     {                           /* Add SR List to an existing SR policy */
     319             :       /* Create the new SL */
     320           0 :       segment_list = create_sl (sr_policy, segments, weight);
     321           0 :       return segment_list - sm->sid_lists;
     322             :     }
     323           0 :   else if (operation == 2)
     324             :     {                           /* Delete SR List from an existing SR
     325             :                                  * policy */
     326             :       /* Check that currently there are more than one SID list */
     327           0 :       if (vec_len (sr_policy->segments_lists) == 1)
     328           0 :         return -21;
     329             : 
     330             :       /*
     331             :        * Check that the SR list does exist and is assigned to the
     332             :        * sr policy
     333             :        */
     334           0 :       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
     335           0 :         if (*sl_index_iterate == sl_index)
     336           0 :         break;
     337             : 
     338           0 :       if (*sl_index_iterate != sl_index)
     339           0 :         return -22;
     340             : 
     341             :       /* Remove the lucky SR list that is being kicked out */
     342           0 :       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
     343             : 
     344             :       mpls_eos_bit_t eos;
     345           0 :       fib_route_path_t path = {
     346             :         .frp_proto = DPO_PROTO_MPLS,
     347             :         .frp_sw_if_index = ~0,
     348             :         .frp_fib_index = 0,
     349           0 :         .frp_weight = segment_list->weight,
     350             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
     351           0 :         .frp_local_label = segment_list->segments[0],
     352             :       };
     353             : 
     354           0 :       vec_add (path.frp_label_stack, segment_list + 1,
     355             :                vec_len (segment_list) - 1);
     356             : 
     357           0 :       fib_route_path_t *paths = NULL;
     358           0 :       vec_add1 (paths, path);
     359             : 
     360           0 :       FOR_EACH_MPLS_EOS_BIT (eos)
     361             :       {
     362             :                         /* *INDENT-OFF* */
     363           0 :                         fib_prefix_t    pfx = {
     364             :                                 .fp_len = 21,
     365             :                                 .fp_proto = FIB_PROTOCOL_MPLS,
     366           0 :                                 .fp_label = sr_policy->bsid,
     367             :                                 .fp_eos = eos,
     368             :                                 .fp_payload_proto = DPO_PROTO_MPLS,
     369             :                         };
     370             :                         /* *INDENT-ON* */
     371             : 
     372           0 :         fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
     373             :       }
     374             : 
     375           0 :       vec_free (paths);
     376           0 :       vec_free (segment_list->segments);
     377           0 :       pool_put_index (sm->sid_lists, sl_index);
     378           0 :       vec_del1 (sr_policy->segments_lists,
     379             :                 sl_index_iterate - sr_policy->segments_lists);
     380             :     }
     381           0 :   else if (operation == 3)
     382             :     {                           /* Modify the weight of an existing
     383             :                                  * SR List */
     384             :       /* Find the corresponding SL */
     385           0 :       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
     386           0 :         if (*sl_index_iterate == sl_index)
     387           0 :         break;
     388             : 
     389           0 :       if (*sl_index_iterate != sl_index)
     390           0 :         return -32;
     391             : 
     392             :       /* Change the weight */
     393           0 :       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
     394             : 
     395             :       /* Update LB */
     396             :       mpls_eos_bit_t eos;
     397           0 :       fib_route_path_t path = {
     398             :         .frp_proto = DPO_PROTO_MPLS,
     399             :         .frp_sw_if_index = ~0,
     400             :         .frp_fib_index = 0,
     401           0 :         .frp_weight = segment_list->weight,
     402             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
     403           0 :         .frp_local_label = segment_list->segments[0],
     404             :       };
     405             : 
     406           0 :       vec_add (path.frp_label_stack, segment_list + 1,
     407             :                vec_len (segment_list) - 1);
     408             : 
     409           0 :       fib_route_path_t *paths = NULL;
     410           0 :       vec_add1 (paths, path);
     411             : 
     412           0 :       FOR_EACH_MPLS_EOS_BIT (eos)
     413             :       {
     414             :                         /* *INDENT-OFF* */
     415           0 :                         fib_prefix_t    pfx = {
     416             :                                 .fp_len = 21,
     417             :                                 .fp_proto = FIB_PROTOCOL_MPLS,
     418           0 :                                 .fp_label = sr_policy->bsid,
     419             :                                 .fp_eos = eos,
     420             :                                 .fp_payload_proto = DPO_PROTO_MPLS,
     421             :                         };
     422             :                         /* *INDENT-ON* */
     423             : 
     424           0 :         fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
     425             :       }
     426             : 
     427           0 :       segment_list->weight = weight;
     428             : 
     429           0 :       path.frp_weight = segment_list->weight;
     430             : 
     431           0 :       vec_free (paths);
     432           0 :       paths = NULL;
     433           0 :       vec_add1 (paths, path);
     434             : 
     435           0 :       FOR_EACH_MPLS_EOS_BIT (eos)
     436             :       {
     437             :                         /* *INDENT-OFF* */
     438           0 :                         fib_prefix_t    pfx = {
     439             :                                 .fp_len = 21,
     440             :                                 .fp_proto = FIB_PROTOCOL_MPLS,
     441           0 :                                 .fp_label = sr_policy->bsid,
     442             :                                 .fp_eos = eos,
     443             :                                 .fp_payload_proto = DPO_PROTO_MPLS,
     444             :                         };
     445             :                         /* *INDENT-ON* */
     446             : 
     447           0 :         fib_table_entry_path_add2 (0,
     448             :                                    &pfx,
     449             :                                    FIB_SOURCE_SR,
     450           0 :                                    (sr_policy->type ==
     451             :                                     SR_POLICY_TYPE_DEFAULT ?
     452             :                                     FIB_ENTRY_FLAG_NONE :
     453             :                                     FIB_ENTRY_FLAG_MULTICAST), paths);
     454             :       }
     455             :     }
     456           0 :   return 0;
     457             : }
     458             : 
     459             : /**
     460             :  * @brief CLI for 'sr mpls policies' command family
     461             :  */
     462             : static clib_error_t *
     463           0 : sr_mpls_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
     464             :                            vlib_cli_command_t * cmd)
     465             : {
     466           0 :   int rv = -1;
     467           0 :   char is_del = 0, is_add = 0, is_mod = 0;
     468           0 :   char policy_set = 0;
     469             :   mpls_label_t bsid, next_label;
     470           0 :   u32 sl_index = (u32) ~ 0;
     471           0 :   u32 weight = (u32) ~ 0;
     472           0 :   mpls_label_t *segments = 0;
     473           0 :   u8 operation = 0;
     474           0 :   u8 is_spray = 0;
     475             : 
     476           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     477             :     {
     478           0 :       if (!is_add && !is_mod && !is_del && unformat (input, "add"))
     479           0 :         is_add = 1;
     480           0 :       else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
     481           0 :         is_del = 1;
     482           0 :       else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
     483           0 :         is_mod = 1;
     484           0 :       else if (!policy_set
     485           0 :                && unformat (input, "bsid %U", unformat_mpls_unicast_label,
     486             :                             &bsid))
     487           0 :         policy_set = 1;
     488           0 :       else if (unformat (input, "weight %d", &weight));
     489           0 :       else if (unformat
     490             :                (input, "next %U", unformat_mpls_unicast_label, &next_label))
     491             :         {
     492           0 :           vec_add (segments, &next_label, 1);
     493             :         }
     494           0 :       else if (unformat (input, "add sl"))
     495           0 :         operation = 1;
     496           0 :       else if (unformat (input, "del sl index %d", &sl_index))
     497           0 :         operation = 2;
     498           0 :       else if (unformat (input, "mod sl index %d", &sl_index))
     499           0 :         operation = 3;
     500           0 :       else if (unformat (input, "spray"))
     501           0 :         is_spray = 1;
     502             :       else
     503           0 :         break;
     504             :     }
     505             : 
     506           0 :   if (!is_add && !is_mod && !is_del)
     507           0 :     return clib_error_return (0, "Incorrect CLI");
     508             : 
     509           0 :   if (!policy_set)
     510           0 :     return clib_error_return (0, "No SR policy BSID or index specified");
     511             : 
     512           0 :   if (is_add)
     513             :     {
     514           0 :       if (vec_len (segments) == 0)
     515           0 :         return clib_error_return (0, "No Segment List specified");
     516             : 
     517           0 :       rv = sr_mpls_policy_add (bsid, segments,
     518             :                                (is_spray ? SR_POLICY_TYPE_SPRAY :
     519             :                                 SR_POLICY_TYPE_DEFAULT), weight);
     520           0 :       vec_free (segments);
     521             :     }
     522           0 :   else if (is_del)
     523           0 :     rv = sr_mpls_policy_del (bsid);
     524           0 :   else if (is_mod)
     525             :     {
     526           0 :       if (!operation)
     527           0 :         return clib_error_return (0, "No SL modification specified");
     528           0 :       if (operation != 1 && sl_index == (u32) ~ 0)
     529           0 :         return clib_error_return (0, "No Segment List index specified");
     530           0 :       if (operation == 1 && vec_len (segments) == 0)
     531           0 :         return clib_error_return (0, "No Segment List specified");
     532           0 :       if (operation == 3 && weight == (u32) ~ 0)
     533           0 :         return clib_error_return (0, "No new weight for the SL specified");
     534           0 :       rv = sr_mpls_policy_mod (bsid, operation, segments, sl_index, weight);
     535           0 :       vec_free (segments);
     536             :     }
     537           0 :   switch (rv)
     538             :     {
     539           0 :     case 0:
     540           0 :       break;
     541           0 :     case 1:
     542           0 :       return 0;
     543           0 :     case -12:
     544           0 :       return clib_error_return (0,
     545             :                                 "There is already a FIB entry for the BindingSID address.\n"
     546             :                                 "The SR policy could not be created.");
     547           0 :     case -21:
     548           0 :       return clib_error_return (0,
     549             :                                 "The selected SR policy only contains ONE segment list. "
     550             :                                 "Please remove the SR policy instead");
     551           0 :     case -22:
     552           0 :       return clib_error_return (0,
     553             :                                 "Could not delete the segment list. "
     554             :                                 "It is not associated with that SR policy.");
     555           0 :     case -23:
     556           0 :       return clib_error_return (0,
     557             :                                 "Could not delete the segment list. "
     558             :                                 "It is not associated with that SR policy.");
     559           0 :     case -32:
     560           0 :       return clib_error_return (0,
     561             :                                 "Could not modify the segment list. "
     562             :                                 "The given SL is not associated with such SR policy.");
     563           0 :     case VNET_API_ERROR_NO_SUCH_TABLE:
     564           0 :       return clib_error_return (0, "the Default MPLS table is not present");
     565           0 :     default:
     566           0 :       return clib_error_return (0, "BUG: sr policy returns %d", rv);
     567             :     }
     568           0 :   return 0;
     569             : }
     570             : 
     571             : /* *INDENT-OFF* */
     572      285289 : VLIB_CLI_COMMAND(sr_mpls_policy_command, static)=
     573             : {
     574             :         .path = "sr mpls policy",
     575             :                 .short_help = "sr mpls policy [add||del||mod] bsid 2999 "
     576             :                 "next 10 next 20 next 30 (weight 1) (spray)",
     577             :                 .long_help = "TBD.\n",
     578             :                 .function = sr_mpls_policy_command_fn,
     579             : };
     580             : /* *INDENT-ON* */
     581             : 
     582             : /**
     583             :  * @brief CLI to display onscreen all the SR MPLS policies
     584             :  */
     585             : static clib_error_t *
     586           0 : show_sr_mpls_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
     587             :                                   vlib_cli_command_t * cmd)
     588             : {
     589           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     590           0 :   mpls_sr_sl_t *segment_list = 0;
     591           0 :   mpls_sr_policy_t *sr_policy = 0;
     592           0 :   mpls_sr_policy_t **vec_policies = 0;
     593             :   mpls_label_t *label;
     594             :   u32 *sl_index;
     595             :   u8 *s;
     596           0 :   int i = 0;
     597             : 
     598           0 :   vlib_cli_output (vm, "SR MPLS policies:");
     599             : 
     600             :         /* *INDENT-OFF* */
     601           0 :         pool_foreach (sr_policy, sm->sr_policies) {
     602           0 :                 vec_add1(vec_policies, sr_policy);
     603             :         }
     604             :         /* *INDENT-ON* */
     605             : 
     606           0 :   vec_foreach_index (i, vec_policies)
     607             :   {
     608           0 :     sr_policy = vec_policies[i];
     609           0 :     vlib_cli_output (vm, "[%u].-\tBSID: %U",
     610           0 :                      (u32) (sr_policy - sm->sr_policies),
     611             :                      format_mpls_unicast_label, sr_policy->bsid);
     612           0 :     switch (sr_policy->endpoint_type)
     613             :       {
     614           0 :       case SR_STEER_IPV6:
     615           0 :         vlib_cli_output (vm, "\tEndpoint: %U", format_ip6_address,
     616             :                          &sr_policy->endpoint.ip6);
     617           0 :         vlib_cli_output (vm, "\tColor: %u", sr_policy->color);
     618           0 :         break;
     619           0 :       case SR_STEER_IPV4:
     620           0 :         vlib_cli_output (vm, "\tEndpoint: %U", format_ip4_address,
     621             :                          &sr_policy->endpoint.ip4);
     622           0 :         vlib_cli_output (vm, "\tColor: %u", sr_policy->color);
     623           0 :         break;
     624           0 :       default:
     625           0 :         vlib_cli_output (vm, "\tTE disabled");
     626             :       }
     627           0 :     vlib_cli_output (vm, "\tType: %s",
     628           0 :                      (sr_policy->type ==
     629             :                       SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
     630           0 :     vlib_cli_output (vm, "\tSegment Lists:");
     631           0 :     vec_foreach (sl_index, sr_policy->segments_lists)
     632             :     {
     633           0 :       s = NULL;
     634           0 :       segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
     635           0 :       s = format (s, "\t[%u].- ", *sl_index);
     636           0 :       s = format (s, "< ");
     637           0 :       vec_foreach (label, segment_list->segments)
     638             :       {
     639           0 :         s = format (s, "%U, ", format_mpls_unicast_label, *label);
     640             :       }
     641           0 :       s = format (s, "\b\b > ");
     642           0 :       vlib_cli_output (vm, "  %s", s);
     643             :     }
     644           0 :     vlib_cli_output (vm, "-----------");
     645             :   }
     646           0 :   vec_free (vec_policies);
     647           0 :   return 0;
     648             : }
     649             : 
     650             : /* *INDENT-OFF* */
     651      285289 : VLIB_CLI_COMMAND(show_sr_mpls_policies_command, static)=
     652             : {
     653             :         .path = "show sr mpls policies",
     654             :                 .short_help = "show sr mpls policies",
     655             :                 .function = show_sr_mpls_policies_command_fn,
     656             : };
     657             : /* *INDENT-ON* */
     658             : 
     659             : /**
     660             :  * @brief Update the Endpoint,Color tuple of an SR policy
     661             :  *
     662             :  * @param bsid is the bindingSID of the SR Policy
     663             :  * @param endpoint represents the IP46 of the endpoint
     664             :  * @param color represents the color (u32)
     665             :  *
     666             :  * To reset to NULL use ~0 as parameters.
     667             :  *
     668             :  * @return 0 if correct, else error
     669             :  */
     670             : int
     671           0 : sr_mpls_policy_assign_endpoint_color (mpls_label_t bsid,
     672             :                                       ip46_address_t * endpoint,
     673             :                                       u8 endpoint_type, u32 color)
     674             : {
     675           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     676           0 :   mpls_sr_policy_t *sr_policy = 0;
     677             :   uword *endpoint_table, *p, *old_value;
     678             : 
     679             :   ip46_address_t any;
     680           0 :   any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
     681             : 
     682           0 :   if (!sm->sr_policies_index_hash)
     683           0 :     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
     684             : 
     685           0 :   p = hash_get (sm->sr_policies_index_hash, bsid);
     686           0 :   if (p)
     687           0 :     sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
     688             :   else
     689           0 :     return -1;
     690             : 
     691             :   /* If previous Endpoint, color existed, remove (NH,C) and (ANY,C) */
     692           0 :   if (sr_policy->endpoint_type)
     693             :     {
     694             :       endpoint_table =
     695           0 :         mhash_get (&sm->sr_policies_c2e2eclabel_hash, &sr_policy->color);
     696           0 :       if (!endpoint_table)
     697           0 :         return -2;
     698             :       old_value =
     699           0 :         mhash_get ((mhash_t *) endpoint_table, &sr_policy->endpoint);
     700             : 
     701             :       /* CID 180995 This should never be NULL unless the two hash tables
     702             :        * get out of sync */
     703           0 :       ALWAYS_ASSERT (old_value != NULL);
     704             : 
     705           0 :       fib_prefix_t pfx = { 0 };
     706           0 :       pfx.fp_proto = FIB_PROTOCOL_MPLS;
     707           0 :       pfx.fp_len = 21;
     708           0 :       pfx.fp_label = (u32) * old_value;
     709             : 
     710             :       mpls_eos_bit_t eos;
     711           0 :       FOR_EACH_MPLS_EOS_BIT (eos)
     712             :       {
     713           0 :         pfx.fp_eos = eos;
     714           0 :         fib_table_entry_path_remove (sm->fib_table_EC,
     715             :                                      &pfx,
     716             :                                      FIB_SOURCE_SR,
     717             :                                      DPO_PROTO_MPLS,
     718             :                                      NULL,
     719             :                                      ~0, 0, 1, FIB_ROUTE_PATH_FLAG_NONE);
     720             :       }
     721             : 
     722           0 :       old_value = mhash_get ((mhash_t *) endpoint_table, &any);
     723           0 :       pfx.fp_label = (u32) * old_value;
     724             : 
     725           0 :       FOR_EACH_MPLS_EOS_BIT (eos)
     726             :       {
     727           0 :         pfx.fp_eos = eos;
     728           0 :         fib_table_entry_path_remove (sm->fib_table_EC,
     729             :                                      &pfx,
     730             :                                      FIB_SOURCE_SR,
     731             :                                      DPO_PROTO_MPLS,
     732             :                                      NULL,
     733             :                                      ~0, 0, 1, FIB_ROUTE_PATH_FLAG_NONE);
     734             :       }
     735             : 
     736             :       /* Release the lock on (NH, Color) and (ANY, Color) */
     737           0 :       internal_label_unlock (sr_policy->endpoint, sr_policy->color);
     738           0 :       internal_label_unlock (any, sr_policy->color);
     739             : 
     740             :       /* Reset the values on the SR policy */
     741           0 :       sr_policy->endpoint_type = 0;
     742           0 :       sr_policy->endpoint.as_u64[0] = sr_policy->endpoint.as_u64[1] =
     743             :         (u64) ~ 0;
     744           0 :       sr_policy->color = (u32) ~ 0;
     745             :     }
     746             : 
     747           0 :   if (endpoint_type)
     748             :     {
     749           0 :       sr_policy->endpoint_type = endpoint_type;
     750           0 :       sr_policy->endpoint.as_u64[0] = endpoint->as_u64[0];
     751           0 :       sr_policy->endpoint.as_u64[1] = endpoint->as_u64[1];
     752           0 :       sr_policy->color = color;
     753             : 
     754           0 :       u32 label = find_or_create_internal_label (*endpoint, color);
     755           0 :       internal_label_lock (*endpoint, sr_policy->color);
     756             : 
     757             :       /* If FIB doesnt exist, create them */
     758           0 :       if (sm->fib_table_EC == (u32) ~ 0)
     759             :         {
     760           0 :           sm->fib_table_EC = fib_table_create_and_lock (FIB_PROTOCOL_MPLS,
     761             :                                                         FIB_SOURCE_SR,
     762             :                                                         "SR-MPLS Traffic Engineering (NextHop,Color)");
     763             : 
     764           0 :           fib_table_flush (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
     765             :                            FIB_SOURCE_SPECIAL);
     766             :         }
     767             : 
     768           0 :       fib_prefix_t pfx = { 0 };
     769           0 :       pfx.fp_proto = FIB_PROTOCOL_MPLS;
     770           0 :       pfx.fp_len = 21;
     771             : 
     772           0 :       fib_route_path_t path = {
     773             :         .frp_proto = DPO_PROTO_MPLS,
     774             :         .frp_sw_if_index = ~0,
     775             :         .frp_fib_index = 0,
     776             :         .frp_weight = 1,
     777             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
     778             :         .frp_label_stack = 0
     779             :       };
     780           0 :       path.frp_local_label = sr_policy->bsid;
     781             : 
     782             :       //Add the entry to ANY,Color
     783           0 :       u32 any_label = find_or_create_internal_label (any, color);
     784           0 :       internal_label_lock (any, sr_policy->color);
     785             : 
     786           0 :       pfx.fp_eos = MPLS_EOS;
     787           0 :       path.frp_eos = MPLS_EOS;
     788             : 
     789           0 :       fib_route_path_t *paths = NULL;
     790           0 :       vec_add1 (paths, path);
     791             : 
     792           0 :       pfx.fp_label = label;
     793           0 :       fib_table_entry_update (sm->fib_table_EC,
     794             :                               &pfx,
     795             :                               FIB_SOURCE_SR,
     796             :                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     797             : 
     798           0 :       pfx.fp_label = any_label;
     799           0 :       fib_table_entry_update (sm->fib_table_EC,
     800             :                               &pfx,
     801             :                               FIB_SOURCE_SR,
     802             :                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     803             : 
     804           0 :       fib_mpls_label_t fml = {
     805             :         .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
     806             :       };
     807             : 
     808           0 :       vec_add1 (path.frp_label_stack, fml);
     809           0 :       pfx.fp_eos = MPLS_NON_EOS;
     810           0 :       path.frp_eos = MPLS_NON_EOS;
     811             : 
     812           0 :       paths = NULL;
     813           0 :       vec_add1 (paths, path);
     814             : 
     815           0 :       pfx.fp_label = label;
     816           0 :       fib_table_entry_update (sm->fib_table_EC,
     817             :                               &pfx,
     818             :                               FIB_SOURCE_SR,
     819             :                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     820             : 
     821           0 :       pfx.fp_label = any_label;
     822           0 :       fib_table_entry_update (sm->fib_table_EC,
     823             :                               &pfx,
     824             :                               FIB_SOURCE_SR,
     825             :                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     826             :     }
     827           0 :   return 0;
     828             : }
     829             : 
     830             : /**
     831             :  * @brief CLI to modify the Endpoint,Color of an SR policy
     832             :  */
     833             : static clib_error_t *
     834           0 : cli_sr_mpls_policy_ec_command_fn (vlib_main_t * vm, unformat_input_t * input,
     835             :                                   vlib_cli_command_t * cmd)
     836             : {
     837             :   ip46_address_t endpoint;
     838           0 :   u32 color = (u32) ~ 0;
     839             :   mpls_label_t bsid;
     840           0 :   u8 endpoint_type = 0;
     841           0 :   char clear = 0, color_set = 0, bsid_set = 0;
     842             : 
     843           0 :   clib_memset (&endpoint, 0, sizeof (ip46_address_t));
     844             : 
     845             :   int rv;
     846           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     847             :     {
     848           0 :       if (!endpoint_type
     849           0 :           && unformat (input, "endpoint %U", unformat_ip6_address,
     850             :                        &endpoint.ip6))
     851           0 :         endpoint_type = SR_STEER_IPV6;
     852           0 :       else if (!endpoint_type
     853           0 :                && unformat (input, "endpoint %U", unformat_ip4_address,
     854             :                             &endpoint.ip4))
     855           0 :         endpoint_type = SR_STEER_IPV4;
     856           0 :       else if (!color_set && unformat (input, "color %u", &color))
     857           0 :         color_set = 1;
     858           0 :       else if (!bsid_set
     859           0 :                && unformat (input, "bsid %U", unformat_mpls_unicast_label,
     860             :                             &bsid))
     861           0 :         bsid_set = 1;
     862           0 :       else if (!clear && unformat (input, "clear"))
     863           0 :         clear = 1;
     864             :       else
     865             :         break;
     866             :     }
     867             : 
     868           0 :   if (!bsid_set)
     869           0 :     return clib_error_return (0, "No BSID specified");
     870           0 :   if (!endpoint_type && !clear)
     871           0 :     return clib_error_return (0, "No Endpoint specified");
     872           0 :   if (!color_set && !clear)
     873           0 :     return clib_error_return (0, "No Color set");
     874             : 
     875             :   /* In case its a cleanup */
     876           0 :   if (clear)
     877             :     {
     878           0 :       ip6_address_set_zero (&endpoint.ip6);
     879           0 :       color = (u32) ~ 0;
     880             :     }
     881             :   rv =
     882           0 :     sr_mpls_policy_assign_endpoint_color (bsid, &endpoint, endpoint_type,
     883             :                                           color);
     884             : 
     885           0 :   if (rv)
     886           0 :     clib_error_return (0, "Error on Endpoint,Color");
     887             : 
     888           0 :   return 0;
     889             : }
     890             : 
     891             : /* *INDENT-OFF* */
     892      285289 : VLIB_CLI_COMMAND(cli_sr_mpls_policy_ec_command, static)=
     893             : {
     894             :         .path = "sr mpls policy te",
     895             :                 .short_help = "sr mpls policy te bsid xxxxx endpoint x.x.x.x color 12341234",
     896             :                 .function = cli_sr_mpls_policy_ec_command_fn,
     897             : };
     898             : /* *INDENT-ON* */
     899             : 
     900             : /********************* SR MPLS Policy initialization ***********************/
     901             : /**
     902             :  * @brief SR MPLS Policy  initialization
     903             :  */
     904             : clib_error_t *
     905         575 : sr_mpls_policy_rewrite_init (vlib_main_t * vm)
     906             : {
     907         575 :   mpls_sr_main_t *sm = &sr_mpls_main;
     908             : 
     909             :   /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
     910         575 :   sm->sr_policies_index_hash = NULL;
     911         575 :   sm->sr_policies_c2e2eclabel_hash.hash = NULL;
     912         575 :   return 0;
     913             : }
     914             : 
     915       69695 : VLIB_INIT_FUNCTION (sr_mpls_policy_rewrite_init);
     916             : 
     917             : /*
     918             :  * fd.io coding-style-patch-verification: ON
     919             :  *
     920             :  * Local Variables: eval: (c-set-style "gnu") End:
     921             :  */

Generated by: LCOV version 1.14