LCOV - code coverage report
Current view: top level - vnet/srmpls - sr_mpls_steering.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 9 417 2.2 %
Date: 2023-10-26 01:39:38 Functions: 7 18 38.9 %

          Line data    Source code
       1             : /*
       2             :  * sr_steering.c: ipv6 segment routing steering into SR policy
       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 Packet steering into SR-MPLS Policies
      20             :  *
      21             :  * This file is in charge of handling the FIB appropiatly to steer packets
      22             :  * through SR Policies as defined in 'sr_mpls_policy.c'. Notice that here
      23             :  * we are only doing steering. SR policy application is done in
      24             :  * sr_policy_rewrite.c
      25             :  *
      26             :  * Supports:
      27             :  *  - Steering of IPv6 traffic Destination Address based through BSID
      28             :  *  - Steering of IPv4 traffic Destination Address based through BSID
      29             :  *  - Steering of IPv4 and IPv6 traffic through N,C (SR CP)
      30             :  */
      31             : 
      32             : #include <vlib/vlib.h>
      33             : #include <vnet/vnet.h>
      34             : #include <vnet/srmpls/sr_mpls.h>
      35             : #include <vnet/ip/ip4_packet.h>
      36             : #include <vnet/ip/ip6_packet.h>
      37             : #include <vnet/fib/mpls_fib.h>
      38             : 
      39             : #include <vppinfra/error.h>
      40             : #include <vppinfra/elog.h>
      41             : 
      42             : #define SRMPLS_TE_OFFSET 50
      43             : 
      44             : /**
      45             :  * @brief function to sort the colors in descending order
      46             :  */
      47             : int
      48           0 : sort_color_descent (const u32 * x, u32 * y)
      49             : {
      50           0 :   return *y - *x;
      51             : }
      52             : 
      53             : /********************* Internal (NH, C) labels *******************************/
      54             : /**
      55             :  * @brief find the corresponding label for (endpoint, color) and lock it
      56             :  * endpoint might be NULL or ANY
      57             :  * NULL = 0, ANY=~0
      58             :  */
      59             : u32
      60           0 : find_or_create_internal_label (ip46_address_t endpoint, u32 color)
      61             : {
      62           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
      63             :   uword *color_table, *result_label;
      64             : 
      65           0 :   if (!sm->sr_policies_c2e2eclabel_hash.hash)
      66           0 :     mhash_init (&sm->sr_policies_c2e2eclabel_hash, sizeof (mhash_t),
      67             :                 sizeof (u32));
      68             : 
      69           0 :   color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
      70           0 :   if (!color_table)
      71             :     {
      72             :       mhash_t color_t;
      73           0 :       clib_memset (&color_t, 0, sizeof (mhash_t));
      74           0 :       mhash_init (&color_t, sizeof (u32), sizeof (ip46_address_t));
      75           0 :       mhash_set_mem (&sm->sr_policies_c2e2eclabel_hash, &color,
      76             :                      (uword *) & color_t, NULL);
      77           0 :       color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
      78             :     }
      79             : 
      80           0 :   result_label = mhash_get ((mhash_t *) color_table, &endpoint);
      81             : 
      82           0 :   if (result_label)
      83           0 :     return (u32) * result_label;
      84             : 
      85             :   /* Create and set a new internal label */
      86           0 :   u32 *new_internal_label = 0;
      87           0 :   pool_get (sm->ec_labels, new_internal_label);
      88           0 :   *new_internal_label = 0;
      89           0 :   mhash_set ((mhash_t *) color_table, &endpoint,
      90           0 :              (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET, NULL);
      91             : 
      92           0 :   return (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET;
      93             : }
      94             : 
      95             : always_inline void
      96           0 : internal_label_lock_co (ip46_address_t endpoint, u32 color, char co_bits)
      97             : {
      98             :   ip46_address_t zero, any;
      99           0 :   ip46_address_reset (&zero);
     100           0 :   any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
     101           0 :   switch (co_bits)
     102             :     {
     103           0 :     case SR_TE_CO_BITS_10:
     104           0 :       internal_label_lock (endpoint, color);
     105           0 :       internal_label_lock (zero, color);
     106           0 :       internal_label_lock (any, color);
     107           0 :       break;
     108           0 :     case SR_TE_CO_BITS_01:
     109           0 :       internal_label_lock (endpoint, color);
     110           0 :       internal_label_lock (zero, color);
     111           0 :       break;
     112           0 :     case SR_TE_CO_BITS_00:
     113             :     case SR_TE_CO_BITS_11:
     114           0 :       internal_label_lock (endpoint, color);
     115           0 :       break;
     116             :     }
     117           0 : }
     118             : 
     119             : /**
     120             :  * @brief lock the label for (NH, C)
     121             :  * endpoint might be NULL or ANY
     122             :  * NULL = 0, ANY=~0
     123             :  */
     124             : void
     125           0 : internal_label_lock (ip46_address_t endpoint, u32 color)
     126             : {
     127           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     128             :   uword *color_table, *result_label;
     129             : 
     130           0 :   if (!sm->sr_policies_c2e2eclabel_hash.hash)
     131           0 :     return;
     132             : 
     133           0 :   color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
     134           0 :   if (!color_table)
     135           0 :     return;
     136             : 
     137           0 :   result_label = mhash_get ((mhash_t *) color_table, &endpoint);
     138             : 
     139           0 :   if (!result_label)
     140           0 :     return;
     141             : 
     142             :   /* Lock it */
     143           0 :   u32 *label_lock =
     144           0 :     pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
     145           0 :   (*label_lock)++;
     146             : }
     147             : 
     148             : 
     149             : always_inline void
     150           0 : internal_label_unlock_co (ip46_address_t endpoint, u32 color, char co_bits)
     151             : {
     152             :   ip46_address_t zero, any;
     153           0 :   ip46_address_reset (&zero);
     154           0 :   any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
     155           0 :   switch (co_bits)
     156             :     {
     157           0 :     case SR_TE_CO_BITS_10:
     158           0 :       internal_label_unlock (endpoint, color);
     159           0 :       internal_label_unlock (zero, color);
     160           0 :       internal_label_unlock (any, color);
     161           0 :       break;
     162           0 :     case SR_TE_CO_BITS_01:
     163           0 :       internal_label_unlock (endpoint, color);
     164           0 :       internal_label_unlock (zero, color);
     165           0 :       break;
     166           0 :     case SR_TE_CO_BITS_00:
     167             :     case SR_TE_CO_BITS_11:
     168           0 :       internal_label_unlock (endpoint, color);
     169           0 :       break;
     170             :     }
     171           0 : }
     172             : 
     173             : /**
     174             :  * @brief Release lock on label for (endpoint, color)
     175             :  * endpoint might be NULL or ANY
     176             :  * NULL = 0, ANY=~0
     177             :  */
     178             : void
     179           0 : internal_label_unlock (ip46_address_t endpoint, u32 color)
     180             : {
     181           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     182             :   uword *color_table, *result_label;
     183             : 
     184           0 :   if (!sm->sr_policies_c2e2eclabel_hash.hash)
     185           0 :     return;
     186             : 
     187           0 :   color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
     188           0 :   if (!color_table)
     189           0 :     return;
     190             : 
     191           0 :   result_label = mhash_get ((mhash_t *) color_table, &endpoint);
     192             : 
     193           0 :   if (!result_label)
     194           0 :     return;
     195             : 
     196           0 :   u32 *label_lock =
     197           0 :     pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
     198           0 :   (*label_lock)--;
     199             : 
     200           0 :   if (*label_lock == 0)
     201             :     {
     202           0 :       pool_put (sm->ec_labels, label_lock);
     203           0 :       mhash_unset ((mhash_t *) color_table, &endpoint, NULL);
     204           0 :       if (mhash_elts ((mhash_t *) color_table) == 0)
     205             :         {
     206           0 :           mhash_free ((mhash_t *) color_table);
     207           0 :           mhash_unset (&sm->sr_policies_c2e2eclabel_hash, &color, NULL);
     208           0 :           if (mhash_elts (&sm->sr_policies_c2e2eclabel_hash) == 0)
     209             :             {
     210           0 :               mhash_free (&sm->sr_policies_c2e2eclabel_hash);
     211           0 :               sm->sr_policies_c2e2eclabel_hash.hash = NULL;
     212           0 :               fib_table_unlock (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
     213             :                                 FIB_SOURCE_SR);
     214           0 :               sm->fib_table_EC = (u32) ~ 0;
     215             :             }
     216             :         }
     217             :     }
     218             : }
     219             : 
     220             : /********************* steering computation  *********************************/
     221             : /**
     222             :  * @brief function to update the FIB
     223             :  */
     224             : void
     225           0 : compute_sr_te_automated_steering_fib_entry (mpls_sr_steering_policy_t *
     226             :                                             steer_pl)
     227             : {
     228           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     229           0 :   fib_prefix_t pfx = { 0 };
     230             : 
     231           0 :   u32 *internal_labels = 0;
     232             :   ip46_address_t zero, any;
     233           0 :   ip46_address_reset (&zero);
     234           0 :   any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
     235             : 
     236           0 :   u32 *color_i = NULL;
     237           0 :   vec_foreach (color_i, steer_pl->color)
     238             :   {
     239           0 :     switch (steer_pl->co_bits)
     240             :       {
     241           0 :       case SR_TE_CO_BITS_10:
     242           0 :         vec_add1 (internal_labels,
     243             :                   find_or_create_internal_label (steer_pl->next_hop,
     244             :                                                  *color_i));
     245           0 :         vec_add1 (internal_labels,
     246             :                   find_or_create_internal_label (zero, *color_i));
     247           0 :         vec_add1 (internal_labels,
     248             :                   find_or_create_internal_label (any, *color_i));
     249           0 :         break;
     250           0 :       case SR_TE_CO_BITS_01:
     251           0 :         vec_add1 (internal_labels,
     252             :                   find_or_create_internal_label (steer_pl->next_hop,
     253             :                                                  *color_i));
     254           0 :         vec_add1 (internal_labels,
     255             :                   find_or_create_internal_label (zero, *color_i));
     256           0 :         break;
     257           0 :       case SR_TE_CO_BITS_00:
     258             :       case SR_TE_CO_BITS_11:
     259           0 :         vec_add1 (internal_labels,
     260             :                   find_or_create_internal_label (steer_pl->next_hop,
     261             :                                                  *color_i));
     262           0 :         break;
     263             :       }
     264           0 :   }
     265             : 
     266             :   /* Does hidden FIB already exist? */
     267           0 :   if (sm->fib_table_EC == (u32) ~ 0)
     268             :     {
     269           0 :       sm->fib_table_EC = fib_table_create_and_lock (FIB_PROTOCOL_MPLS,
     270             :                                                     FIB_SOURCE_SR,
     271             :                                                     "SR-MPLS Traffic Engineering (NextHop,Color)");
     272             : 
     273           0 :       fib_table_flush (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
     274             :                        FIB_SOURCE_SPECIAL);
     275             :     }
     276             : 
     277             :   /* Add the corresponding FIB entries */
     278           0 :   fib_route_path_t path = {
     279             :     .frp_proto = DPO_PROTO_MPLS,
     280             :     .frp_eos = MPLS_EOS,
     281             :     .frp_sw_if_index = ~0,
     282           0 :     .frp_fib_index = sm->fib_table_EC,
     283             :     .frp_weight = 1,
     284             :     .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
     285             :     .frp_label_stack = 0
     286             :   };
     287           0 :   fib_route_path_t *paths = NULL;
     288             : 
     289           0 :   if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
     290             :     {
     291           0 :       pfx.fp_proto = FIB_PROTOCOL_IP6;
     292           0 :       pfx.fp_len = steer_pl->classify.mask_width;
     293           0 :       pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
     294             :     }
     295           0 :   else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
     296             :     {
     297           0 :       pfx.fp_proto = FIB_PROTOCOL_IP4;
     298           0 :       pfx.fp_len = steer_pl->classify.mask_width;
     299           0 :       pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
     300             :     }
     301             : 
     302           0 :   if (steer_pl->vpn_label != (u32) ~ 0)
     303             :     {
     304           0 :       fib_mpls_label_t fml = {
     305           0 :         .fml_value = steer_pl->vpn_label,
     306             :       };
     307           0 :       vec_add1 (path.frp_label_stack, fml);
     308           0 :       path.frp_eos = MPLS_NON_EOS;
     309             :     }
     310             : 
     311             :   u32 label_i;
     312           0 :   vec_foreach_index (label_i, internal_labels)
     313             :   {
     314           0 :     path.frp_local_label = internal_labels[label_i];
     315           0 :     path.frp_preference = label_i;
     316           0 :     vec_add1 (paths, path);
     317             :   }
     318             : 
     319             :   /* Finally we must add to FIB IGP to N */
     320           0 :   clib_memcpy (&path.frp_addr, &steer_pl->next_hop,
     321             :                sizeof (steer_pl->next_hop));
     322           0 :   path.frp_preference = vec_len (internal_labels);
     323           0 :   path.frp_label_stack = NULL;
     324             : 
     325           0 :   if (steer_pl->nh_type == SR_STEER_IPV6)
     326             :     {
     327           0 :       path.frp_proto = DPO_PROTO_IP6;
     328           0 :       path.frp_fib_index =
     329           0 :         fib_table_find (FIB_PROTOCOL_IP6,
     330           0 :                         (steer_pl->classify.fib_table !=
     331             :                          (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
     332             :     }
     333           0 :   else if (steer_pl->nh_type == SR_STEER_IPV4)
     334             :     {
     335           0 :       path.frp_proto = DPO_PROTO_IP4;
     336           0 :       path.frp_fib_index =
     337           0 :         fib_table_find (FIB_PROTOCOL_IP4,
     338           0 :                         (steer_pl->classify.fib_table !=
     339             :                          (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
     340             :     }
     341             : 
     342           0 :   vec_add1 (paths, path);
     343           0 :   if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
     344           0 :     fib_table_entry_update (fib_table_find
     345             :                             (FIB_PROTOCOL_IP6,
     346           0 :                              (steer_pl->classify.fib_table !=
     347             :                               (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
     348             :                             &pfx, FIB_SOURCE_SR,
     349             :                             FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     350           0 :   else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
     351           0 :     fib_table_entry_update (fib_table_find
     352             :                             (FIB_PROTOCOL_IP4,
     353           0 :                              (steer_pl->classify.fib_table !=
     354             :                               (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
     355             :                             &pfx, FIB_SOURCE_SR,
     356             :                             FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     357             : 
     358           0 :   vec_free (paths);
     359           0 :   paths = NULL;
     360           0 : }
     361             : 
     362             : /**
     363             :  * @brief Steer traffic L3 traffic through a given SR-MPLS policy
     364             :  *
     365             :  * @param is_del
     366             :  * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
     367             :  * @param sr_policy is the index of the SR Policy (alt to bsid)
     368             :  * @param table_id is the VRF where to install the FIB entry for the BSID
     369             :  * @param prefix is the IPv4/v6 address for L3 traffic type
     370             :  * @param mask_width is the mask for L3 traffic type
     371             :  * @param traffic_type describes the type of traffic
     372             :  * @param next_hop SR TE Next-Hop
     373             :  * @param nh_type is the AF of Next-Hop
     374             :  * @param color SR TE color
     375             :  * @param co_bits SR TE color-only bits
     376             :  *
     377             :  * @return 0 if correct, else error
     378             :  */
     379             : int
     380           0 : sr_mpls_steering_policy_add (mpls_label_t bsid, u32 table_id,
     381             :                              ip46_address_t * prefix, u32 mask_width,
     382             :                              u8 traffic_type, ip46_address_t * next_hop,
     383             :                              u8 nh_type, u32 color, char co_bits,
     384             :                              mpls_label_t vpn_label)
     385             : {
     386           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     387             :   sr_mpls_steering_key_t key;
     388             :   mpls_sr_steering_policy_t *steer_pl;
     389           0 :   fib_prefix_t pfx = { 0 };
     390             : 
     391           0 :   mpls_sr_policy_t *sr_policy = 0;
     392           0 :   uword *p = 0;
     393             : 
     394           0 :   clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
     395             : 
     396           0 :   if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
     397           0 :     return -1;
     398             : 
     399             :   /* Compute the steer policy key */
     400           0 :   key.prefix.as_u64[0] = prefix->as_u64[0];
     401           0 :   key.prefix.as_u64[1] = prefix->as_u64[1];
     402           0 :   key.mask_width = mask_width;
     403           0 :   key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
     404           0 :   key.traffic_type = traffic_type;
     405             : 
     406             :   /*
     407             :    * Search for steering policy. If already exists we are adding a new
     408             :    * color.
     409             :    */
     410           0 :   if (!sm->sr_steer_policies_hash.hash)
     411           0 :     mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
     412             :                 sizeof (sr_mpls_steering_key_t));
     413             : 
     414           0 :   p = mhash_get (&sm->sr_steer_policies_hash, &key);
     415           0 :   if (p)
     416             :     {
     417           0 :       steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
     418           0 :       if (steer_pl->bsid != (u32) ~ 0)
     419           0 :         return -1;              //Means we are rewritting the steering. Not allowed.
     420             : 
     421             :       /* Means we are adding a color. Check that NH match. */
     422           0 :       if (ip46_address_cmp (&steer_pl->next_hop, next_hop))
     423           0 :         return -2;
     424           0 :       if (vec_search (steer_pl->color, color) != ~0)
     425           0 :         return -3;
     426           0 :       if (steer_pl->co_bits != co_bits)
     427           0 :         return -4;              /* CO colors should be the same */
     428           0 :       if (steer_pl->vpn_label != vpn_label)
     429           0 :         return -5;              /* VPN label should be the same */
     430             : 
     431             :       /* Remove the steering and ReDo it */
     432           0 :       vec_add1 (steer_pl->color, color);
     433           0 :       vec_sort_with_function (steer_pl->color, sort_color_descent);
     434           0 :       compute_sr_te_automated_steering_fib_entry (steer_pl);
     435           0 :       internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
     436           0 :       return 0;
     437             :     }
     438             : 
     439             :   /* Create a new steering policy */
     440           0 :   pool_get (sm->steer_policies, steer_pl);
     441           0 :   clib_memset (steer_pl, 0, sizeof (*steer_pl));
     442           0 :   clib_memcpy (&steer_pl->classify.prefix, prefix, sizeof (ip46_address_t));
     443           0 :   clib_memcpy (&steer_pl->next_hop, next_hop, sizeof (ip46_address_t));
     444           0 :   steer_pl->nh_type = nh_type;
     445           0 :   steer_pl->co_bits = co_bits;
     446           0 :   steer_pl->classify.mask_width = mask_width;
     447           0 :   steer_pl->classify.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
     448           0 :   steer_pl->classify.traffic_type = traffic_type;
     449           0 :   steer_pl->color = NULL;
     450           0 :   steer_pl->vpn_label = vpn_label;
     451             : 
     452             :   /* Create and store key */
     453           0 :   mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
     454             :              NULL);
     455             : 
     456             :   /* Local steering */
     457           0 :   if (bsid != (u32) ~ 0)
     458             :     {
     459           0 :       if (!sm->sr_policies_index_hash)
     460           0 :         sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
     461           0 :       steer_pl->bsid = bsid;
     462           0 :       p = hash_get (sm->sr_policies_index_hash, bsid);
     463           0 :       if (!p)
     464           0 :         return -1;
     465           0 :       sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
     466             : 
     467           0 :       fib_route_path_t path = {
     468             :         .frp_proto = DPO_PROTO_MPLS,
     469           0 :         .frp_local_label = sr_policy->bsid,
     470             :         .frp_eos = MPLS_EOS,
     471             :         .frp_sw_if_index = ~0,
     472             :         .frp_fib_index = 0,
     473             :         .frp_weight = 1,
     474             :         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
     475             :         .frp_label_stack = 0
     476             :       };
     477           0 :       fib_route_path_t *paths = NULL;
     478             : 
     479           0 :       if (steer_pl->vpn_label != (u32) ~ 0)
     480             :         {
     481           0 :           fib_mpls_label_t fml = {
     482           0 :             .fml_value = steer_pl->vpn_label,
     483             :           };
     484           0 :           vec_add1 (path.frp_label_stack, fml);
     485             :         }
     486             : 
     487             :       /* FIB API calls - Recursive route through the BindingSID */
     488           0 :       if (traffic_type == SR_STEER_IPV6)
     489             :         {
     490           0 :           pfx.fp_proto = FIB_PROTOCOL_IP6;
     491           0 :           pfx.fp_len = steer_pl->classify.mask_width;
     492           0 :           pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
     493           0 :           path.frp_fib_index = 0;
     494           0 :           path.frp_preference = 0;
     495           0 :           vec_add1 (paths, path);
     496           0 :           fib_table_entry_path_add2 (fib_table_find
     497             :                                      (FIB_PROTOCOL_IP6,
     498             :                                       (table_id != (u32) ~ 0 ? table_id : 0)),
     499             :                                      &pfx, FIB_SOURCE_SR,
     500             :                                      FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     501           0 :           vec_free (paths);
     502             :         }
     503           0 :       else if (traffic_type == SR_STEER_IPV4)
     504             :         {
     505           0 :           pfx.fp_proto = FIB_PROTOCOL_IP4;
     506           0 :           pfx.fp_len = steer_pl->classify.mask_width;
     507           0 :           pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
     508           0 :           path.frp_fib_index = 0;
     509           0 :           path.frp_preference = 0;
     510           0 :           vec_add1 (paths, path);
     511           0 :           fib_table_entry_path_add2 (fib_table_find
     512             :                                      (FIB_PROTOCOL_IP4,
     513             :                                       (table_id != (u32) ~ 0 ? table_id : 0)),
     514             :                                      &pfx, FIB_SOURCE_SR,
     515             :                                      FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
     516           0 :           vec_free (paths);
     517             :         }
     518             :     }
     519             :   /* Automated steering */
     520             :   else
     521             :     {
     522           0 :       steer_pl->bsid = (u32) ~ 0;
     523           0 :       vec_add1 (steer_pl->color, color);
     524           0 :       compute_sr_te_automated_steering_fib_entry (steer_pl);
     525           0 :       internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
     526             :     }
     527           0 :   return 0;
     528             : }
     529             : 
     530             : /**
     531             :  * @brief Delete steering rule for an SR-MPLS policy
     532             :  *
     533             :  * @param is_del
     534             :  * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
     535             :  * @param sr_policy is the index of the SR Policy (alt to bsid)
     536             :  * @param table_id is the VRF where to install the FIB entry for the BSID
     537             :  * @param prefix is the IPv4/v6 address for L3 traffic type
     538             :  * @param mask_width is the mask for L3 traffic type
     539             :  * @param traffic_type describes the type of traffic
     540             :  * @param next_hop SR TE Next-HOP
     541             :  * @param nh_type is the AF of Next-Hop
     542             :  * @param color SR TE color
     543             :  *
     544             :  * @return 0 if correct, else error
     545             :  */
     546             : int
     547           0 : sr_mpls_steering_policy_del (ip46_address_t * prefix, u32 mask_width,
     548             :                              u8 traffic_type, u32 table_id, u32 color)
     549             : {
     550           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     551             :   sr_mpls_steering_key_t key;
     552             :   mpls_sr_steering_policy_t *steer_pl;
     553           0 :   fib_prefix_t pfx = { 0 };
     554           0 :   uword *p = 0;
     555             : 
     556           0 :   clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
     557             : 
     558             :   /* Compute the steer policy key */
     559           0 :   if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
     560           0 :     return -1;
     561             : 
     562           0 :   key.prefix.as_u64[0] = prefix->as_u64[0];
     563           0 :   key.prefix.as_u64[1] = prefix->as_u64[1];
     564           0 :   key.mask_width = mask_width;
     565           0 :   key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
     566           0 :   key.traffic_type = traffic_type;
     567             : 
     568           0 :   if (!sm->sr_steer_policies_hash.hash)
     569           0 :     mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
     570             :                 sizeof (sr_mpls_steering_key_t));
     571             : 
     572             :   /* Search for the item */
     573           0 :   p = mhash_get (&sm->sr_steer_policies_hash, &key);
     574             : 
     575           0 :   if (!p)
     576           0 :     return -1;
     577             : 
     578             :   /* Retrieve Steer Policy function */
     579           0 :   steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
     580             : 
     581           0 :   if (steer_pl->bsid == (u32) ~ 0)
     582             :     {
     583             :       /* Remove the color from the color vector */
     584           0 :       vec_del1 (steer_pl->color, vec_search (steer_pl->color, color));
     585             : 
     586           0 :       if (vec_len (steer_pl->color))
     587             :         {
     588             :           /* Reorder Colors */
     589           0 :           vec_sort_with_function (steer_pl->color, sort_color_descent);
     590           0 :           compute_sr_te_automated_steering_fib_entry (steer_pl);
     591             :           /* Remove all the locks for this ones... */
     592           0 :           internal_label_unlock_co (steer_pl->next_hop, color,
     593           0 :                                     steer_pl->co_bits);
     594           0 :           return 0;
     595             :         }
     596             :       else
     597             :         {
     598           0 :           vec_free (steer_pl->color);
     599             :           /* Remove FIB entry */
     600           0 :           if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
     601             :             {
     602           0 :               pfx.fp_proto = FIB_PROTOCOL_IP6;
     603           0 :               pfx.fp_len = steer_pl->classify.mask_width;
     604           0 :               pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
     605           0 :               fib_table_entry_delete (fib_table_find
     606             :                                       (FIB_PROTOCOL_IP6,
     607             :                                        steer_pl->classify.fib_table), &pfx,
     608             :                                       FIB_SOURCE_SR);
     609             :             }
     610           0 :           else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
     611             :             {
     612           0 :               pfx.fp_proto = FIB_PROTOCOL_IP4;
     613           0 :               pfx.fp_len = steer_pl->classify.mask_width;
     614           0 :               pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
     615           0 :               fib_table_entry_delete (fib_table_find
     616             :                                       (FIB_PROTOCOL_IP4,
     617             :                                        steer_pl->classify.fib_table), &pfx,
     618             :                                       FIB_SOURCE_SR);
     619             :             }
     620             :           /* Remove all the locks for this ones... */
     621           0 :           internal_label_unlock_co (steer_pl->next_hop, color,
     622           0 :                                     steer_pl->co_bits);
     623             :         }
     624             :     }
     625             :   else                          //Remove by BSID
     626             :     {
     627           0 :       if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
     628             :         {
     629           0 :           pfx.fp_proto = FIB_PROTOCOL_IP6;
     630           0 :           pfx.fp_len = steer_pl->classify.mask_width;
     631           0 :           pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
     632           0 :           fib_table_entry_delete (fib_table_find
     633             :                                   (FIB_PROTOCOL_IP6,
     634             :                                    steer_pl->classify.fib_table), &pfx,
     635             :                                   FIB_SOURCE_SR);
     636             :         }
     637           0 :       else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
     638             :         {
     639           0 :           pfx.fp_proto = FIB_PROTOCOL_IP4;
     640           0 :           pfx.fp_len = steer_pl->classify.mask_width;
     641           0 :           pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
     642           0 :           fib_table_entry_delete (fib_table_find
     643             :                                   (FIB_PROTOCOL_IP4,
     644             :                                    steer_pl->classify.fib_table), &pfx,
     645             :                                   FIB_SOURCE_SR);
     646             :         }
     647             :     }
     648             :   /* Delete SR steering policy entry */
     649           0 :   pool_put (sm->steer_policies, steer_pl);
     650           0 :   mhash_unset (&sm->sr_steer_policies_hash, &key, NULL);
     651           0 :   if (mhash_elts (&sm->sr_steer_policies_hash) == 0)
     652             :     {
     653           0 :       mhash_free (&sm->sr_steer_policies_hash);
     654           0 :       sm->sr_steer_policies_hash.hash = NULL;
     655             :     }
     656           0 :   return 0;
     657             : }
     658             : 
     659             : static clib_error_t *
     660           0 : sr_mpls_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
     661             :                                  vlib_cli_command_t * cmd)
     662             : {
     663           0 :   int is_del = 0;
     664             : 
     665             :   ip46_address_t prefix, nh;
     666           0 :   u32 dst_mask_width = 0;
     667           0 :   u8 traffic_type = 0;
     668           0 :   u8 nh_type = 0;
     669           0 :   u32 fib_table = (u32) ~ 0, color = (u32) ~ 0;
     670           0 :   u32 co_bits = 0;
     671             : 
     672           0 :   mpls_label_t bsid, vpn_label = (u32) ~ 0;
     673             : 
     674           0 :   u8 sr_policy_set = 0;
     675             : 
     676           0 :   clib_memset (&prefix, 0, sizeof (ip46_address_t));
     677           0 :   clib_memset (&nh, 0, sizeof (ip46_address_t));
     678             : 
     679             :   int rv;
     680           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     681             :     {
     682           0 :       if (unformat (input, "del"))
     683           0 :         is_del = 1;
     684           0 :       else if (!traffic_type
     685           0 :                && unformat (input, "l3 %U/%d", unformat_ip6_address,
     686             :                             &prefix.ip6, &dst_mask_width))
     687           0 :         traffic_type = SR_STEER_IPV6;
     688           0 :       else if (!traffic_type
     689           0 :                && unformat (input, "l3 %U/%d", unformat_ip4_address,
     690             :                             &prefix.ip4, &dst_mask_width))
     691           0 :         traffic_type = SR_STEER_IPV4;
     692           0 :       else if (!sr_policy_set
     693           0 :                && unformat (input, "via sr policy bsid %U",
     694             :                             unformat_mpls_unicast_label, &bsid))
     695           0 :         sr_policy_set = 1;
     696           0 :       else if (!sr_policy_set
     697           0 :                && unformat (input, "via next-hop %U color %d co %d",
     698             :                             unformat_ip4_address, &nh.ip4, &color, &co_bits))
     699             :         {
     700           0 :           sr_policy_set = 1;
     701           0 :           nh_type = SR_STEER_IPV4;
     702             :         }
     703           0 :       else if (!sr_policy_set
     704           0 :                && unformat (input, "via next-hop %U color %d co %d",
     705             :                             unformat_ip6_address, &nh.ip6, &color, &co_bits))
     706             :         {
     707           0 :           sr_policy_set = 1;
     708           0 :           nh_type = SR_STEER_IPV6;
     709             :         }
     710           0 :       else if (fib_table == (u32) ~ 0
     711           0 :                && unformat (input, "fib-table %d", &fib_table));
     712           0 :       else if (unformat (input, "vpn-label %U",
     713             :                          unformat_mpls_unicast_label, &vpn_label));
     714             :       else
     715           0 :         break;
     716             :     }
     717             : 
     718           0 :   if (!traffic_type)
     719           0 :     return clib_error_return (0, "No L3 traffic specified");
     720           0 :   if (!sr_policy_set)
     721           0 :     return clib_error_return (0, "No SR policy specified");
     722             : 
     723             :   /* Make sure that the prefixes are clean */
     724           0 :   if (traffic_type == SR_STEER_IPV4)
     725             :     {
     726           0 :       u32 mask =
     727           0 :         (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
     728           0 :       prefix.ip4.as_u32 &= mask;
     729             :     }
     730           0 :   else if (traffic_type == SR_STEER_IPV6)
     731             :     {
     732             :       ip6_address_t mask;
     733           0 :       ip6_address_mask_from_width (&mask, dst_mask_width);
     734           0 :       ip6_address_mask (&prefix.ip6, &mask);
     735             :     }
     736             : 
     737           0 :   if (nh_type)
     738           0 :     bsid = (u32) ~ 0;
     739             : 
     740           0 :   if (is_del)
     741             :     rv =
     742           0 :       sr_mpls_steering_policy_del (&prefix, dst_mask_width,
     743             :                                    traffic_type, fib_table, color);
     744             : 
     745             :   else
     746             :     rv =
     747           0 :       sr_mpls_steering_policy_add (bsid, fib_table, &prefix, dst_mask_width,
     748             :                                    traffic_type, &nh, nh_type, color, co_bits,
     749             :                                    vpn_label);
     750             : 
     751           0 :   switch (rv)
     752             :     {
     753           0 :     case 0:
     754           0 :       break;
     755           0 :     case 1:
     756           0 :       return 0;
     757           0 :     case -1:
     758           0 :       return clib_error_return (0, "Incorrect API usage.");
     759           0 :     case -2:
     760           0 :       return clib_error_return (0, "The Next-Hop does not match.");
     761           0 :     case -3:
     762           0 :       return clib_error_return (0, "The color already exists.");
     763           0 :     case -4:
     764           0 :       return clib_error_return (0, "The co-bits do not match.");
     765           0 :     case -5:
     766           0 :       return clib_error_return (0, "The VPN-labels do not match.");
     767           0 :     default:
     768           0 :       return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
     769             :     }
     770           0 :   return 0;
     771             : }
     772             : 
     773             : /* *INDENT-OFF* */
     774      285289 : VLIB_CLI_COMMAND(sr_mpls_steer_policy_command, static)=
     775             : {
     776             :   .path = "sr mpls steer",
     777             :     .short_help = "sr mpls steer (del) l3 <ip_addr/mask> "
     778             :     "via [sr policy bsid <mpls_label> || next-hop <ip46_addr> color <u32> co <0|1|2|3> ](fib-table <fib_table_index>)(vpn-label 500)",
     779             :     .long_help =
     780             :     "\tSteer L3 traffic through an existing SR policy.\n"
     781             :     "\tExamples:\n"
     782             :     "\t\tsr steer l3 2001::/64 via sr_policy bsid 29999\n"
     783             :     "\t\tsr steer del l3 2001::/64 via sr_policy bsid 29999\n"
     784             :     "\t\tsr steer l3 2001::/64 via next-hop 1.1.1.1 color 1234 co 0\n"
     785             :     "\t\tsr steer l3 2001::/64 via next-hop 2001::1 color 1234 co 2 vpn-label 500\n",
     786             :     .function = sr_mpls_steer_policy_command_fn,
     787             : };
     788             : /* *INDENT-ON* */
     789             : 
     790             : static clib_error_t *
     791           0 : show_sr_mpls_steering_policies_command_fn (vlib_main_t * vm,
     792             :                                            unformat_input_t * input,
     793             :                                            vlib_cli_command_t * cmd)
     794             : {
     795           0 :   mpls_sr_main_t *sm = &sr_mpls_main;
     796           0 :   mpls_sr_steering_policy_t **steer_policies = 0;
     797             :   mpls_sr_steering_policy_t *steer_pl;
     798             : 
     799             :   int i;
     800             : 
     801           0 :   vlib_cli_output (vm, "SR MPLS steering policies:");
     802             :   /* *INDENT-OFF* */
     803           0 :   pool_foreach (steer_pl, sm->steer_policies)  {
     804           0 :     vec_add1(steer_policies, steer_pl);
     805             :   }
     806             :   /* *INDENT-ON* */
     807           0 :   for (i = 0; i < vec_len (steer_policies); i++)
     808             :     {
     809           0 :       vlib_cli_output (vm, "==========================");
     810           0 :       steer_pl = steer_policies[i];
     811           0 :       if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
     812             :         {
     813           0 :           vlib_cli_output (vm, "Prefix: %U/%d via:",
     814             :                            format_ip4_address,
     815             :                            &steer_pl->classify.prefix.ip4,
     816             :                            steer_pl->classify.mask_width);
     817             :         }
     818           0 :       else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
     819             :         {
     820           0 :           vlib_cli_output (vm, "Prefix: %U/%d via:",
     821             :                            format_ip6_address,
     822             :                            &steer_pl->classify.prefix.ip6,
     823             :                            steer_pl->classify.mask_width);
     824             :         }
     825             : 
     826           0 :       if (steer_pl->bsid != (u32) ~ 0)
     827             :         {
     828           0 :           vlib_cli_output (vm, "· BSID %U",
     829             :                            format_mpls_unicast_label, steer_pl->bsid);
     830             :         }
     831             :       else
     832             :         {
     833           0 :           if (steer_pl->nh_type == SR_STEER_IPV4)
     834             :             {
     835           0 :               vlib_cli_output (vm, "· Next-hop %U",
     836             :                                format_ip4_address, &steer_pl->next_hop.ip4);
     837             :             }
     838           0 :           else if (steer_pl->nh_type == SR_STEER_IPV6)
     839             :             {
     840           0 :               vlib_cli_output (vm, "· Next-hop %U",
     841             :                                format_ip6_address, &steer_pl->next_hop.ip6);
     842             :             }
     843             : 
     844           0 :           u32 *color_i = 0;
     845           0 :           u8 *s = NULL;
     846           0 :           s = format (s, "[ ");
     847           0 :           vec_foreach (color_i, steer_pl->color)
     848             :           {
     849           0 :             s = format (s, "%d, ", *color_i);
     850             :           }
     851           0 :           s = format (s, "\b\b ]");
     852           0 :           vlib_cli_output (vm, "· Color %s", s);
     853             : 
     854           0 :           switch (steer_pl->co_bits)
     855             :             {
     856           0 :             case SR_TE_CO_BITS_00:
     857           0 :               vlib_cli_output (vm, "· CO-bits: 00");
     858           0 :               break;
     859           0 :             case SR_TE_CO_BITS_01:
     860           0 :               vlib_cli_output (vm, "· CO-bits: 01");
     861           0 :               break;
     862           0 :             case SR_TE_CO_BITS_10:
     863           0 :               vlib_cli_output (vm, "· CO-bits: 10");
     864           0 :               break;
     865           0 :             case SR_TE_CO_BITS_11:
     866           0 :               vlib_cli_output (vm, "· CO-bits: 11");
     867           0 :               break;
     868             :             }
     869           0 :         }
     870             :     }
     871           0 :   return 0;
     872             : }
     873             : 
     874             : /* *INDENT-OFF* */
     875      285289 : VLIB_CLI_COMMAND(show_sr_mpls_steering_policies_command, static)=
     876             : {
     877             :   .path = "show sr mpls steering policies",
     878             :     .short_help = "show sr mpls steering policies",
     879             :     .function = show_sr_mpls_steering_policies_command_fn,
     880             : };
     881             : /* *INDENT-ON* */
     882             : 
     883             : clib_error_t *
     884         575 : sr_mpls_steering_init (vlib_main_t * vm)
     885             : {
     886         575 :   mpls_sr_main_t *sm = &sr_mpls_main;
     887             : 
     888             :   /* Init memory for function keys */
     889         575 :   sm->sr_steer_policies_hash.hash = NULL;
     890             : 
     891         575 :   sm->fib_table_EC = (u32) ~ 0;
     892         575 :   sm->ec_labels = 0;
     893             : 
     894         575 :   return 0;
     895             : }
     896             : 
     897             : /* *INDENT-OFF* */
     898       70271 : VLIB_INIT_FUNCTION(sr_mpls_steering_init);
     899             : /* *INDENT-ON* */
     900             : 
     901             : /*
     902             :  * fd.io coding-style-patch-verification: ON
     903             :  *
     904             :  * Local Variables: eval: (c-set-style "gnu") End:
     905             :  */

Generated by: LCOV version 1.14