LCOV - code coverage report
Current view: top level - vnet/srv6 - sr_localsid.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 789 1142 69.1 %
Date: 2023-07-05 22:20:52 Functions: 33 36 91.7 %

          Line data    Source code
       1             : /*
       2             :  * sr_localsid.c: ipv6 segment routing Endpoint behaviors
       3             :  *
       4             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : /**
      19             :  * @file
      20             :  * @brief Processing of packets with a SRH
      21             :  *
      22             :  * CLI to define new Segment Routing End processing functions.
      23             :  * Graph node to support such functions.
      24             :  *
      25             :  * Each function associates an SRv6 segment (IPv6 address) with an specific
      26             :  * Segment Routing function.
      27             :  *
      28             :  */
      29             : 
      30             : #include <vlib/vlib.h>
      31             : #include <vnet/vnet.h>
      32             : #include <vnet/srv6/sr.h>
      33             : #include <vnet/ip/ip.h>
      34             : #include <vnet/srv6/sr_packet.h>
      35             : #include <vnet/ip/ip6_packet.h>
      36             : #include <vnet/fib/ip6_fib.h>
      37             : #include <vnet/dpo/dpo.h>
      38             : #include <vnet/adj/adj.h>
      39             : 
      40             : #include <vppinfra/error.h>
      41             : #include <vppinfra/elog.h>
      42             : 
      43             : /**
      44             :  * @brief Dynamically added SR localsid DPO type
      45             :  */
      46             : static dpo_type_t sr_localsid_dpo_type;
      47             : static dpo_type_t sr_localsid_d_dpo_type;
      48             : static dpo_type_t sr_localsid_un_dpo_type;
      49             : static dpo_type_t sr_localsid_un_perf_dpo_type;
      50             : 
      51             : static void
      52          49 : sr_localsid_key_create (sr_localsid_key_t * key, ip6_address_t * addr,
      53             :                         u16 pref_len)
      54             : {
      55          49 :   clib_memset (key, 0, sizeof (sr_localsid_key_t));
      56          49 :   clib_memcpy (&key->address, addr, sizeof (ip6_address_t));
      57          49 :   key->pref_len = pref_len;
      58          49 : }
      59             : 
      60             : /**
      61             :  * @brief SR localsid add/del
      62             :  *
      63             :  * Function to add or delete SR LocalSIDs.
      64             :  *
      65             :  * @param is_del Boolean of whether its a delete instruction
      66             :  * @param localsid_addr IPv6 address of the localsid
      67             :  * @param is_decap Boolean of whether decapsulation is allowed in this function
      68             :  * @param behavior Type of behavior (function) for this localsid
      69             :  * @param sw_if_index Only for L2/L3 xconnect. OIF. In VRF variant the fib_table.
      70             :  * @param vlan_index Only for L2 xconnect. Outgoing VLAN tag.
      71             :  * @param fib_table  FIB table in which we should install the localsid entry
      72             :  * @param nh_addr Next Hop IPv4/IPv6 address. Only for L2/L3 xconnect.
      73             :  *
      74             :  * @return 0 on success, error otherwise.
      75             :  */
      76             : int
      77          49 : sr_cli_localsid (char is_del, ip6_address_t * localsid_addr,
      78             :                  u16 localsid_prefix_len, char end_psp, u8 behavior,
      79             :                  u32 sw_if_index, u32 vlan_index, u32 fib_table,
      80             :                  ip46_address_t * nh_addr, int usid_len, void *ls_plugin_mem)
      81             : {
      82          49 :   ip6_sr_main_t *sm = &sr_main;
      83             :   uword *p;
      84             :   int rv;
      85          49 :   u8 pref_length = 128;
      86          49 :   sr_localsid_fn_registration_t *plugin = 0;
      87             :   sr_localsid_key_t key;
      88             : 
      89          49 :   ip6_sr_localsid_t *ls = 0;
      90             : 
      91          49 :   dpo_id_t dpo = DPO_INVALID;
      92             : 
      93             :   /* Search for the item */
      94          49 :   sr_localsid_key_create (&key, localsid_addr, localsid_prefix_len);
      95          49 :   p = mhash_get (&sm->sr_localsids_index_hash, &key);
      96             : 
      97          49 :   if (p)
      98             :     {
      99          20 :       if (is_del)
     100             :         {
     101             :           /* Retrieve localsid */
     102          20 :           ls = pool_elt_at_index (sm->localsids, p[0]);
     103          20 :           if (ls->behavior >= SR_BEHAVIOR_LAST)
     104             :             {
     105          11 :               plugin = pool_elt_at_index (sm->plugin_functions,
     106             :                                           ls->behavior - SR_BEHAVIOR_LAST);
     107          11 :               pref_length = plugin->prefix_length;
     108             :             }
     109             : 
     110          20 :           if (localsid_prefix_len != 0)
     111             :             {
     112           9 :               pref_length = localsid_prefix_len;
     113             :             }
     114             : 
     115             :           /* Delete FIB entry */
     116          20 :           fib_prefix_t pfx = {
     117             :             .fp_proto = FIB_PROTOCOL_IP6,
     118             :             .fp_len = pref_length,
     119             :             .fp_addr = {
     120             :                         .ip6 = *localsid_addr,
     121             :                         }
     122             :           };
     123             : 
     124          20 :           fib_table_entry_delete (fib_table_find
     125             :                                   (FIB_PROTOCOL_IP6, fib_table), &pfx,
     126             :                                   FIB_SOURCE_SR);
     127             : 
     128             :           /* In case it is a Xconnect iface remove the (OIF, NHOP) adj */
     129          20 :           if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX6
     130          17 :               || ls->behavior == SR_BEHAVIOR_DX4)
     131           4 :             adj_unlock (ls->nh_adj);
     132             : 
     133          20 :           if (ls->behavior >= SR_BEHAVIOR_LAST)
     134             :             {
     135             :               /* Callback plugin removal function */
     136          11 :               rv = plugin->removal (ls);
     137             :             }
     138             : 
     139             :           /* Delete localsid registry */
     140          20 :           pool_put (sm->localsids, ls);
     141          20 :           mhash_unset (&sm->sr_localsids_index_hash, &key, NULL);
     142          20 :           return 0;
     143             :         }
     144             :       else                      /* create with function already existing; complain */
     145           0 :         return -1;
     146             :     }
     147             :   else
     148             :     /* delete; localsid does not exist; complain */
     149          29 :   if (is_del)
     150           0 :     return -2;
     151             : 
     152          29 :   if (behavior >= SR_BEHAVIOR_LAST)
     153             :     {
     154          14 :       sr_localsid_fn_registration_t *plugin = 0;
     155          14 :       plugin =
     156          14 :         pool_elt_at_index (sm->plugin_functions, behavior - SR_BEHAVIOR_LAST);
     157          14 :       pref_length = plugin->prefix_length;
     158             :     }
     159             : 
     160          29 :   if (localsid_prefix_len != 0)
     161             :     {
     162          17 :       pref_length = localsid_prefix_len;
     163             :     }
     164             : 
     165             :   /* Check whether there exists a FIB entry with such address */
     166          29 :   fib_prefix_t pfx = {
     167             :     .fp_proto = FIB_PROTOCOL_IP6,
     168             :     .fp_len = pref_length,
     169             :   };
     170             : 
     171          29 :   pfx.fp_addr.as_u64[0] = localsid_addr->as_u64[0];
     172          29 :   pfx.fp_addr.as_u64[1] = localsid_addr->as_u64[1];
     173          29 :   pfx.fp_len = pref_length;
     174             : 
     175             :   /* Lookup the FIB index associated to the table id provided */
     176          29 :   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, fib_table);
     177          29 :   if (fib_index == ~0)
     178           0 :     return -3;
     179             : 
     180             :   /* Lookup the localsid in such FIB table */
     181          29 :   fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
     182          29 :   if (FIB_NODE_INDEX_INVALID != fei)
     183           0 :     return -4;                  //There is an entry for such address (the localsid addr)
     184             : 
     185             :   /* Create a new localsid registry */
     186          29 :   pool_get (sm->localsids, ls);
     187          29 :   clib_memset (ls, 0, sizeof (*ls));
     188             : 
     189          29 :   clib_memcpy (&ls->localsid, localsid_addr, sizeof (ip6_address_t));
     190          29 :   ls->localsid_prefix_len = pref_length;
     191          29 :   ls->end_psp = end_psp;
     192          29 :   ls->behavior = behavior;
     193          29 :   ls->nh_adj = (u32) ~ 0;
     194          29 :   ls->fib_table = fib_table;
     195          29 :   switch (behavior)
     196             :     {
     197           4 :     case SR_BEHAVIOR_END:
     198           4 :       break;
     199           4 :     case SR_BEHAVIOR_END_UN:
     200             :     case SR_BEHAVIOR_END_UN_PERF:
     201           4 :       if (usid_len)
     202             :         {
     203             :           int usid_width;
     204           4 :           clib_memcpy (&ls->usid_block, localsid_addr,
     205             :                        sizeof (ip6_address_t));
     206             : 
     207           4 :           usid_width = pref_length - usid_len;
     208           4 :           ip6_address_mask_from_width (&ls->usid_block_mask, usid_width);
     209             : 
     210           4 :           ls->usid_index = usid_width / 8;
     211           4 :           ls->usid_len = usid_len / 8;
     212           4 :           ls->usid_next_index = ls->usid_index + ls->usid_len;
     213           4 :           ls->usid_next_len = 16 - ls->usid_next_index;
     214             :         }
     215           4 :       break;
     216           2 :     case SR_BEHAVIOR_X:
     217           2 :       ls->sw_if_index = sw_if_index;
     218           2 :       clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
     219           2 :       break;
     220           0 :     case SR_BEHAVIOR_T:
     221           0 :       ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
     222           0 :       break;
     223           1 :     case SR_BEHAVIOR_DX4:
     224           1 :       ls->sw_if_index = sw_if_index;
     225           1 :       clib_memcpy (&ls->next_hop.ip4, &nh_addr->ip4, sizeof (ip4_address_t));
     226           1 :       break;
     227           1 :     case SR_BEHAVIOR_DX6:
     228           1 :       ls->sw_if_index = sw_if_index;
     229           1 :       clib_memcpy (&ls->next_hop.ip6, &nh_addr->ip6, sizeof (ip6_address_t));
     230           1 :       break;
     231           1 :     case SR_BEHAVIOR_DT6:
     232           1 :       ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP6, sw_if_index);
     233           1 :       break;
     234           1 :     case SR_BEHAVIOR_DT4:
     235           1 :       ls->vrf_index = fib_table_find (FIB_PROTOCOL_IP4, sw_if_index);
     236           1 :       break;
     237           1 :     case SR_BEHAVIOR_DX2:
     238           1 :       ls->sw_if_index = sw_if_index;
     239           1 :       ls->vlan_index = vlan_index;
     240           1 :       break;
     241             :     }
     242             : 
     243             :   /* Figure out the adjacency magic for Xconnect variants */
     244          29 :   if (ls->behavior == SR_BEHAVIOR_X || ls->behavior == SR_BEHAVIOR_DX4
     245          26 :       || ls->behavior == SR_BEHAVIOR_DX6)
     246             :     {
     247           4 :       adj_index_t nh_adj_index = ADJ_INDEX_INVALID;
     248             : 
     249             :       /* Retrieve the adjacency corresponding to the (OIF, next_hop) */
     250           4 :       if (ls->behavior == SR_BEHAVIOR_DX6 || ls->behavior == SR_BEHAVIOR_X)
     251           3 :         nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6, VNET_LINK_IP6,
     252             :                                             nh_addr, sw_if_index);
     253             : 
     254           1 :       else if (ls->behavior == SR_BEHAVIOR_DX4)
     255           1 :         nh_adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, VNET_LINK_IP4,
     256             :                                             nh_addr, sw_if_index);
     257             : 
     258             :       /* Check for ADJ creation error. If so panic */
     259           4 :       if (nh_adj_index == ADJ_INDEX_INVALID)
     260             :         {
     261           0 :           pool_put (sm->localsids, ls);
     262           0 :           return -5;
     263             :         }
     264             : 
     265           4 :       ls->nh_adj = nh_adj_index;
     266             :     }
     267             : 
     268             :   /* Set DPO */
     269          29 :   if (ls->behavior == SR_BEHAVIOR_END || ls->behavior == SR_BEHAVIOR_X
     270          23 :       || ls->behavior == SR_BEHAVIOR_T)
     271           6 :     dpo_set (&dpo, sr_localsid_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
     272          23 :   else if (ls->behavior == SR_BEHAVIOR_END_UN)
     273           2 :     dpo_set (&dpo, sr_localsid_un_dpo_type, DPO_PROTO_IP6,
     274           2 :              ls - sm->localsids);
     275          21 :   else if (ls->behavior == SR_BEHAVIOR_END_UN_PERF)
     276           2 :     dpo_set (&dpo, sr_localsid_un_perf_dpo_type, DPO_PROTO_IP6,
     277           2 :              ls - sm->localsids);
     278          19 :   else if (ls->behavior > SR_BEHAVIOR_D_FIRST
     279          19 :            && ls->behavior < SR_BEHAVIOR_LAST)
     280           5 :     dpo_set (&dpo, sr_localsid_d_dpo_type, DPO_PROTO_IP6, ls - sm->localsids);
     281          14 :   else if (ls->behavior >= SR_BEHAVIOR_LAST)
     282             :     {
     283          14 :       sr_localsid_fn_registration_t *plugin = 0;
     284          14 :       plugin = pool_elt_at_index (sm->plugin_functions,
     285             :                                   ls->behavior - SR_BEHAVIOR_LAST);
     286             :       /* Copy the unformat memory result */
     287          14 :       ls->plugin_mem = ls_plugin_mem;
     288             :       /* Callback plugin creation function */
     289          14 :       rv = plugin->creation (ls);
     290          14 :       if (rv)
     291             :         {
     292           0 :           pool_put (sm->localsids, ls);
     293           0 :           return -6;
     294             :         }
     295          14 :       dpo_set (&dpo, plugin->dpo, DPO_PROTO_IP6, ls - sm->localsids);
     296             :     }
     297             : 
     298             :   /* Set hash key for searching localsid by address */
     299          29 :   mhash_set (&sm->sr_localsids_index_hash, &key, ls - sm->localsids, NULL);
     300             : 
     301          29 :   fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_SR,
     302             :                                    FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
     303          29 :   dpo_reset (&dpo);
     304             : 
     305             :   /* Set counter to zero */
     306          29 :   vlib_validate_combined_counter (&(sm->sr_ls_valid_counters),
     307          29 :                                   ls - sm->localsids);
     308          29 :   vlib_validate_combined_counter (&(sm->sr_ls_invalid_counters),
     309          29 :                                   ls - sm->localsids);
     310             : 
     311          29 :   vlib_zero_combined_counter (&(sm->sr_ls_valid_counters),
     312          29 :                               ls - sm->localsids);
     313          29 :   vlib_zero_combined_counter (&(sm->sr_ls_invalid_counters),
     314          29 :                               ls - sm->localsids);
     315             : 
     316          29 :   return 0;
     317             : }
     318             : 
     319             : /**
     320             :  * @brief SR LocalSID CLI function.
     321             :  *
     322             :  * @see sr_cli_localsid
     323             :  */
     324             : static clib_error_t *
     325          29 : sr_cli_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
     326             :                             vlib_cli_command_t * cmd)
     327             : {
     328          29 :   vnet_main_t *vnm = vnet_get_main ();
     329          29 :   ip6_sr_main_t *sm = &sr_main;
     330          29 :   u32 sw_if_index = (u32) ~ 0, vlan_index = (u32) ~ 0, fib_index = 0;
     331          29 :   int prefix_len = 0;
     332          29 :   int is_del = 0;
     333          29 :   int end_psp = 0;
     334             :   ip6_address_t resulting_address;
     335             :   ip46_address_t next_hop;
     336          29 :   char address_set = 0;
     337          29 :   char behavior = 0;
     338          29 :   void *ls_plugin_mem = 0;
     339          29 :   int usid_size = 0;
     340             : 
     341             :   int rv;
     342             : 
     343          29 :   clib_memset (&resulting_address, 0, sizeof (ip6_address_t));
     344          29 :   ip46_address_reset (&next_hop);
     345             : 
     346          87 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     347             :     {
     348          58 :       if (unformat (input, "del"))
     349          11 :         is_del = 1;
     350          47 :       else if (!address_set
     351          29 :                && unformat (input, "prefix %U/%u", unformat_ip6_address,
     352             :                             &resulting_address, &prefix_len))
     353           6 :         address_set = 1;
     354          41 :       else if (!address_set
     355          23 :                && unformat (input, "address %U", unformat_ip6_address,
     356             :                             &resulting_address))
     357          23 :         address_set = 1;
     358          18 :       else if (!address_set
     359           0 :                && unformat (input, "addr %U", unformat_ip6_address,
     360             :                             &resulting_address))
     361           0 :         address_set = 1;
     362          18 :       else if (unformat (input, "fib-table %u", &fib_index));
     363          18 :       else if (vlan_index == (u32) ~ 0
     364          18 :                && unformat (input, "vlan %u", &vlan_index));
     365          18 :       else if (!behavior && unformat (input, "behavior"))
     366             :         {
     367          18 :           if (unformat (input, "end.x %U %U",
     368             :                         unformat_vnet_sw_interface, vnm, &sw_if_index,
     369             :                         unformat_ip6_address, &next_hop.ip6))
     370           0 :             behavior = SR_BEHAVIOR_X;
     371          18 :           else if (unformat (input, "end.t %u", &sw_if_index))
     372           0 :             behavior = SR_BEHAVIOR_T;
     373          18 :           else if (unformat (input, "end.dx6 %U %U",
     374             :                              unformat_vnet_sw_interface, vnm, &sw_if_index,
     375             :                              unformat_ip6_address, &next_hop.ip6))
     376           0 :             behavior = SR_BEHAVIOR_DX6;
     377          18 :           else if (unformat (input, "end.dx4 %U %U",
     378             :                              unformat_vnet_sw_interface, vnm, &sw_if_index,
     379             :                              unformat_ip4_address, &next_hop.ip4))
     380           0 :             behavior = SR_BEHAVIOR_DX4;
     381          18 :           else if (unformat (input, "end.dx2 %U",
     382             :                              unformat_vnet_sw_interface, vnm, &sw_if_index))
     383           0 :             behavior = SR_BEHAVIOR_DX2;
     384          18 :           else if (unformat (input, "end.dt6 %u", &sw_if_index))
     385           0 :             behavior = SR_BEHAVIOR_DT6;
     386          18 :           else if (unformat (input, "end.dt4 %u", &sw_if_index))
     387           0 :             behavior = SR_BEHAVIOR_DT4;
     388          18 :           else if (unformat (input, "un %u", &usid_size))
     389           2 :             behavior = SR_BEHAVIOR_END_UN_PERF;
     390          16 :           else if (unformat (input, "un.flex %u", &usid_size))
     391           2 :             behavior = SR_BEHAVIOR_END_UN;
     392             :           else
     393             :             {
     394             :               /* Loop over all the plugin behavior format functions */
     395          14 :               sr_localsid_fn_registration_t *plugin = 0, **vec_plugins = 0;
     396          14 :               sr_localsid_fn_registration_t **plugin_it = 0;
     397             : 
     398             :               /* Create a vector out of the plugin pool as recommended */
     399             :               /* *INDENT-OFF* */
     400         140 :               pool_foreach (plugin, sm->plugin_functions)
     401             :                 {
     402         126 :                   vec_add1 (vec_plugins, plugin);
     403             :                 }
     404             :               /* *INDENT-ON* */
     405             : 
     406          49 :               vec_foreach (plugin_it, vec_plugins)
     407             :               {
     408          49 :                 if (unformat
     409          49 :                     (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
     410             :                   {
     411          14 :                     behavior = (*plugin_it)->sr_localsid_function_number;
     412          14 :                     break;
     413             :                   }
     414             :               }
     415             :             }
     416             : 
     417          18 :           if (!behavior)
     418             :             {
     419           0 :               if (unformat (input, "end"))
     420           0 :                 behavior = SR_BEHAVIOR_END;
     421             :               else
     422           0 :                 break;
     423             :             }
     424             :         }
     425           0 :       else if (!end_psp && unformat (input, "psp"))
     426           0 :         end_psp = 1;
     427             :       else
     428             :         break;
     429             :     }
     430             : 
     431          29 :   if (!behavior && end_psp)
     432           0 :     behavior = SR_BEHAVIOR_END;
     433             : 
     434          29 :   if (usid_size)
     435             :     {
     436           4 :       if (prefix_len < usid_size)
     437           0 :         return clib_error_return (0,
     438             :                                   "Error: Prefix length must be greater"
     439             :                                   " than uSID length.");
     440             : 
     441           4 :       if (usid_size != 16 && usid_size != 32)
     442           0 :         return clib_error_return (0,
     443             :                                   "Error: Invalid uSID length (16 or 32).");
     444             : 
     445           4 :       if ((prefix_len - usid_size) & 0x7)
     446           0 :         return clib_error_return (0,
     447             :                                   "Error: Prefix Length must be multiple of 8.");
     448             :     }
     449             : 
     450          29 :   if (!address_set)
     451           0 :     return clib_error_return (0,
     452             :                               "Error: SRv6 LocalSID address is mandatory.");
     453          29 :   if (!is_del && !behavior)
     454           0 :     return clib_error_return (0,
     455             :                               "Error: SRv6 LocalSID behavior is mandatory.");
     456          29 :   if (vlan_index != (u32) ~ 0)
     457           0 :     return clib_error_return (0,
     458             :                               "Error: SRv6 End.DX2 with rewrite VLAN tag not supported by now.");
     459          29 :   if (end_psp && !(behavior == SR_BEHAVIOR_END || behavior == SR_BEHAVIOR_X))
     460           0 :     return clib_error_return (0,
     461             :                               "Error: SRv6 PSP only compatible with End and End.X");
     462             : 
     463             :   rv =
     464          29 :     sr_cli_localsid (is_del, &resulting_address, prefix_len, end_psp,
     465             :                      behavior, sw_if_index, vlan_index, fib_index, &next_hop,
     466             :                      usid_size, ls_plugin_mem);
     467             : 
     468          29 :   if (behavior == SR_BEHAVIOR_END_UN_PERF)
     469             :     {
     470           2 :       if (rv == 0)
     471             :         {
     472             :           u16 perf_len;
     473           2 :           perf_len = prefix_len + usid_size;
     474           2 :           rv = sr_cli_localsid (is_del, &resulting_address, perf_len, end_psp,
     475             :                                 SR_BEHAVIOR_END, sw_if_index, vlan_index,
     476             :                                 fib_index, &next_hop, 0, ls_plugin_mem);
     477             :         }
     478             :     }
     479             : 
     480          29 :   switch (rv)
     481             :     {
     482          29 :     case 0:
     483          29 :       break;
     484           0 :     case 1:
     485           0 :       return 0;
     486           0 :     case -1:
     487           0 :       return clib_error_return (0,
     488             :                                 "Identical localsid already exists. Requested localsid not created.");
     489           0 :     case -2:
     490           0 :       return clib_error_return (0,
     491             :                                 "The requested localsid could not be deleted. SR localsid not found");
     492           0 :     case -3:
     493           0 :       return clib_error_return (0, "FIB table %u does not exist", fib_index);
     494           0 :     case -4:
     495           0 :       return clib_error_return (0, "There is already one FIB entry for the"
     496             :                                 "requested localsid non segment routing related");
     497           0 :     case -5:
     498           0 :       return clib_error_return (0,
     499             :                                 "Could not create ARP/ND entry for such next_hop. Internal error.");
     500           0 :     case -6:
     501           0 :       return clib_error_return (0,
     502             :                                 "Error on the plugin based localsid creation.");
     503           0 :     default:
     504           0 :       return clib_error_return (0, "BUG: sr localsid returns %d", rv);
     505             :     }
     506          29 :   return 0;
     507             : }
     508             : 
     509             : /* *INDENT-OFF* */
     510      272887 : VLIB_CLI_COMMAND (sr_localsid_command, static) = {
     511             :   .path = "sr localsid",
     512             :   .short_help = "sr localsid (del) address XX:XX::YY:YY"
     513             :       "(fib-table 8) behavior STRING",
     514             :   .long_help =
     515             :     "Create SR LocalSID and binds it to a particular behavior\n"
     516             :     "Arguments:\n"
     517             :     "\tlocalSID IPv6_addr(128b)   LocalSID IPv6 address\n"
     518             :     "\t(fib-table X)              Optional. VRF where to install SRv6 localsid\n"
     519             :     "\tbehavior STRING            Specifies the behavior\n"
     520             :     "\n\tBehaviors:\n"
     521             :     "\tEnd\t-> Endpoint.\n"
     522             :     "\tEnd.uN\t-> Endpoint with uSID.\n"
     523             :     "\tEnd.X\t-> Endpoint with decapsulation and Layer-3 cross-connect.\n"
     524             :     "\t\tParameters: '<iface> <ip6_next_hop>'\n"
     525             :     "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
     526             :     "\t\tParameters: '<iface>'\n"
     527             :     "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
     528             :     "\t\tParameters: '<iface> <ip6_next_hop>'\n"
     529             :     "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
     530             :     "\t\tParameters: '<iface> <ip4_next_hop>'\n"
     531             :     "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
     532             :     "\t\tParameters: '<ip6_fib_table>'\n"
     533             :     "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
     534             :     "\t\tParameters: '<ip4_fib_table>'\n",
     535             :   .function = sr_cli_localsid_command_fn,
     536             : };
     537             : /* *INDENT-ON* */
     538             : 
     539             : /**
     540             :  * @brief CLI function to 'show' all SR LocalSIDs on console.
     541             :  */
     542             : static clib_error_t *
     543          59 : show_sr_localsid_command_fn (vlib_main_t * vm, unformat_input_t * input,
     544             :                              vlib_cli_command_t * cmd)
     545             : {
     546          59 :   vnet_main_t *vnm = vnet_get_main ();
     547          59 :   ip6_sr_main_t *sm = &sr_main;
     548          59 :   ip6_sr_localsid_t **localsid_list = 0;
     549             :   ip6_sr_localsid_t *ls;
     550             :   int i;
     551             : 
     552          59 :   vlib_cli_output (vm, "SRv6 - My LocalSID Table:");
     553          59 :   vlib_cli_output (vm, "=========================");
     554             :   /* *INDENT-OFF* */
     555         119 :   pool_foreach (ls, sm->localsids)  { vec_add1 (localsid_list, ls); }
     556             :   /* *INDENT-ON* */
     557         119 :   for (i = 0; i < vec_len (localsid_list); i++)
     558             :     {
     559          60 :       ls = localsid_list[i];
     560          60 :       switch (ls->behavior)
     561             :         {
     562           6 :         case SR_BEHAVIOR_END:
     563           6 :           vlib_cli_output (vm, "\tAddress: \t%U\n\tBehavior: \tEnd",
     564             :                            format_ip6_address, &ls->localsid);
     565           6 :           break;
     566           2 :         case SR_BEHAVIOR_END_UN:
     567           2 :           vlib_cli_output (vm,
     568             :                            "\tAddress: \t%U\n\tBehavior: \tEnd (flex) [uSID:\t%U/%d, length: %d]",
     569             :                            format_ip6_address, &ls->localsid,
     570             :                            format_ip6_address, &ls->usid_block,
     571           2 :                            ls->usid_index * 8, ls->usid_len * 8);
     572           2 :           break;
     573           2 :         case SR_BEHAVIOR_END_UN_PERF:
     574           2 :           vlib_cli_output (vm,
     575             :                            "\tAddress: \t%U\n\tBehavior: \tEnd [uSID:\t%U/%d, length: %d]",
     576             :                            format_ip6_address, &ls->localsid,
     577             :                            format_ip6_address, &ls->usid_block,
     578           2 :                            ls->usid_index * 8, ls->usid_len * 8);
     579           2 :           break;
     580           4 :         case SR_BEHAVIOR_X:
     581           4 :           vlib_cli_output (vm,
     582             :                            "\tAddress: \t%U/%u\n\tBehavior: \tX (Endpoint with Layer-3 cross-connect)"
     583             :                            "\n\tIface:  \t%U\n\tNext hop: \t%U",
     584             :                            format_ip6_address, &ls->localsid,
     585           4 :                            ls->localsid_prefix_len,
     586             :                            format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
     587             :                            format_ip6_address, &ls->next_hop.ip6);
     588           4 :           break;
     589           0 :         case SR_BEHAVIOR_T:
     590           0 :           vlib_cli_output (vm,
     591             :                            "\tAddress: \t%U/%u\n\tBehavior: \tT (Endpoint with specific IPv6 table lookup)"
     592             :                            "\n\tTable:  \t%u",
     593             :                            format_ip6_address, &ls->localsid,
     594           0 :                            ls->localsid_prefix_len,
     595             :                            fib_table_get_table_id (ls->vrf_index,
     596             :                                                    FIB_PROTOCOL_IP6));
     597           0 :           break;
     598           2 :         case SR_BEHAVIOR_DX4:
     599           2 :           vlib_cli_output (vm,
     600             :                            "\tAddress: \t%U/%u\n\tBehavior: \tDX4 (Endpoint with decapsulation and IPv4 cross-connect)"
     601             :                            "\n\tIface:  \t%U\n\tNext hop: \t%U",
     602             :                            format_ip6_address, &ls->localsid,
     603           2 :                            ls->localsid_prefix_len,
     604             :                            format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
     605             :                            format_ip4_address, &ls->next_hop.ip4);
     606           2 :           break;
     607           2 :         case SR_BEHAVIOR_DX6:
     608           2 :           vlib_cli_output (vm,
     609             :                            "\tAddress: \t%U/%u\n\tBehavior: \tDX6 (Endpoint with decapsulation and IPv6 cross-connect)"
     610             :                            "\n\tIface:  \t%U\n\tNext hop: \t%U",
     611             :                            format_ip6_address, &ls->localsid,
     612           2 :                            ls->localsid_prefix_len,
     613             :                            format_vnet_sw_if_index_name, vnm, ls->sw_if_index,
     614             :                            format_ip6_address, &ls->next_hop.ip6);
     615           2 :           break;
     616           2 :         case SR_BEHAVIOR_DX2:
     617           2 :           if (ls->vlan_index == (u32) ~ 0)
     618           0 :             vlib_cli_output (vm,
     619             :                              "\tAddress: \t%U/%u\n\tBehavior: \tDX2 (Endpoint with decapulation and Layer-2 cross-connect)"
     620             :                              "\n\tIface:  \t%U", format_ip6_address,
     621           0 :                              &ls->localsid, ls->localsid_prefix_len,
     622             :                              format_vnet_sw_if_index_name, vnm,
     623             :                              ls->sw_if_index);
     624             :           else
     625           2 :             vlib_cli_output (vm,
     626             :                              "Unsupported yet. (DX2 with egress VLAN rewrite)");
     627           2 :           break;
     628           2 :         case SR_BEHAVIOR_DT6:
     629           2 :           vlib_cli_output (vm,
     630             :                            "\tAddress: \t%U/%u\n\tBehavior: \tDT6 (Endpoint with decapsulation and specific IPv6 table lookup)"
     631             :                            "\n\tTable: %u", format_ip6_address, &ls->localsid,
     632           2 :                            ls->localsid_prefix_len,
     633             :                            fib_table_get_table_id (ls->vrf_index,
     634             :                                                    FIB_PROTOCOL_IP6));
     635           2 :           break;
     636           2 :         case SR_BEHAVIOR_DT4:
     637           2 :           vlib_cli_output (vm,
     638             :                            "\tAddress: \t%U/%u\n\tBehavior: \tDT4 (Endpoint with decapsulation and specific IPv4 table lookup)"
     639             :                            "\n\tTable: \t%u", format_ip6_address,
     640           2 :                            &ls->localsid, ls->localsid_prefix_len,
     641             :                            fib_table_get_table_id (ls->vrf_index,
     642             :                                                    FIB_PROTOCOL_IP4));
     643           2 :           break;
     644          36 :         default:
     645          36 :           if (ls->behavior >= SR_BEHAVIOR_LAST)
     646             :             {
     647          36 :               sr_localsid_fn_registration_t *plugin =
     648          36 :                 pool_elt_at_index (sm->plugin_functions,
     649             :                                    ls->behavior - SR_BEHAVIOR_LAST);
     650             : 
     651          36 :               vlib_cli_output (vm, "\tAddress: \t%U/%u\n"
     652             :                                "\tBehavior: \t%s (%s)\n\t%U",
     653             :                                format_ip6_address, &ls->localsid,
     654          36 :                                ls->localsid_prefix_len, plugin->keyword_str,
     655             :                                plugin->def_str, plugin->ls_format,
     656             :                                ls->plugin_mem);
     657             :             }
     658             :           else
     659             :             //Should never get here...
     660           0 :             vlib_cli_output (vm, "Internal error");
     661          36 :           break;
     662             :         }
     663          60 :       if (ls->end_psp)
     664           4 :         vlib_cli_output (vm, "\tPSP: \tTrue\n");
     665             : 
     666             :       /* Print counters */
     667             :       vlib_counter_t valid, invalid;
     668          60 :       vlib_get_combined_counter (&(sm->sr_ls_valid_counters), i, &valid);
     669          60 :       vlib_get_combined_counter (&(sm->sr_ls_invalid_counters), i, &invalid);
     670          60 :       vlib_cli_output (vm, "\tGood traffic: \t[%Ld packets : %Ld bytes]\n",
     671             :                        valid.packets, valid.bytes);
     672          60 :       vlib_cli_output (vm, "\tBad traffic:  \t[%Ld packets : %Ld bytes]\n",
     673             :                        invalid.packets, invalid.bytes);
     674          60 :       vlib_cli_output (vm, "--------------------");
     675             :     }
     676          59 :   return 0;
     677             : }
     678             : 
     679             : /* *INDENT-OFF* */
     680      272887 : VLIB_CLI_COMMAND (show_sr_localsid_command, static) = {
     681             :   .path = "show sr localsids",
     682             :   .short_help = "show sr localsids",
     683             :   .function = show_sr_localsid_command_fn,
     684             : };
     685             : /* *INDENT-ON* */
     686             : 
     687             : /**
     688             :  * @brief Function to 'clear' ALL SR localsid counters
     689             :  */
     690             : static clib_error_t *
     691           0 : clear_sr_localsid_counters_command_fn (vlib_main_t * vm,
     692             :                                        unformat_input_t * input,
     693             :                                        vlib_cli_command_t * cmd)
     694             : {
     695           0 :   ip6_sr_main_t *sm = &sr_main;
     696             : 
     697           0 :   vlib_clear_combined_counters (&(sm->sr_ls_valid_counters));
     698           0 :   vlib_clear_combined_counters (&(sm->sr_ls_invalid_counters));
     699             : 
     700           0 :   return 0;
     701             : }
     702             : 
     703             : /* *INDENT-OFF* */
     704      272887 : VLIB_CLI_COMMAND (clear_sr_localsid_counters_command, static) = {
     705             :   .path = "clear sr localsid-counters",
     706             :   .short_help = "clear sr localsid-counters",
     707             :   .function = clear_sr_localsid_counters_command_fn,
     708             : };
     709             : /* *INDENT-ON* */
     710             : 
     711             : /************************ SR LocalSID graphs node ****************************/
     712             : /**
     713             :  * @brief SR localsid node trace
     714             :  */
     715             : typedef struct
     716             : {
     717             :   ip6_address_t localsid;
     718             :   u16 behavior;
     719             :   u8 sr[256];
     720             :   u8 num_segments;
     721             :   u8 segments_left;
     722             : } sr_localsid_trace_t;
     723             : 
     724             : #define foreach_sr_localsid_error                                   \
     725             : _(NO_INNER_HEADER, "(SR-Error) No inner IP header")                 \
     726             : _(NO_MORE_SEGMENTS, "(SR-Error) No more segments")                  \
     727             : _(NO_SRH, "(SR-Error) No SR header")                                \
     728             : _(NO_PSP, "(SR-Error) PSP Not available (segments left > 0)")       \
     729             : _(NOT_LS, "(SR-Error) Decaps not available (segments left > 0)")    \
     730             : _(L2, "(SR-Error) SRv6 decapsulated a L2 frame without dest")
     731             : 
     732             : typedef enum
     733             : {
     734             : #define _(sym,str) SR_LOCALSID_ERROR_##sym,
     735             :   foreach_sr_localsid_error
     736             : #undef _
     737             :     SR_LOCALSID_N_ERROR,
     738             : } sr_localsid_error_t;
     739             : 
     740             : static char *sr_localsid_error_strings[] = {
     741             : #define _(sym,string) string,
     742             :   foreach_sr_localsid_error
     743             : #undef _
     744             : };
     745             : 
     746             : #define foreach_sr_localsid_next        \
     747             : _(ERROR, "error-drop")                  \
     748             : _(IP6_LOOKUP, "ip6-lookup")             \
     749             : _(IP4_LOOKUP, "ip4-lookup")             \
     750             : _(IP6_REWRITE, "ip6-rewrite")           \
     751             : _(IP4_REWRITE, "ip4-rewrite")           \
     752             : _(INTERFACE_OUTPUT, "interface-output")
     753             : 
     754             : typedef enum
     755             : {
     756             : #define _(s,n) SR_LOCALSID_NEXT_##s,
     757             :   foreach_sr_localsid_next
     758             : #undef _
     759             :     SR_LOCALSID_N_NEXT,
     760             : } sr_localsid_next_t;
     761             : 
     762             : /**
     763             :  * @brief SR LocalSID graph node trace function
     764             :  *
     765             :  * @see sr_localsid
     766             :  */
     767             : u8 *
     768          71 : format_sr_localsid_trace (u8 * s, va_list * args)
     769             : {
     770          71 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     771          71 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     772          71 :   sr_localsid_trace_t *t = va_arg (*args, sr_localsid_trace_t *);
     773             : 
     774             :   s =
     775          71 :     format (s, "SR-LOCALSID:\n\tLocalsid: %U\n", format_ip6_address,
     776             :             &t->localsid);
     777          71 :   switch (t->behavior)
     778             :     {
     779          15 :     case SR_BEHAVIOR_END:
     780          15 :       s = format (s, "\tBehavior: End\n");
     781          15 :       break;
     782           4 :     case SR_BEHAVIOR_END_UN:
     783           4 :       s = format (s, "\tBehavior: End.uN (flex)\n");
     784           4 :       break;
     785           4 :     case SR_BEHAVIOR_END_UN_PERF:
     786           4 :       s = format (s, "\tBehavior: End.uN\n");
     787           4 :       break;
     788           6 :     case SR_BEHAVIOR_DX6:
     789           6 :       s = format (s, "\tBehavior: Decapsulation with IPv6 L3 xconnect\n");
     790           6 :       break;
     791           6 :     case SR_BEHAVIOR_DX4:
     792           6 :       s = format (s, "\tBehavior: Decapsulation with IPv4 L3 xconnect\n");
     793           6 :       break;
     794          12 :     case SR_BEHAVIOR_X:
     795          12 :       s = format (s, "\tBehavior: IPv6 L3 xconnect\n");
     796          12 :       break;
     797           0 :     case SR_BEHAVIOR_T:
     798           0 :       s = format (s, "\tBehavior: IPv6 specific table lookup\n");
     799           0 :       break;
     800           6 :     case SR_BEHAVIOR_DT6:
     801           6 :       s = format (s, "\tBehavior: Decapsulation with IPv6 Table lookup\n");
     802           6 :       break;
     803           6 :     case SR_BEHAVIOR_DT4:
     804           6 :       s = format (s, "\tBehavior: Decapsulation with IPv4 Table lookup\n");
     805           6 :       break;
     806          12 :     case SR_BEHAVIOR_DX2:
     807          12 :       s = format (s, "\tBehavior: Decapsulation with L2 xconnect\n");
     808          12 :       break;
     809           0 :     default:
     810           0 :       s = format (s, "\tBehavior: defined in plugin\n");      //TODO
     811           0 :       break;
     812             :     }
     813          71 :   if (t->num_segments != 0xFF)
     814             :     {
     815          29 :       if (t->num_segments > 0)
     816             :         {
     817          20 :           s = format (s, "\tSegments left: %d\n", t->segments_left);
     818          20 :           s = format (s, "\tSID list: [in ietf order]");
     819          20 :           int i = 0;
     820          78 :           for (i = 0; i < t->num_segments; i++)
     821             :             {
     822          58 :               s = format (s, "\n\t-> %U", format_ip6_address,
     823          58 :                           (ip6_address_t *) & t->sr[i *
     824             :                                                     sizeof (ip6_address_t)]);
     825             :             }
     826             :         }
     827             :     }
     828          71 :   return s;
     829             : }
     830             : 
     831             : /**
     832             :  * @brief Function doing End processing.
     833             :  */
     834             : static_always_inline void
     835          27 : end_srh_processing (vlib_node_runtime_t * node,
     836             :                     vlib_buffer_t * b0,
     837             :                     ip6_header_t * ip0,
     838             :                     ip6_sr_header_t * sr0,
     839             :                     ip6_sr_localsid_t * ls0,
     840             :                     u32 * next0, u8 psp, ip6_ext_header_t * prev0)
     841             : {
     842             :   ip6_address_t *new_dst0;
     843             : 
     844          27 :   if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
     845             :     {
     846          24 :       if (sr0->segments_left == 1 && psp)
     847           6 :         {
     848             :           u32 new_l0, sr_len;
     849             :           u64 *copy_dst0, *copy_src0;
     850           6 :           u32 copy_len_u64s0 = 0;
     851             : 
     852           6 :           ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
     853           6 :           ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
     854             : 
     855             :           /* Remove the SRH taking care of the rest of IPv6 ext header */
     856           6 :           if (prev0)
     857           0 :             prev0->next_hdr = sr0->protocol;
     858             :           else
     859           6 :             ip0->protocol = sr0->protocol;
     860             : 
     861           6 :           sr_len = ip6_ext_header_len (sr0);
     862           6 :           vlib_buffer_advance (b0, sr_len);
     863           6 :           new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
     864           6 :           ip0->payload_length = clib_host_to_net_u16 (new_l0);
     865           6 :           copy_src0 = (u64 *) ip0;
     866           6 :           copy_dst0 = copy_src0 + (sr0->length + 1);
     867             :           /* number of 8 octet units to copy
     868             :            * By default in absence of extension headers it is equal to length of ip6 header
     869             :            * With extension headers it number of 8 octet units of ext headers preceding
     870             :            * SR header
     871             :            */
     872           6 :           copy_len_u64s0 =
     873           6 :             (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
     874           6 :           copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
     875           6 :           copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
     876           6 :           copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
     877           6 :           copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
     878           6 :           copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
     879             : 
     880             :           int i;
     881           6 :           for (i = copy_len_u64s0 - 1; i >= 0; i--)
     882             :             {
     883           0 :               copy_dst0[i] = copy_src0[i];
     884             :             }
     885             : 
     886           6 :           if (ls0->behavior == SR_BEHAVIOR_X)
     887             :             {
     888           3 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
     889           3 :               *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
     890             :             }
     891           3 :           else if (ls0->behavior == SR_BEHAVIOR_T)
     892             :             {
     893           0 :               vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
     894             :             }
     895             :         }
     896          18 :       else if (PREDICT_TRUE (sr0->segments_left > 0))
     897             :         {
     898          18 :           sr0->segments_left -= 1;
     899          18 :           new_dst0 = (ip6_address_t *) (sr0->segments);
     900          18 :           new_dst0 += sr0->segments_left;
     901          18 :           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
     902          18 :           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
     903             : 
     904          18 :           if (ls0->behavior == SR_BEHAVIOR_X)
     905             :             {
     906           9 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
     907           9 :               *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
     908             :             }
     909           9 :           else if (ls0->behavior == SR_BEHAVIOR_T)
     910             :             {
     911           0 :               vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
     912             :             }
     913             :         }
     914             :       else
     915             :         {
     916           0 :           *next0 = SR_LOCALSID_NEXT_ERROR;
     917           0 :           b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
     918             :         }
     919             :     }
     920             :   else
     921             :     {
     922             :       /* Error. Routing header of type != SR */
     923           3 :       *next0 = SR_LOCALSID_NEXT_ERROR;
     924           3 :       b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
     925             :     }
     926          27 : }
     927             : 
     928             : /**
     929             :  * @brief Function doing End uN processing.
     930             :  */
     931             : static_always_inline void
     932           4 : end_un_srh_processing (vlib_node_runtime_t * node,
     933             :                        vlib_buffer_t * b0,
     934             :                        ip6_header_t * ip0,
     935             :                        ip6_sr_header_t * sr0,
     936             :                        ip6_sr_localsid_t * ls0,
     937             :                        u32 * next0, u8 psp, ip6_ext_header_t * prev0)
     938             : {
     939             :   ip6_address_t *new_dst0;
     940           4 :   bool next_usid = false;
     941             :   u8 next_usid_index;
     942             :   u8 usid_len;
     943             :   u8 index;
     944             : 
     945           4 :   usid_len = ls0->usid_len;
     946           4 :   next_usid_index = ls0->usid_next_index;
     947             : 
     948             :   /* uSID */
     949           4 :   for (index = 0; index < usid_len; index++)
     950             :     {
     951           4 :       if (ip0->dst_address.as_u8[next_usid_index + index] != 0)
     952             :         {
     953           4 :           next_usid = true;
     954           4 :           break;
     955             :         }
     956             :     }
     957             : 
     958           4 :   if (PREDICT_TRUE (next_usid))
     959             :     {
     960             :       u8 offset;
     961             : 
     962           4 :       index = ls0->usid_index;
     963             : 
     964             :       /* advance next usid */
     965          44 :       for (offset = 0; offset < ls0->usid_next_len; offset++)
     966             :         {
     967          40 :           ip0->dst_address.as_u8[index + offset] =
     968          40 :             ip0->dst_address.as_u8[next_usid_index + offset];
     969             :         }
     970             : 
     971          12 :       for (index = 16 - usid_len; index < 16; index++)
     972             :         {
     973           8 :           ip0->dst_address.as_u8[index] = 0;
     974             :         }
     975             : 
     976           4 :       return;
     977             :     }
     978             : 
     979           0 :   if (PREDICT_TRUE (sr0 && sr0->type == ROUTING_HEADER_TYPE_SR))
     980             :     {
     981           0 :       if (sr0->segments_left == 1 && psp)
     982           0 :         {
     983             :           u32 new_l0, sr_len;
     984             :           u64 *copy_dst0, *copy_src0;
     985           0 :           u32 copy_len_u64s0 = 0;
     986             : 
     987           0 :           ip0->dst_address.as_u64[0] = sr0->segments->as_u64[0];
     988           0 :           ip0->dst_address.as_u64[1] = sr0->segments->as_u64[1];
     989             : 
     990             :           /* Remove the SRH taking care of the rest of IPv6 ext header */
     991           0 :           if (prev0)
     992           0 :             prev0->next_hdr = sr0->protocol;
     993             :           else
     994           0 :             ip0->protocol = sr0->protocol;
     995             : 
     996           0 :           sr_len = ip6_ext_header_len (sr0);
     997           0 :           vlib_buffer_advance (b0, sr_len);
     998           0 :           new_l0 = clib_net_to_host_u16 (ip0->payload_length) - sr_len;
     999           0 :           ip0->payload_length = clib_host_to_net_u16 (new_l0);
    1000           0 :           copy_src0 = (u64 *) ip0;
    1001           0 :           copy_dst0 = copy_src0 + (sr0->length + 1);
    1002             :           /* number of 8 octet units to copy
    1003             :            * By default in absence of extension headers it is equal to length of ip6 header
    1004             :            * With extension headers it number of 8 octet units of ext headers preceding
    1005             :            * SR header
    1006             :            */
    1007           0 :           copy_len_u64s0 =
    1008           0 :             (((u8 *) sr0 - (u8 *) ip0) - sizeof (ip6_header_t)) >> 3;
    1009           0 :           copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
    1010           0 :           copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
    1011           0 :           copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
    1012           0 :           copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
    1013           0 :           copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
    1014             : 
    1015             :           int i;
    1016           0 :           for (i = copy_len_u64s0 - 1; i >= 0; i--)
    1017             :             {
    1018           0 :               copy_dst0[i] = copy_src0[i];
    1019             :             }
    1020             :         }
    1021           0 :       else if (PREDICT_TRUE (sr0->segments_left > 0))
    1022             :         {
    1023           0 :           sr0->segments_left -= 1;
    1024           0 :           new_dst0 = (ip6_address_t *) (sr0->segments);
    1025           0 :           new_dst0 += sr0->segments_left;
    1026           0 :           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
    1027           0 :           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
    1028             :         }
    1029             :       else
    1030             :         {
    1031           0 :           *next0 = SR_LOCALSID_NEXT_ERROR;
    1032           0 :           b0->error = node->errors[SR_LOCALSID_ERROR_NO_MORE_SEGMENTS];
    1033             :         }
    1034             :     }
    1035             :   else
    1036             :     {
    1037             :       /* Error. Routing header of type != SR */
    1038           0 :       *next0 = SR_LOCALSID_NEXT_ERROR;
    1039           0 :       b0->error = node->errors[SR_LOCALSID_ERROR_NO_SRH];
    1040             :     }
    1041             : }
    1042             : 
    1043             : static_always_inline void
    1044           4 : end_un_processing (ip6_header_t * ip0, ip6_sr_localsid_t * ls0)
    1045             : {
    1046             :   u8 next_usid_index;
    1047             :   u8 index;
    1048             :   u8 offset;
    1049             : 
    1050             :   /* uSID */
    1051           4 :   index = ls0->usid_index;
    1052           4 :   next_usid_index = ls0->usid_next_index;
    1053             : 
    1054             :   /* advance next usid */
    1055          44 :   for (offset = 0; offset < ls0->usid_next_len; offset++)
    1056             :     {
    1057          40 :       ip0->dst_address.as_u8[index + offset] =
    1058          40 :         ip0->dst_address.as_u8[next_usid_index + offset];
    1059             :     }
    1060             : 
    1061          12 :   for (index = 16 - ls0->usid_len; index < 16; index++)
    1062             :     {
    1063           8 :       ip0->dst_address.as_u8[index] = 0;
    1064             :     }
    1065             : 
    1066           4 :   return;
    1067             : }
    1068             : 
    1069             : /*
    1070             :  * @brief Function doing SRH processing for D* variants
    1071             :  */
    1072             : static_always_inline void
    1073          36 : end_decaps_srh_processing (vlib_node_runtime_t * node,
    1074             :                            vlib_buffer_t * b0,
    1075             :                            ip6_header_t * ip0,
    1076             :                            ip6_sr_header_t * sr0,
    1077             :                            ip6_sr_localsid_t * ls0, u32 * next0)
    1078             : {
    1079             :   /* Compute the size of the IPv6 header with all Ext. headers */
    1080             :   u8 next_proto;
    1081             :   ip6_ext_header_t *next_ext_header;
    1082          36 :   u16 total_size = 0;
    1083             : 
    1084          36 :   next_proto = ip0->protocol;
    1085          36 :   next_ext_header = (void *) (ip0 + 1);
    1086          36 :   total_size = sizeof (ip6_header_t);
    1087          54 :   while (ip6_ext_hdr (next_proto))
    1088             :     {
    1089          18 :       total_size += ip6_ext_header_len (next_ext_header);
    1090          18 :       next_proto = next_ext_header->next_hdr;
    1091          18 :       next_ext_header = ip6_ext_next_header (next_ext_header);
    1092             :     }
    1093             : 
    1094             :   /* Ensure this is the last segment. Otherwise drop. */
    1095          36 :   if (sr0 && sr0->segments_left != 0)
    1096             :     {
    1097           0 :       *next0 = SR_LOCALSID_NEXT_ERROR;
    1098           0 :       b0->error = node->errors[SR_LOCALSID_ERROR_NOT_LS];
    1099           0 :       return;
    1100             :     }
    1101             : 
    1102          36 :   switch (next_proto)
    1103             :     {
    1104          12 :     case IP_PROTOCOL_IPV6:
    1105             :       /* Encap-End IPv6. Pop outer IPv6 header. */
    1106          12 :       if (ls0->behavior == SR_BEHAVIOR_DX6)
    1107             :         {
    1108           6 :           vlib_buffer_advance (b0, total_size);
    1109           6 :           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
    1110           6 :           *next0 = SR_LOCALSID_NEXT_IP6_REWRITE;
    1111           6 :           return;
    1112             :         }
    1113           6 :       else if (ls0->behavior == SR_BEHAVIOR_DT6)
    1114             :         {
    1115           6 :           vlib_buffer_advance (b0, total_size);
    1116           6 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
    1117           6 :           return;
    1118             :         }
    1119           0 :       break;
    1120          12 :     case IP_PROTOCOL_IP_IN_IP:
    1121             :       /* Encap-End IPv4. Pop outer IPv6 header */
    1122          12 :       if (ls0->behavior == SR_BEHAVIOR_DX4)
    1123             :         {
    1124           6 :           vlib_buffer_advance (b0, total_size);
    1125           6 :           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
    1126           6 :           *next0 = SR_LOCALSID_NEXT_IP4_REWRITE;
    1127           6 :           return;
    1128             :         }
    1129           6 :       else if (ls0->behavior == SR_BEHAVIOR_DT4)
    1130             :         {
    1131           6 :           vlib_buffer_advance (b0, total_size);
    1132           6 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->vrf_index;
    1133           6 :           *next0 = SR_LOCALSID_NEXT_IP4_LOOKUP;
    1134           6 :           return;
    1135             :         }
    1136           0 :       break;
    1137          12 :     case IP_PROTOCOL_IP6_ETHERNET:
    1138             :       /* L2 encaps */
    1139          12 :       if (ls0->behavior == SR_BEHAVIOR_DX2)
    1140             :         {
    1141          12 :           vlib_buffer_advance (b0, total_size);
    1142          12 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = ls0->sw_if_index;
    1143          12 :           *next0 = SR_LOCALSID_NEXT_INTERFACE_OUTPUT;
    1144          12 :           return;
    1145             :         }
    1146           0 :       break;
    1147             :     }
    1148           0 :   *next0 = SR_LOCALSID_NEXT_ERROR;
    1149           0 :   b0->error = node->errors[SR_LOCALSID_ERROR_NO_INNER_HEADER];
    1150           0 :   return;
    1151             : }
    1152             : 
    1153             : /**
    1154             :  * @brief SR LocalSID graph node. Supports all default SR Endpoint variants with decaps
    1155             :  */
    1156             : static uword
    1157           5 : sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1158             :                   vlib_frame_t * from_frame)
    1159             : {
    1160             :   u32 n_left_from, next_index, *from, *to_next;
    1161           5 :   ip6_sr_main_t *sm = &sr_main;
    1162           5 :   from = vlib_frame_vector_args (from_frame);
    1163           5 :   n_left_from = from_frame->n_vectors;
    1164           5 :   next_index = node->cached_next_index;
    1165           5 :   u32 thread_index = vm->thread_index;
    1166             : 
    1167          10 :   while (n_left_from > 0)
    1168             :     {
    1169             :       u32 n_left_to_next;
    1170           5 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1171             : 
    1172             :       /* Quad - Loop */
    1173           7 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    1174             :         {
    1175             :           u32 bi0, bi1, bi2, bi3;
    1176             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    1177             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    1178             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    1179             :           u32 next0, next1, next2, next3;
    1180           2 :           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    1181             :           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
    1182             : 
    1183             :           /* Prefetch next iteration. */
    1184             :           {
    1185             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    1186             : 
    1187           2 :             p4 = vlib_get_buffer (vm, from[4]);
    1188           2 :             p5 = vlib_get_buffer (vm, from[5]);
    1189           2 :             p6 = vlib_get_buffer (vm, from[6]);
    1190           2 :             p7 = vlib_get_buffer (vm, from[7]);
    1191             : 
    1192             :             /* Prefetch the buffer header and packet for the N+4 loop iteration */
    1193           2 :             vlib_prefetch_buffer_header (p4, LOAD);
    1194           2 :             vlib_prefetch_buffer_header (p5, LOAD);
    1195           2 :             vlib_prefetch_buffer_header (p6, LOAD);
    1196           2 :             vlib_prefetch_buffer_header (p7, LOAD);
    1197             : 
    1198           2 :             clib_prefetch_store (p4->data);
    1199           2 :             clib_prefetch_store (p5->data);
    1200           2 :             clib_prefetch_store (p6->data);
    1201           2 :             clib_prefetch_store (p7->data);
    1202             :           }
    1203             : 
    1204           2 :           to_next[0] = bi0 = from[0];
    1205           2 :           to_next[1] = bi1 = from[1];
    1206           2 :           to_next[2] = bi2 = from[2];
    1207           2 :           to_next[3] = bi3 = from[3];
    1208           2 :           from += 4;
    1209           2 :           to_next += 4;
    1210           2 :           n_left_from -= 4;
    1211           2 :           n_left_to_next -= 4;
    1212             : 
    1213           2 :           b0 = vlib_get_buffer (vm, bi0);
    1214           2 :           b1 = vlib_get_buffer (vm, bi1);
    1215           2 :           b2 = vlib_get_buffer (vm, bi2);
    1216           2 :           b3 = vlib_get_buffer (vm, bi3);
    1217             : 
    1218           2 :           ls0 =
    1219           2 :             pool_elt_at_index (sm->localsids,
    1220             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1221           2 :           ls1 =
    1222           2 :             pool_elt_at_index (sm->localsids,
    1223             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    1224           2 :           ls2 =
    1225           2 :             pool_elt_at_index (sm->localsids,
    1226             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    1227           2 :           ls3 =
    1228           2 :             pool_elt_at_index (sm->localsids,
    1229             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    1230             : 
    1231           2 :           ip0 = vlib_buffer_get_current (b0);
    1232           2 :           ip1 = vlib_buffer_get_current (b1);
    1233           2 :           ip2 = vlib_buffer_get_current (b2);
    1234           2 :           ip3 = vlib_buffer_get_current (b3);
    1235             : 
    1236             :           sr0 =
    1237           2 :             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
    1238             :           sr1 =
    1239           2 :             ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, NULL);
    1240             :           sr2 =
    1241           2 :             ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, NULL);
    1242             :           sr3 =
    1243           2 :             ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, NULL);
    1244             : 
    1245           2 :           end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
    1246           2 :           end_decaps_srh_processing (node, b1, ip1, sr1, ls1, &next1);
    1247           2 :           end_decaps_srh_processing (node, b2, ip2, sr2, ls2, &next2);
    1248           2 :           end_decaps_srh_processing (node, b3, ip3, sr3, ls3, &next3);
    1249             : 
    1250           2 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1251             :             {
    1252             :               sr_localsid_trace_t *tr =
    1253           2 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1254           2 :               tr->num_segments = 0;
    1255           2 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    1256             :                            sizeof (tr->localsid.as_u8));
    1257           2 :               tr->behavior = ls0->behavior;
    1258           2 :               if (ip0 == vlib_buffer_get_current (b0))
    1259             :                 {
    1260           0 :                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
    1261           0 :                       && sr0->type == ROUTING_HEADER_TYPE_SR)
    1262             :                     {
    1263           0 :                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
    1264           0 :                       tr->num_segments =
    1265           0 :                         sr0->length * 8 / sizeof (ip6_address_t);
    1266           0 :                       tr->segments_left = sr0->segments_left;
    1267             :                     }
    1268             :                 }
    1269             :               else
    1270           2 :                 tr->num_segments = 0xFF;
    1271             :             }
    1272             : 
    1273           2 :           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    1274             :             {
    1275             :               sr_localsid_trace_t *tr =
    1276           2 :                 vlib_add_trace (vm, node, b1, sizeof (*tr));
    1277           2 :               tr->num_segments = 0;
    1278           2 :               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
    1279             :                            sizeof (tr->localsid.as_u8));
    1280           2 :               tr->behavior = ls1->behavior;
    1281           2 :               if (ip1 == vlib_buffer_get_current (b1))
    1282             :                 {
    1283           0 :                   if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
    1284           0 :                       && sr1->type == ROUTING_HEADER_TYPE_SR)
    1285             :                     {
    1286           0 :                       clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
    1287           0 :                       tr->num_segments =
    1288           0 :                         sr1->length * 8 / sizeof (ip6_address_t);
    1289           0 :                       tr->segments_left = sr1->segments_left;
    1290             :                     }
    1291             :                 }
    1292             :               else
    1293           2 :                 tr->num_segments = 0xFF;
    1294             :             }
    1295             : 
    1296           2 :           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    1297             :             {
    1298             :               sr_localsid_trace_t *tr =
    1299           2 :                 vlib_add_trace (vm, node, b2, sizeof (*tr));
    1300           2 :               tr->num_segments = 0;
    1301           2 :               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
    1302             :                            sizeof (tr->localsid.as_u8));
    1303           2 :               tr->behavior = ls2->behavior;
    1304           2 :               if (ip2 == vlib_buffer_get_current (b2))
    1305             :                 {
    1306           0 :                   if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
    1307           0 :                       && sr2->type == ROUTING_HEADER_TYPE_SR)
    1308             :                     {
    1309           0 :                       clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
    1310           0 :                       tr->num_segments =
    1311           0 :                         sr2->length * 8 / sizeof (ip6_address_t);
    1312           0 :                       tr->segments_left = sr2->segments_left;
    1313             :                     }
    1314             :                 }
    1315             :               else
    1316           2 :                 tr->num_segments = 0xFF;
    1317             :             }
    1318             : 
    1319           2 :           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    1320             :             {
    1321             :               sr_localsid_trace_t *tr =
    1322           2 :                 vlib_add_trace (vm, node, b3, sizeof (*tr));
    1323           2 :               tr->num_segments = 0;
    1324           2 :               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
    1325             :                            sizeof (tr->localsid.as_u8));
    1326           2 :               tr->behavior = ls3->behavior;
    1327           2 :               if (ip3 == vlib_buffer_get_current (b3))
    1328             :                 {
    1329           0 :                   if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
    1330           0 :                       && sr3->type == ROUTING_HEADER_TYPE_SR)
    1331             :                     {
    1332           0 :                       clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
    1333           0 :                       tr->num_segments =
    1334           0 :                         sr3->length * 8 / sizeof (ip6_address_t);
    1335           0 :                       tr->segments_left = sr3->segments_left;
    1336             :                     }
    1337             :                 }
    1338             :               else
    1339           2 :                 tr->num_segments = 0xFF;
    1340             :             }
    1341             : 
    1342           4 :           vlib_increment_combined_counter
    1343           2 :             (((next0 ==
    1344             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1345           2 :               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
    1346             :              1, vlib_buffer_length_in_chain (vm, b0));
    1347             : 
    1348           4 :           vlib_increment_combined_counter
    1349           2 :             (((next1 ==
    1350             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1351           2 :               &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
    1352             :              1, vlib_buffer_length_in_chain (vm, b1));
    1353             : 
    1354           4 :           vlib_increment_combined_counter
    1355           2 :             (((next2 ==
    1356             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1357           2 :               &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
    1358             :              1, vlib_buffer_length_in_chain (vm, b2));
    1359             : 
    1360           4 :           vlib_increment_combined_counter
    1361           2 :             (((next3 ==
    1362             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1363           2 :               &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
    1364             :              1, vlib_buffer_length_in_chain (vm, b3));
    1365             : 
    1366           2 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    1367             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    1368             :                                            next0, next1, next2, next3);
    1369             :         }
    1370             : 
    1371             :       /* Single loop for potentially the last three packets */
    1372          33 :       while (n_left_from > 0 && n_left_to_next > 0)
    1373             :         {
    1374             :           u32 bi0;
    1375             :           vlib_buffer_t *b0;
    1376             :           ip6_header_t *ip0;
    1377             :           ip6_sr_header_t *sr0;
    1378          28 :           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    1379             :           ip6_sr_localsid_t *ls0;
    1380             : 
    1381          28 :           bi0 = from[0];
    1382          28 :           to_next[0] = bi0;
    1383          28 :           from += 1;
    1384          28 :           to_next += 1;
    1385          28 :           n_left_from -= 1;
    1386          28 :           n_left_to_next -= 1;
    1387             : 
    1388          28 :           b0 = vlib_get_buffer (vm, bi0);
    1389          28 :           ip0 = vlib_buffer_get_current (b0);
    1390             : 
    1391             :           /* Lookup the SR End behavior based on IP DA (adj) */
    1392          28 :           ls0 =
    1393          28 :             pool_elt_at_index (sm->localsids,
    1394             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1395             : 
    1396             :           /* Find SRH as well as previous header */
    1397             :           sr0 =
    1398          28 :             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, NULL);
    1399             : 
    1400             :           /* SRH processing and End variants */
    1401          28 :           end_decaps_srh_processing (node, b0, ip0, sr0, ls0, &next0);
    1402             : 
    1403          28 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1404             :             {
    1405             :               sr_localsid_trace_t *tr =
    1406          28 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1407          28 :               tr->num_segments = 0;
    1408          28 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    1409             :                            sizeof (tr->localsid.as_u8));
    1410          28 :               tr->behavior = ls0->behavior;
    1411          28 :               if (ip0 == vlib_buffer_get_current (b0))
    1412             :                 {
    1413           0 :                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
    1414           0 :                       && sr0->type == ROUTING_HEADER_TYPE_SR)
    1415             :                     {
    1416           0 :                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
    1417           0 :                       tr->num_segments =
    1418           0 :                         sr0->length * 8 / sizeof (ip6_address_t);
    1419           0 :                       tr->segments_left = sr0->segments_left;
    1420             :                     }
    1421             :                 }
    1422             :               else
    1423          28 :                 tr->num_segments = 0xFF;
    1424             :             }
    1425             : 
    1426             :           /* Increase the counters */
    1427          56 :           vlib_increment_combined_counter
    1428          28 :             (((next0 ==
    1429             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1430          28 :               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
    1431             :              1, vlib_buffer_length_in_chain (vm, b0));
    1432             : 
    1433          28 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    1434             :                                            n_left_to_next, bi0, next0);
    1435             :         }
    1436           5 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1437             :     }
    1438           5 :   return from_frame->n_vectors;
    1439             : }
    1440             : 
    1441             : /* *INDENT-OFF* */
    1442      178120 : VLIB_REGISTER_NODE (sr_localsid_d_node) = {
    1443             :   .function = sr_localsid_d_fn,
    1444             :   .name = "sr-localsid-d",
    1445             :   .vector_size = sizeof (u32),
    1446             :   .format_trace = format_sr_localsid_trace,
    1447             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1448             :   .n_errors = SR_LOCALSID_N_ERROR,
    1449             :   .error_strings = sr_localsid_error_strings,
    1450             :   .n_next_nodes = SR_LOCALSID_N_NEXT,
    1451             :   .next_nodes = {
    1452             : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
    1453             :     foreach_sr_localsid_next
    1454             : #undef _
    1455             :   },
    1456             : };
    1457             : /* *INDENT-ON* */
    1458             : 
    1459             : /**
    1460             :  * @brief SR LocalSID graph node. Supports all default SR Endpoint without decaps
    1461             :  */
    1462             : static uword
    1463           4 : sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1464             :                 vlib_frame_t * from_frame)
    1465             : {
    1466             :   u32 n_left_from, next_index, *from, *to_next;
    1467           4 :   ip6_sr_main_t *sm = &sr_main;
    1468           4 :   from = vlib_frame_vector_args (from_frame);
    1469           4 :   n_left_from = from_frame->n_vectors;
    1470           4 :   next_index = node->cached_next_index;
    1471           4 :   u32 thread_index = vm->thread_index;
    1472             : 
    1473           8 :   while (n_left_from > 0)
    1474             :     {
    1475             :       u32 n_left_to_next;
    1476           4 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1477             : 
    1478             :       /* Quad - Loop */
    1479           5 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    1480             :         {
    1481             :           u32 bi0, bi1, bi2, bi3;
    1482             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    1483             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    1484             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    1485             :           ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
    1486             :           u32 next0, next1, next2, next3;
    1487           1 :           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    1488             :           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
    1489             : 
    1490             :           /* Prefetch next iteration. */
    1491             :           {
    1492             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    1493             : 
    1494           1 :             p4 = vlib_get_buffer (vm, from[4]);
    1495           1 :             p5 = vlib_get_buffer (vm, from[5]);
    1496           1 :             p6 = vlib_get_buffer (vm, from[6]);
    1497           1 :             p7 = vlib_get_buffer (vm, from[7]);
    1498             : 
    1499             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    1500           1 :             vlib_prefetch_buffer_header (p4, LOAD);
    1501           1 :             vlib_prefetch_buffer_header (p5, LOAD);
    1502           1 :             vlib_prefetch_buffer_header (p6, LOAD);
    1503           1 :             vlib_prefetch_buffer_header (p7, LOAD);
    1504             : 
    1505           1 :             clib_prefetch_store (p4->data);
    1506           1 :             clib_prefetch_store (p5->data);
    1507           1 :             clib_prefetch_store (p6->data);
    1508           1 :             clib_prefetch_store (p7->data);
    1509             :           }
    1510             : 
    1511           1 :           to_next[0] = bi0 = from[0];
    1512           1 :           to_next[1] = bi1 = from[1];
    1513           1 :           to_next[2] = bi2 = from[2];
    1514           1 :           to_next[3] = bi3 = from[3];
    1515           1 :           from += 4;
    1516           1 :           to_next += 4;
    1517           1 :           n_left_from -= 4;
    1518           1 :           n_left_to_next -= 4;
    1519             : 
    1520           1 :           b0 = vlib_get_buffer (vm, bi0);
    1521           1 :           b1 = vlib_get_buffer (vm, bi1);
    1522           1 :           b2 = vlib_get_buffer (vm, bi2);
    1523           1 :           b3 = vlib_get_buffer (vm, bi3);
    1524             : 
    1525           1 :           ip0 = vlib_buffer_get_current (b0);
    1526           1 :           ip1 = vlib_buffer_get_current (b1);
    1527           1 :           ip2 = vlib_buffer_get_current (b2);
    1528           1 :           ip3 = vlib_buffer_get_current (b3);
    1529             : 
    1530             :           sr0 =
    1531           1 :             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
    1532             :           sr1 =
    1533           1 :             ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
    1534             :           sr2 =
    1535           1 :             ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
    1536             :           sr3 =
    1537           1 :             ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
    1538             : 
    1539           1 :           ls0 =
    1540           1 :             pool_elt_at_index (sm->localsids,
    1541             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1542           1 :           ls1 =
    1543           1 :             pool_elt_at_index (sm->localsids,
    1544             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    1545           1 :           ls2 =
    1546           1 :             pool_elt_at_index (sm->localsids,
    1547             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    1548           1 :           ls3 =
    1549           1 :             pool_elt_at_index (sm->localsids,
    1550             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    1551             : 
    1552           1 :           end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
    1553             :                               prev0);
    1554           1 :           end_srh_processing (node, b1, ip1, sr1, ls1, &next1, ls1->end_psp,
    1555             :                               prev1);
    1556           1 :           end_srh_processing (node, b2, ip2, sr2, ls2, &next2, ls2->end_psp,
    1557             :                               prev2);
    1558           1 :           end_srh_processing (node, b3, ip3, sr3, ls3, &next3, ls3->end_psp,
    1559             :                               prev3);
    1560             : 
    1561           1 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1562             :             {
    1563             :               sr_localsid_trace_t *tr =
    1564           1 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1565           1 :               tr->num_segments = 0;
    1566           1 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    1567             :                            sizeof (tr->localsid.as_u8));
    1568           1 :               tr->behavior = ls0->behavior;
    1569           1 :               if (ip0 == vlib_buffer_get_current (b0))
    1570             :                 {
    1571           1 :                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
    1572           1 :                       && sr0->type == ROUTING_HEADER_TYPE_SR)
    1573             :                     {
    1574           1 :                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
    1575           1 :                       tr->num_segments =
    1576           1 :                         sr0->length * 8 / sizeof (ip6_address_t);
    1577           1 :                       tr->segments_left = sr0->segments_left;
    1578             :                     }
    1579             :                 }
    1580             :               else
    1581           0 :                 tr->num_segments = 0xFF;
    1582             :             }
    1583             : 
    1584           1 :           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    1585             :             {
    1586             :               sr_localsid_trace_t *tr =
    1587           1 :                 vlib_add_trace (vm, node, b1, sizeof (*tr));
    1588           1 :               tr->num_segments = 0;
    1589           1 :               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
    1590             :                            sizeof (tr->localsid.as_u8));
    1591           1 :               tr->behavior = ls1->behavior;
    1592           1 :               if (ip1 == vlib_buffer_get_current (b1))
    1593             :                 {
    1594           1 :                   if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
    1595           1 :                       && sr1->type == ROUTING_HEADER_TYPE_SR)
    1596             :                     {
    1597           1 :                       clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
    1598           1 :                       tr->num_segments =
    1599           1 :                         sr1->length * 8 / sizeof (ip6_address_t);
    1600           1 :                       tr->segments_left = sr1->segments_left;
    1601             :                     }
    1602             :                 }
    1603             :               else
    1604           0 :                 tr->num_segments = 0xFF;
    1605             :             }
    1606             : 
    1607           1 :           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    1608             :             {
    1609             :               sr_localsid_trace_t *tr =
    1610           1 :                 vlib_add_trace (vm, node, b2, sizeof (*tr));
    1611           1 :               tr->num_segments = 0;
    1612           1 :               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
    1613             :                            sizeof (tr->localsid.as_u8));
    1614           1 :               tr->behavior = ls2->behavior;
    1615           1 :               if (ip2 == vlib_buffer_get_current (b2))
    1616             :                 {
    1617           1 :                   if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
    1618           1 :                       && sr2->type == ROUTING_HEADER_TYPE_SR)
    1619             :                     {
    1620           1 :                       clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
    1621           1 :                       tr->num_segments =
    1622           1 :                         sr2->length * 8 / sizeof (ip6_address_t);
    1623           1 :                       tr->segments_left = sr2->segments_left;
    1624             :                     }
    1625             :                 }
    1626             :               else
    1627           0 :                 tr->num_segments = 0xFF;
    1628             :             }
    1629             : 
    1630           1 :           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    1631             :             {
    1632             :               sr_localsid_trace_t *tr =
    1633           1 :                 vlib_add_trace (vm, node, b3, sizeof (*tr));
    1634           1 :               tr->num_segments = 0;
    1635           1 :               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
    1636             :                            sizeof (tr->localsid.as_u8));
    1637           1 :               tr->behavior = ls3->behavior;
    1638           1 :               if (ip3 == vlib_buffer_get_current (b3))
    1639             :                 {
    1640           1 :                   if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
    1641           1 :                       && sr3->type == ROUTING_HEADER_TYPE_SR)
    1642             :                     {
    1643           1 :                       clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
    1644           1 :                       tr->num_segments =
    1645           1 :                         sr3->length * 8 / sizeof (ip6_address_t);
    1646           1 :                       tr->segments_left = sr3->segments_left;
    1647             :                     }
    1648             :                 }
    1649             :               else
    1650           0 :                 tr->num_segments = 0xFF;
    1651             :             }
    1652             : 
    1653           2 :           vlib_increment_combined_counter
    1654           1 :             (((next0 ==
    1655             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1656           1 :               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
    1657             :              1, vlib_buffer_length_in_chain (vm, b0));
    1658             : 
    1659           2 :           vlib_increment_combined_counter
    1660           1 :             (((next1 ==
    1661             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1662           1 :               &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
    1663             :              1, vlib_buffer_length_in_chain (vm, b1));
    1664             : 
    1665           2 :           vlib_increment_combined_counter
    1666           1 :             (((next2 ==
    1667             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1668           1 :               &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
    1669             :              1, vlib_buffer_length_in_chain (vm, b2));
    1670             : 
    1671           2 :           vlib_increment_combined_counter
    1672           1 :             (((next3 ==
    1673             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1674           1 :               &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
    1675             :              1, vlib_buffer_length_in_chain (vm, b3));
    1676             : 
    1677           1 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    1678             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    1679             :                                            next0, next1, next2, next3);
    1680             :         }
    1681             : 
    1682             :       /* Single loop for potentially the last three packets */
    1683          27 :       while (n_left_from > 0 && n_left_to_next > 0)
    1684             :         {
    1685             :           u32 bi0;
    1686             :           vlib_buffer_t *b0;
    1687          23 :           ip6_header_t *ip0 = 0;
    1688             :           ip6_ext_header_t *prev0;
    1689             :           ip6_sr_header_t *sr0;
    1690          23 :           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    1691             :           ip6_sr_localsid_t *ls0;
    1692             : 
    1693          23 :           bi0 = from[0];
    1694          23 :           to_next[0] = bi0;
    1695          23 :           from += 1;
    1696          23 :           to_next += 1;
    1697          23 :           n_left_from -= 1;
    1698          23 :           n_left_to_next -= 1;
    1699             : 
    1700          23 :           b0 = vlib_get_buffer (vm, bi0);
    1701          23 :           ip0 = vlib_buffer_get_current (b0);
    1702             :           sr0 =
    1703          23 :             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
    1704             : 
    1705             :           /* Lookup the SR End behavior based on IP DA (adj) */
    1706          23 :           ls0 =
    1707          23 :             pool_elt_at_index (sm->localsids,
    1708             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1709             : 
    1710             :           /* SRH processing */
    1711          23 :           end_srh_processing (node, b0, ip0, sr0, ls0, &next0, ls0->end_psp,
    1712             :                               prev0);
    1713             : 
    1714          23 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1715             :             {
    1716             :               sr_localsid_trace_t *tr =
    1717          23 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1718          23 :               tr->num_segments = 0;
    1719          23 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    1720             :                            sizeof (tr->localsid.as_u8));
    1721          23 :               tr->behavior = ls0->behavior;
    1722          23 :               if (ip0 == vlib_buffer_get_current (b0))
    1723             :                 {
    1724          17 :                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
    1725          14 :                       && sr0->type == ROUTING_HEADER_TYPE_SR)
    1726             :                     {
    1727          14 :                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
    1728          14 :                       tr->num_segments =
    1729          14 :                         sr0->length * 8 / sizeof (ip6_address_t);
    1730          14 :                       tr->segments_left = sr0->segments_left;
    1731             :                     }
    1732             :                 }
    1733             :               else
    1734           6 :                 tr->num_segments = 0xFF;
    1735             :             }
    1736             : 
    1737          46 :           vlib_increment_combined_counter
    1738          23 :             (((next0 ==
    1739             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1740          23 :               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
    1741             :              1, vlib_buffer_length_in_chain (vm, b0));
    1742             : 
    1743          23 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    1744             :                                            n_left_to_next, bi0, next0);
    1745             :         }
    1746           4 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1747             :     }
    1748           4 :   return from_frame->n_vectors;
    1749             : }
    1750             : 
    1751             : /* *INDENT-OFF* */
    1752      178120 : VLIB_REGISTER_NODE (sr_localsid_node) = {
    1753             :   .function = sr_localsid_fn,
    1754             :   .name = "sr-localsid",
    1755             :   .vector_size = sizeof (u32),
    1756             :   .format_trace = format_sr_localsid_trace,
    1757             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1758             :   .n_errors = SR_LOCALSID_N_ERROR,
    1759             :   .error_strings = sr_localsid_error_strings,
    1760             :   .n_next_nodes = SR_LOCALSID_N_NEXT,
    1761             :   .next_nodes = {
    1762             : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
    1763             :     foreach_sr_localsid_next
    1764             : #undef _
    1765             :   },
    1766             : };
    1767             : /* *INDENT-ON* */
    1768             : 
    1769             : /**
    1770             :  * @brief SR LocalSID uN graph node. Supports all default SR Endpoint without decaps
    1771             :  */
    1772             : static uword
    1773           2 : sr_localsid_un_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1774             :                    vlib_frame_t * from_frame)
    1775             : {
    1776             :   u32 n_left_from, next_index, *from, *to_next;
    1777           2 :   ip6_sr_main_t *sm = &sr_main;
    1778           2 :   from = vlib_frame_vector_args (from_frame);
    1779           2 :   n_left_from = from_frame->n_vectors;
    1780           2 :   next_index = node->cached_next_index;
    1781           2 :   u32 thread_index = vm->thread_index;
    1782             : 
    1783           4 :   while (n_left_from > 0)
    1784             :     {
    1785             :       u32 n_left_to_next;
    1786           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1787             : 
    1788             :       /* Quad - Loop */
    1789           2 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    1790             :         {
    1791             :           u32 bi0, bi1, bi2, bi3;
    1792             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    1793             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    1794             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    1795             :           ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
    1796             :           u32 next0, next1, next2, next3;
    1797           0 :           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    1798             :           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
    1799             : 
    1800             :           /* Prefetch next iteration. */
    1801             :           {
    1802             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    1803             : 
    1804           0 :             p4 = vlib_get_buffer (vm, from[4]);
    1805           0 :             p5 = vlib_get_buffer (vm, from[5]);
    1806           0 :             p6 = vlib_get_buffer (vm, from[6]);
    1807           0 :             p7 = vlib_get_buffer (vm, from[7]);
    1808             : 
    1809             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    1810           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    1811           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    1812           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    1813           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    1814             : 
    1815           0 :             clib_prefetch_store (p4->data);
    1816           0 :             clib_prefetch_store (p5->data);
    1817           0 :             clib_prefetch_store (p6->data);
    1818           0 :             clib_prefetch_store (p7->data);
    1819             :           }
    1820             : 
    1821           0 :           to_next[0] = bi0 = from[0];
    1822           0 :           to_next[1] = bi1 = from[1];
    1823           0 :           to_next[2] = bi2 = from[2];
    1824           0 :           to_next[3] = bi3 = from[3];
    1825           0 :           from += 4;
    1826           0 :           to_next += 4;
    1827           0 :           n_left_from -= 4;
    1828           0 :           n_left_to_next -= 4;
    1829             : 
    1830           0 :           b0 = vlib_get_buffer (vm, bi0);
    1831           0 :           b1 = vlib_get_buffer (vm, bi1);
    1832           0 :           b2 = vlib_get_buffer (vm, bi2);
    1833           0 :           b3 = vlib_get_buffer (vm, bi3);
    1834             : 
    1835           0 :           ip0 = vlib_buffer_get_current (b0);
    1836           0 :           ip1 = vlib_buffer_get_current (b1);
    1837           0 :           ip2 = vlib_buffer_get_current (b2);
    1838           0 :           ip3 = vlib_buffer_get_current (b3);
    1839             : 
    1840             :           sr0 =
    1841           0 :             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
    1842             :           sr1 =
    1843           0 :             ip6_ext_header_find (vm, b1, ip1, IP_PROTOCOL_IPV6_ROUTE, &prev1);
    1844             :           sr2 =
    1845           0 :             ip6_ext_header_find (vm, b2, ip2, IP_PROTOCOL_IPV6_ROUTE, &prev2);
    1846             :           sr3 =
    1847           0 :             ip6_ext_header_find (vm, b3, ip3, IP_PROTOCOL_IPV6_ROUTE, &prev3);
    1848             : 
    1849           0 :           ls0 =
    1850           0 :             pool_elt_at_index (sm->localsids,
    1851             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1852           0 :           ls1 =
    1853           0 :             pool_elt_at_index (sm->localsids,
    1854             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    1855           0 :           ls2 =
    1856           0 :             pool_elt_at_index (sm->localsids,
    1857             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    1858           0 :           ls3 =
    1859           0 :             pool_elt_at_index (sm->localsids,
    1860             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    1861             : 
    1862           0 :           end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
    1863           0 :                                  ls0->end_psp, prev0);
    1864           0 :           end_un_srh_processing (node, b1, ip1, sr1, ls1, &next1,
    1865           0 :                                  ls1->end_psp, prev1);
    1866           0 :           end_un_srh_processing (node, b2, ip2, sr2, ls2, &next2,
    1867           0 :                                  ls2->end_psp, prev2);
    1868           0 :           end_un_srh_processing (node, b3, ip3, sr3, ls3, &next3,
    1869           0 :                                  ls3->end_psp, prev3);
    1870             : 
    1871           0 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1872             :             {
    1873             :               sr_localsid_trace_t *tr =
    1874           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1875           0 :               tr->num_segments = 0;
    1876           0 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    1877             :                            sizeof (tr->localsid.as_u8));
    1878           0 :               tr->behavior = ls0->behavior;
    1879           0 :               if (ip0 == vlib_buffer_get_current (b0))
    1880             :                 {
    1881           0 :                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
    1882           0 :                       && sr0->type == ROUTING_HEADER_TYPE_SR)
    1883             :                     {
    1884           0 :                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
    1885           0 :                       tr->num_segments =
    1886           0 :                         sr0->length * 8 / sizeof (ip6_address_t);
    1887           0 :                       tr->segments_left = sr0->segments_left;
    1888             :                     }
    1889             :                 }
    1890             :               else
    1891           0 :                 tr->num_segments = 0xFF;
    1892             :             }
    1893             : 
    1894           0 :           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    1895             :             {
    1896             :               sr_localsid_trace_t *tr =
    1897           0 :                 vlib_add_trace (vm, node, b1, sizeof (*tr));
    1898           0 :               tr->num_segments = 0;
    1899           0 :               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
    1900             :                            sizeof (tr->localsid.as_u8));
    1901           0 :               tr->behavior = ls1->behavior;
    1902           0 :               if (ip1 == vlib_buffer_get_current (b1))
    1903             :                 {
    1904           0 :                   if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE
    1905           0 :                       && sr1->type == ROUTING_HEADER_TYPE_SR)
    1906             :                     {
    1907           0 :                       clib_memcpy (tr->sr, sr1->segments, sr1->length * 8);
    1908           0 :                       tr->num_segments =
    1909           0 :                         sr1->length * 8 / sizeof (ip6_address_t);
    1910           0 :                       tr->segments_left = sr1->segments_left;
    1911             :                     }
    1912             :                 }
    1913             :               else
    1914           0 :                 tr->num_segments = 0xFF;
    1915             :             }
    1916             : 
    1917           0 :           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    1918             :             {
    1919             :               sr_localsid_trace_t *tr =
    1920           0 :                 vlib_add_trace (vm, node, b2, sizeof (*tr));
    1921           0 :               tr->num_segments = 0;
    1922           0 :               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
    1923             :                            sizeof (tr->localsid.as_u8));
    1924           0 :               tr->behavior = ls2->behavior;
    1925           0 :               if (ip2 == vlib_buffer_get_current (b2))
    1926             :                 {
    1927           0 :                   if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE
    1928           0 :                       && sr2->type == ROUTING_HEADER_TYPE_SR)
    1929             :                     {
    1930           0 :                       clib_memcpy (tr->sr, sr2->segments, sr2->length * 8);
    1931           0 :                       tr->num_segments =
    1932           0 :                         sr2->length * 8 / sizeof (ip6_address_t);
    1933           0 :                       tr->segments_left = sr2->segments_left;
    1934             :                     }
    1935             :                 }
    1936             :               else
    1937           0 :                 tr->num_segments = 0xFF;
    1938             :             }
    1939             : 
    1940           0 :           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    1941             :             {
    1942             :               sr_localsid_trace_t *tr =
    1943           0 :                 vlib_add_trace (vm, node, b3, sizeof (*tr));
    1944           0 :               tr->num_segments = 0;
    1945           0 :               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
    1946             :                            sizeof (tr->localsid.as_u8));
    1947           0 :               tr->behavior = ls3->behavior;
    1948           0 :               if (ip3 == vlib_buffer_get_current (b3))
    1949             :                 {
    1950           0 :                   if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE
    1951           0 :                       && sr3->type == ROUTING_HEADER_TYPE_SR)
    1952             :                     {
    1953           0 :                       clib_memcpy (tr->sr, sr3->segments, sr3->length * 8);
    1954           0 :                       tr->num_segments =
    1955           0 :                         sr3->length * 8 / sizeof (ip6_address_t);
    1956           0 :                       tr->segments_left = sr3->segments_left;
    1957             :                     }
    1958             :                 }
    1959             :               else
    1960           0 :                 tr->num_segments = 0xFF;
    1961             :             }
    1962             : 
    1963           0 :           vlib_increment_combined_counter
    1964           0 :             (((next0 ==
    1965             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1966           0 :               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
    1967             :              1, vlib_buffer_length_in_chain (vm, b0));
    1968             : 
    1969           0 :           vlib_increment_combined_counter
    1970           0 :             (((next1 ==
    1971             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1972           0 :               &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids,
    1973             :              1, vlib_buffer_length_in_chain (vm, b1));
    1974             : 
    1975           0 :           vlib_increment_combined_counter
    1976           0 :             (((next2 ==
    1977             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1978           0 :               &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids,
    1979             :              1, vlib_buffer_length_in_chain (vm, b2));
    1980             : 
    1981           0 :           vlib_increment_combined_counter
    1982           0 :             (((next3 ==
    1983             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    1984           0 :               &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids,
    1985             :              1, vlib_buffer_length_in_chain (vm, b3));
    1986             : 
    1987           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    1988             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    1989             :                                            next0, next1, next2, next3);
    1990             :         }
    1991             : 
    1992             :       /* Single loop for potentially the last three packets */
    1993           6 :       while (n_left_from > 0 && n_left_to_next > 0)
    1994             :         {
    1995             :           u32 bi0;
    1996             :           vlib_buffer_t *b0;
    1997           4 :           ip6_header_t *ip0 = 0;
    1998             :           ip6_ext_header_t *prev0;
    1999             :           ip6_sr_header_t *sr0;
    2000           4 :           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    2001             :           ip6_sr_localsid_t *ls0;
    2002             : 
    2003           4 :           bi0 = from[0];
    2004           4 :           to_next[0] = bi0;
    2005           4 :           from += 1;
    2006           4 :           to_next += 1;
    2007           4 :           n_left_from -= 1;
    2008           4 :           n_left_to_next -= 1;
    2009             : 
    2010           4 :           b0 = vlib_get_buffer (vm, bi0);
    2011           4 :           ip0 = vlib_buffer_get_current (b0);
    2012             :           sr0 =
    2013           4 :             ip6_ext_header_find (vm, b0, ip0, IP_PROTOCOL_IPV6_ROUTE, &prev0);
    2014             : 
    2015             :           /* Lookup the SR End behavior based on IP DA (adj) */
    2016           4 :           ls0 =
    2017           4 :             pool_elt_at_index (sm->localsids,
    2018             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2019             : 
    2020             :           /* SRH processing */
    2021           4 :           end_un_srh_processing (node, b0, ip0, sr0, ls0, &next0,
    2022           4 :                                  ls0->end_psp, prev0);
    2023             : 
    2024           4 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2025             :             {
    2026             :               sr_localsid_trace_t *tr =
    2027           4 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    2028           4 :               tr->num_segments = 0;
    2029           4 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    2030             :                            sizeof (tr->localsid.as_u8));
    2031           4 :               tr->behavior = ls0->behavior;
    2032           4 :               if (ip0 == vlib_buffer_get_current (b0))
    2033             :                 {
    2034           4 :                   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE
    2035           2 :                       && sr0->type == ROUTING_HEADER_TYPE_SR)
    2036             :                     {
    2037           2 :                       clib_memcpy (tr->sr, sr0->segments, sr0->length * 8);
    2038           2 :                       tr->num_segments =
    2039           2 :                         sr0->length * 8 / sizeof (ip6_address_t);
    2040           2 :                       tr->segments_left = sr0->segments_left;
    2041             :                     }
    2042             :                 }
    2043             :               else
    2044           0 :                 tr->num_segments = 0xFF;
    2045             :             }
    2046             : 
    2047           8 :           vlib_increment_combined_counter
    2048           4 :             (((next0 ==
    2049             :                SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) :
    2050           4 :               &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids,
    2051             :              1, vlib_buffer_length_in_chain (vm, b0));
    2052             : 
    2053           4 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    2054             :                                            n_left_to_next, bi0, next0);
    2055             :         }
    2056           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    2057             :     }
    2058           2 :   return from_frame->n_vectors;
    2059             : }
    2060             : 
    2061             : /* *INDENT-OFF* */
    2062      178120 : VLIB_REGISTER_NODE (sr_localsid_un_node) = {
    2063             :   .function = sr_localsid_un_fn,
    2064             :   .name = "sr-localsid-un",
    2065             :   .vector_size = sizeof (u32),
    2066             :   .format_trace = format_sr_localsid_trace,
    2067             :   .type = VLIB_NODE_TYPE_INTERNAL,
    2068             :   .n_errors = SR_LOCALSID_N_ERROR,
    2069             :   .error_strings = sr_localsid_error_strings,
    2070             :   .n_next_nodes = SR_LOCALSID_N_NEXT,
    2071             :   .next_nodes = {
    2072             : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
    2073             :     foreach_sr_localsid_next
    2074             : #undef _
    2075             :   },
    2076             : };
    2077             : /* *INDENT-ON* */
    2078             : 
    2079             : static uword
    2080           2 : sr_localsid_un_perf_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    2081             :                         vlib_frame_t * from_frame)
    2082             : {
    2083             :   u32 n_left_from, next_index, *from, *to_next;
    2084           2 :   ip6_sr_main_t *sm = &sr_main;
    2085           2 :   from = vlib_frame_vector_args (from_frame);
    2086           2 :   n_left_from = from_frame->n_vectors;
    2087           2 :   next_index = node->cached_next_index;
    2088           2 :   u32 thread_index = vm->thread_index;
    2089             : 
    2090           4 :   while (n_left_from > 0)
    2091             :     {
    2092             :       u32 n_left_to_next;
    2093           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    2094             : 
    2095             :       /* Quad - Loop */
    2096           2 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    2097             :         {
    2098             :           u32 bi0, bi1, bi2, bi3;
    2099             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    2100             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    2101             :           u32 next0, next1, next2, next3;
    2102           0 :           next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    2103             :           ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
    2104             : 
    2105             :           /* Prefetch next iteration. */
    2106             :           {
    2107             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    2108             : 
    2109           0 :             p4 = vlib_get_buffer (vm, from[4]);
    2110           0 :             p5 = vlib_get_buffer (vm, from[5]);
    2111           0 :             p6 = vlib_get_buffer (vm, from[6]);
    2112           0 :             p7 = vlib_get_buffer (vm, from[7]);
    2113             : 
    2114             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    2115           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    2116           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    2117           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    2118           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    2119             : 
    2120           0 :             clib_prefetch_store (p4->data);
    2121           0 :             clib_prefetch_store (p5->data);
    2122           0 :             clib_prefetch_store (p6->data);
    2123           0 :             clib_prefetch_store (p7->data);
    2124             :           }
    2125             : 
    2126           0 :           to_next[0] = bi0 = from[0];
    2127           0 :           to_next[1] = bi1 = from[1];
    2128           0 :           to_next[2] = bi2 = from[2];
    2129           0 :           to_next[3] = bi3 = from[3];
    2130           0 :           from += 4;
    2131           0 :           to_next += 4;
    2132           0 :           n_left_from -= 4;
    2133           0 :           n_left_to_next -= 4;
    2134             : 
    2135           0 :           b0 = vlib_get_buffer (vm, bi0);
    2136           0 :           b1 = vlib_get_buffer (vm, bi1);
    2137           0 :           b2 = vlib_get_buffer (vm, bi2);
    2138           0 :           b3 = vlib_get_buffer (vm, bi3);
    2139             : 
    2140           0 :           ip0 = vlib_buffer_get_current (b0);
    2141           0 :           ip1 = vlib_buffer_get_current (b1);
    2142           0 :           ip2 = vlib_buffer_get_current (b2);
    2143           0 :           ip3 = vlib_buffer_get_current (b3);
    2144             : 
    2145           0 :           ls0 =
    2146           0 :             pool_elt_at_index (sm->localsids,
    2147             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2148           0 :           ls1 =
    2149           0 :             pool_elt_at_index (sm->localsids,
    2150             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    2151           0 :           ls2 =
    2152           0 :             pool_elt_at_index (sm->localsids,
    2153             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    2154           0 :           ls3 =
    2155           0 :             pool_elt_at_index (sm->localsids,
    2156             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    2157             : 
    2158           0 :           end_un_processing (ip0, ls0);
    2159           0 :           end_un_processing (ip1, ls1);
    2160           0 :           end_un_processing (ip2, ls2);
    2161           0 :           end_un_processing (ip3, ls3);
    2162             : 
    2163           0 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2164             :             {
    2165             :               sr_localsid_trace_t *tr =
    2166           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    2167           0 :               tr->num_segments = 0;
    2168           0 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    2169             :                            sizeof (tr->localsid.as_u8));
    2170           0 :               tr->behavior = ls0->behavior;
    2171             :             }
    2172             : 
    2173           0 :           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    2174             :             {
    2175             :               sr_localsid_trace_t *tr =
    2176           0 :                 vlib_add_trace (vm, node, b1, sizeof (*tr));
    2177           0 :               tr->num_segments = 0;
    2178           0 :               clib_memcpy (tr->localsid.as_u8, ls1->localsid.as_u8,
    2179             :                            sizeof (tr->localsid.as_u8));
    2180           0 :               tr->behavior = ls1->behavior;
    2181             :             }
    2182             : 
    2183           0 :           if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    2184             :             {
    2185             :               sr_localsid_trace_t *tr =
    2186           0 :                 vlib_add_trace (vm, node, b2, sizeof (*tr));
    2187           0 :               tr->num_segments = 0;
    2188           0 :               clib_memcpy (tr->localsid.as_u8, ls2->localsid.as_u8,
    2189             :                            sizeof (tr->localsid.as_u8));
    2190           0 :               tr->behavior = ls2->behavior;
    2191             :             }
    2192             : 
    2193           0 :           if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    2194             :             {
    2195             :               sr_localsid_trace_t *tr =
    2196           0 :                 vlib_add_trace (vm, node, b3, sizeof (*tr));
    2197           0 :               tr->num_segments = 0;
    2198           0 :               clib_memcpy (tr->localsid.as_u8, ls3->localsid.as_u8,
    2199             :                            sizeof (tr->localsid.as_u8));
    2200           0 :               tr->behavior = ls3->behavior;
    2201             :             }
    2202             : 
    2203           0 :           vlib_increment_combined_counter
    2204           0 :             (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
    2205             :              1, vlib_buffer_length_in_chain (vm, b0));
    2206             : 
    2207           0 :           vlib_increment_combined_counter
    2208           0 :             (&(sm->sr_ls_valid_counters), thread_index, ls1 - sm->localsids,
    2209             :              1, vlib_buffer_length_in_chain (vm, b1));
    2210             : 
    2211           0 :           vlib_increment_combined_counter
    2212           0 :             (&(sm->sr_ls_valid_counters), thread_index, ls2 - sm->localsids,
    2213             :              1, vlib_buffer_length_in_chain (vm, b2));
    2214             : 
    2215           0 :           vlib_increment_combined_counter
    2216           0 :             (&(sm->sr_ls_valid_counters), thread_index, ls3 - sm->localsids,
    2217             :              1, vlib_buffer_length_in_chain (vm, b3));
    2218             : 
    2219           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    2220             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    2221             :                                            next0, next1, next2, next3);
    2222             :         }
    2223             : 
    2224             :       /* Single loop for potentially the last three packets */
    2225           6 :       while (n_left_from > 0 && n_left_to_next > 0)
    2226             :         {
    2227             :           u32 bi0;
    2228             :           vlib_buffer_t *b0;
    2229           4 :           ip6_header_t *ip0 = 0;
    2230           4 :           u32 next0 = SR_LOCALSID_NEXT_IP6_LOOKUP;
    2231             :           ip6_sr_localsid_t *ls0;
    2232             : 
    2233           4 :           bi0 = from[0];
    2234           4 :           to_next[0] = bi0;
    2235           4 :           from += 1;
    2236           4 :           to_next += 1;
    2237           4 :           n_left_from -= 1;
    2238           4 :           n_left_to_next -= 1;
    2239             : 
    2240           4 :           b0 = vlib_get_buffer (vm, bi0);
    2241           4 :           ip0 = vlib_buffer_get_current (b0);
    2242             : 
    2243             :           /* Lookup the SR End behavior based on IP DA (adj) */
    2244           4 :           ls0 =
    2245           4 :             pool_elt_at_index (sm->localsids,
    2246             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2247             : 
    2248             :           /* SRH processing */
    2249           4 :           end_un_processing (ip0, ls0);
    2250             : 
    2251           4 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2252             :             {
    2253             :               sr_localsid_trace_t *tr =
    2254           4 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    2255           4 :               tr->num_segments = 0;
    2256           4 :               clib_memcpy (tr->localsid.as_u8, ls0->localsid.as_u8,
    2257             :                            sizeof (tr->localsid.as_u8));
    2258           4 :               tr->behavior = ls0->behavior;
    2259             :             }
    2260             : 
    2261           4 :           vlib_increment_combined_counter
    2262           4 :             (&(sm->sr_ls_valid_counters), thread_index, ls0 - sm->localsids,
    2263             :              1, vlib_buffer_length_in_chain (vm, b0));
    2264             : 
    2265           4 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    2266             :                                            n_left_to_next, bi0, next0);
    2267             :         }
    2268           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    2269             :     }
    2270           2 :   return from_frame->n_vectors;
    2271             : }
    2272             : 
    2273             : /* *INDENT-OFF* */
    2274      178120 : VLIB_REGISTER_NODE (sr_localsid_un_perf_node) = {
    2275             :   .function = sr_localsid_un_perf_fn,
    2276             :   .name = "sr-localsid-un-perf",
    2277             :   .vector_size = sizeof (u32),
    2278             :   .format_trace = format_sr_localsid_trace,
    2279             :   .type = VLIB_NODE_TYPE_INTERNAL,
    2280             :   .n_errors = SR_LOCALSID_N_ERROR,
    2281             :   .error_strings = sr_localsid_error_strings,
    2282             :   .n_next_nodes = SR_LOCALSID_N_NEXT,
    2283             :   .next_nodes = {
    2284             : #define _(s,n) [SR_LOCALSID_NEXT_##s] = n,
    2285             :     foreach_sr_localsid_next
    2286             : #undef _
    2287             :   },
    2288             : };
    2289             : /* *INDENT-ON* */
    2290             : 
    2291             : static u8 *
    2292           0 : format_sr_dpo (u8 * s, va_list * args)
    2293             : {
    2294           0 :   index_t index = va_arg (*args, index_t);
    2295           0 :   CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
    2296             : 
    2297           0 :   return (format (s, "SR: localsid_index:[%d]", index));
    2298             : }
    2299             : 
    2300             : const static dpo_vft_t sr_loc_vft = {
    2301             :   .dv_lock = sr_dpo_lock,
    2302             :   .dv_unlock = sr_dpo_unlock,
    2303             :   .dv_format = format_sr_dpo,
    2304             : };
    2305             : 
    2306             : const static char *const sr_loc_ip6_nodes[] = {
    2307             :   "sr-localsid",
    2308             :   NULL,
    2309             : };
    2310             : 
    2311             : const static char *const *const sr_loc_nodes[DPO_PROTO_NUM] = {
    2312             :   [DPO_PROTO_IP6] = sr_loc_ip6_nodes,
    2313             : };
    2314             : 
    2315             : const static char *const sr_loc_d_ip6_nodes[] = {
    2316             :   "sr-localsid-d",
    2317             :   NULL,
    2318             : };
    2319             : 
    2320             : const static char *const *const sr_loc_d_nodes[DPO_PROTO_NUM] = {
    2321             :   [DPO_PROTO_IP6] = sr_loc_d_ip6_nodes,
    2322             : };
    2323             : 
    2324             : const static char *const sr_loc_un_ip6_nodes[] = {
    2325             :   "sr-localsid-un",
    2326             :   NULL,
    2327             : };
    2328             : 
    2329             : const static char *const *const sr_loc_un_nodes[DPO_PROTO_NUM] = {
    2330             :   [DPO_PROTO_IP6] = sr_loc_un_ip6_nodes,
    2331             : };
    2332             : 
    2333             : const static char *const sr_loc_un_perf_ip6_nodes[] = {
    2334             :   "sr-localsid-un-perf",
    2335             :   NULL,
    2336             : };
    2337             : 
    2338             : const static char *const *const sr_loc_un_perf_nodes[DPO_PROTO_NUM] = {
    2339             :   [DPO_PROTO_IP6] = sr_loc_un_perf_ip6_nodes,
    2340             : };
    2341             : 
    2342             : /*************************** SR LocalSID plugins ******************************/
    2343             : /**
    2344             :  * @brief SR LocalSID plugin registry
    2345             :  */
    2346             : int
    2347        5031 : sr_localsid_register_function (vlib_main_t * vm, u8 * fn_name,
    2348             :                                u8 * keyword_str, u8 * def_str,
    2349             :                                u8 * params_str, u8 prefix_length,
    2350             :                                dpo_type_t * dpo,
    2351             :                                format_function_t * ls_format,
    2352             :                                unformat_function_t * ls_unformat,
    2353             :                                sr_plugin_callback_t * creation_fn,
    2354             :                                sr_plugin_callback_t * removal_fn)
    2355             : {
    2356        5031 :   ip6_sr_main_t *sm = &sr_main;
    2357             :   uword *p;
    2358             : 
    2359             :   sr_localsid_fn_registration_t *plugin;
    2360             : 
    2361             :   /* Did this function exist? If so update it */
    2362        5031 :   p = hash_get_mem (sm->plugin_functions_by_key, fn_name);
    2363        5031 :   if (p)
    2364             :     {
    2365           0 :       plugin = pool_elt_at_index (sm->plugin_functions, p[0]);
    2366             :     }
    2367             :   /* Else create a new one and set hash key */
    2368             :   else
    2369             :     {
    2370        5031 :       pool_get (sm->plugin_functions, plugin);
    2371       10062 :       hash_set_mem (sm->plugin_functions_by_key, fn_name,
    2372             :                     plugin - sm->plugin_functions);
    2373             :     }
    2374             : 
    2375        5031 :   clib_memset (plugin, 0, sizeof (*plugin));
    2376             : 
    2377        5031 :   plugin->sr_localsid_function_number = (plugin - sm->plugin_functions);
    2378        5031 :   plugin->sr_localsid_function_number += SR_BEHAVIOR_LAST;
    2379        5031 :   plugin->prefix_length = prefix_length;
    2380        5031 :   plugin->ls_format = ls_format;
    2381        5031 :   plugin->ls_unformat = ls_unformat;
    2382        5031 :   plugin->creation = creation_fn;
    2383        5031 :   plugin->removal = removal_fn;
    2384        5031 :   clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
    2385        5031 :   plugin->function_name = format (0, "%s%c", fn_name, 0);
    2386        5031 :   plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
    2387        5031 :   plugin->def_str = format (0, "%s%c", def_str, 0);
    2388        5031 :   plugin->params_str = format (0, "%s%c", params_str, 0);
    2389             : 
    2390        5031 :   return plugin->sr_localsid_function_number;
    2391             : }
    2392             : 
    2393             : /**
    2394             :  * @brief CLI function to 'show' all available SR LocalSID behaviors
    2395             :  */
    2396             : static clib_error_t *
    2397           0 : show_sr_localsid_behaviors_command_fn (vlib_main_t * vm,
    2398             :                                        unformat_input_t * input,
    2399             :                                        vlib_cli_command_t * cmd)
    2400             : {
    2401           0 :   ip6_sr_main_t *sm = &sr_main;
    2402             :   sr_localsid_fn_registration_t *plugin;
    2403           0 :   sr_localsid_fn_registration_t **plugins_vec = 0;
    2404             :   int i;
    2405             : 
    2406           0 :   vlib_cli_output (vm,
    2407             :                    "SR LocalSIDs behaviors:\n-----------------------\n\n");
    2408             : 
    2409             :   /* *INDENT-OFF* */
    2410           0 :   pool_foreach (plugin, sm->plugin_functions)
    2411           0 :     { vec_add1 (plugins_vec, plugin); }
    2412             :   /* *INDENT-ON* */
    2413             : 
    2414             :   /* Print static behaviors */
    2415           0 :   vlib_cli_output (vm, "Default behaviors:\n"
    2416             :                    "\tEnd\t-> Endpoint.\n"
    2417             :                    "\tEnd.X\t-> Endpoint with Layer-3 cross-connect.\n"
    2418             :                    "\t\tParameters: '<iface> <ip6_next_hop>'\n"
    2419             :                    "\tEnd.T\t-> Endpoint with specific IPv6 table lookup.\n"
    2420             :                    "\t\tParameters: '<fib_table>'\n"
    2421             :                    "\tEnd.DX2\t-> Endpoint with decapsulation and Layer-2 cross-connect.\n"
    2422             :                    "\t\tParameters: '<iface>'\n"
    2423             :                    "\tEnd.DX6\t-> Endpoint with decapsulation and IPv6 cross-connect.\n"
    2424             :                    "\t\tParameters: '<iface> <ip6_next_hop>'\n"
    2425             :                    "\tEnd.DX4\t-> Endpoint with decapsulation and IPv4 cross-connect.\n"
    2426             :                    "\t\tParameters: '<iface> <ip4_next_hop>'\n"
    2427             :                    "\tEnd.DT6\t-> Endpoint with decapsulation and specific IPv6 table lookup.\n"
    2428             :                    "\t\tParameters: '<ip6_fib_table>'\n"
    2429             :                    "\tEnd.DT4\t-> Endpoint with decapsulation and specific IPv4 table lookup.\n"
    2430             :                    "\t\tParameters: '<ip4_fib_table>'\n");
    2431           0 :   vlib_cli_output (vm, "Plugin behaviors:\n");
    2432           0 :   for (i = 0; i < vec_len (plugins_vec); i++)
    2433             :     {
    2434           0 :       plugin = plugins_vec[i];
    2435           0 :       vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
    2436             :                        plugin->def_str);
    2437           0 :       vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
    2438             :     }
    2439           0 :   return 0;
    2440             : }
    2441             : 
    2442             : /* *INDENT-OFF* */
    2443      272887 : VLIB_CLI_COMMAND (show_sr_localsid_behaviors_command, static) = {
    2444             :   .path = "show sr localsids behaviors",
    2445             :   .short_help = "show sr localsids behaviors",
    2446             :   .function = show_sr_localsid_behaviors_command_fn,
    2447             : };
    2448             : /* *INDENT-ON* */
    2449             : 
    2450             : /**
    2451             :  * @brief SR LocalSID initialization
    2452             :  */
    2453             : clib_error_t *
    2454         559 : sr_localsids_init (vlib_main_t * vm)
    2455             : {
    2456             :   /* Init memory for function keys */
    2457         559 :   ip6_sr_main_t *sm = &sr_main;
    2458         559 :   mhash_init (&sm->sr_localsids_index_hash, sizeof (uword),
    2459             :               sizeof (sr_localsid_key_t));
    2460             :   /* Init SR behaviors DPO type */
    2461         559 :   sr_localsid_dpo_type = dpo_register_new_type (&sr_loc_vft, sr_loc_nodes);
    2462             :   /* Init SR behaviors DPO type */
    2463         559 :   sr_localsid_d_dpo_type =
    2464         559 :     dpo_register_new_type (&sr_loc_vft, sr_loc_d_nodes);
    2465             :   /* Init SR bhaviors DPO type */
    2466         559 :   sr_localsid_un_dpo_type =
    2467         559 :     dpo_register_new_type (&sr_loc_vft, sr_loc_un_nodes);
    2468         559 :   sr_localsid_un_perf_dpo_type =
    2469         559 :     dpo_register_new_type (&sr_loc_vft, sr_loc_un_perf_nodes);
    2470             :   /* Init memory for localsid plugins */
    2471         559 :   sm->plugin_functions_by_key = hash_create_string (0, sizeof (uword));
    2472         559 :   return 0;
    2473             : }
    2474             : 
    2475       66079 : VLIB_INIT_FUNCTION (sr_localsids_init);
    2476             : /*
    2477             : * fd.io coding-style-patch-verification: ON
    2478             : *
    2479             : * Local Variables:
    2480             : * eval: (c-set-style "gnu")
    2481             : * End:
    2482             : */

Generated by: LCOV version 1.14