LCOV - code coverage report
Current view: top level - vnet/srv6 - sr_policy_rewrite.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 471 1734 27.2 %
Date: 2023-07-05 22:20:52 Functions: 42 65 64.6 %

          Line data    Source code
       1             : /*
       2             :  * sr_policy_rewrite.c: ipv6 sr policy creation
       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 SR policy creation and application
      21             :  *
      22             :  * Create an SR policy.
      23             :  * An SR policy can be either of 'default' type or 'spray' type
      24             :  * An SR policy has attached a list of SID lists.
      25             :  * In case the SR policy is a default one it will load balance among them.
      26             :  * An SR policy has associated a BindingSID.
      27             :  * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
      28             :  * associated to such bindingSID will be applied to such packet.
      29             :  *
      30             :  * SR policies can be applied either by using IPv6 encapsulation or
      31             :  * SRH insertion. Both methods can be found on this file.
      32             :  *
      33             :  * Traffic input usually is IPv6 packets. However it is possible to have
      34             :  * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
      35             :  *
      36             :  * This file provides the appropriate VPP graph nodes to do any of these
      37             :  * methods.
      38             :  *
      39             :  */
      40             : 
      41             : #include <vlib/vlib.h>
      42             : #include <vnet/vnet.h>
      43             : #include <vnet/srv6/sr.h>
      44             : #include <vnet/ip/ip4_inlines.h>
      45             : #include <vnet/ip/ip6_inlines.h>
      46             : #include <vnet/srv6/sr_packet.h>
      47             : #include <vnet/fib/ip6_fib.h>
      48             : #include <vnet/dpo/dpo.h>
      49             : #include <vnet/dpo/replicate_dpo.h>
      50             : #include <vnet/srv6/sr_pt.h>
      51             : 
      52             : #include <vppinfra/byte_order.h>
      53             : #include <vppinfra/error.h>
      54             : #include <vppinfra/elog.h>
      55             : 
      56             : /**
      57             :  * @brief SR policy rewrite trace
      58             :  */
      59             : typedef struct
      60             : {
      61             :   ip6_address_t src, dst;
      62             : } sr_policy_rewrite_trace_t;
      63             : 
      64             : /* Graph arcs */
      65             : #define foreach_sr_policy_rewrite_next     \
      66             : _(IP6_LOOKUP, "ip6-lookup")         \
      67             : _(ERROR, "error-drop")
      68             : 
      69             : typedef enum
      70             : {
      71             : #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
      72             :   foreach_sr_policy_rewrite_next
      73             : #undef _
      74             :     SR_POLICY_REWRITE_N_NEXT,
      75             : } sr_policy_rewrite_next_t;
      76             : 
      77             : /* SR rewrite errors */
      78             : #define foreach_sr_policy_rewrite_error                     \
      79             : _(INTERNAL_ERROR, "Segment Routing undefined error")        \
      80             : _(BSID_ZERO, "BSID with SL = 0")                            \
      81             : _(COUNTER_TOTAL, "SR steered IPv6 packets")                 \
      82             : _(COUNTER_ENCAP, "SR: Encaps packets")                      \
      83             : _(COUNTER_INSERT, "SR: SRH inserted packets")               \
      84             : _(COUNTER_BSID, "SR: BindingSID steered packets")
      85             : 
      86             : typedef enum
      87             : {
      88             : #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
      89             :   foreach_sr_policy_rewrite_error
      90             : #undef _
      91             :     SR_POLICY_REWRITE_N_ERROR,
      92             : } sr_policy_rewrite_error_t;
      93             : 
      94             : static char *sr_policy_rewrite_error_strings[] = {
      95             : #define _(sym,string) string,
      96             :   foreach_sr_policy_rewrite_error
      97             : #undef _
      98             : };
      99             : 
     100             : /**
     101             :  * @brief Dynamically added SR SL DPO type
     102             :  */
     103             : static dpo_type_t sr_pr_encaps_dpo_type;
     104             : static dpo_type_t sr_pr_insert_dpo_type;
     105             : static dpo_type_t sr_pr_bsid_encaps_dpo_type;
     106             : static dpo_type_t sr_pr_bsid_insert_dpo_type;
     107             : 
     108             : /**
     109             :  * @brief IPv6 SA for encapsulated packets
     110             :  */
     111             : static ip6_address_t sr_pr_encaps_src;
     112             : static u8 sr_pr_encaps_hop_limit = IPv6_DEFAULT_HOP_LIMIT;
     113             : 
     114             : /******************* SR rewrite set encaps IPv6 source addr *******************/
     115             : /* Note:  This is temporal. We don't know whether to follow this path or
     116             :           take the ip address of a loopback interface or even the OIF         */
     117             : 
     118             : void
     119           0 : sr_set_source (ip6_address_t * address)
     120             : {
     121           0 :   clib_memcpy_fast (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
     122           0 : }
     123             : 
     124             : ip6_address_t *
     125           0 : sr_get_encaps_source ()
     126             : {
     127           0 :   return &sr_pr_encaps_src;
     128             : }
     129             : 
     130             : static clib_error_t *
     131           7 : set_sr_src_command_fn (vlib_main_t * vm, unformat_input_t * input,
     132             :                        vlib_cli_command_t * cmd)
     133             : {
     134           7 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     135             :     {
     136           7 :       if (unformat
     137             :           (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
     138           7 :         return 0;
     139             :       else
     140           0 :         return clib_error_return (0, "No address specified");
     141             :     }
     142           0 :   return clib_error_return (0, "No address specified");
     143             : }
     144             : 
     145             : /* *INDENT-OFF* */
     146      272887 : VLIB_CLI_COMMAND (set_sr_src_command, static) = {
     147             :   .path = "set sr encaps source",
     148             :   .short_help = "set sr encaps source addr <ip6_addr>",
     149             :   .function = set_sr_src_command_fn,
     150             : };
     151             : /* *INDENT-ON* */
     152             : 
     153             : /******************** SR rewrite set encaps IPv6 hop-limit ********************/
     154             : 
     155             : void
     156           0 : sr_set_hop_limit (u8 hop_limit)
     157             : {
     158           0 :   sr_pr_encaps_hop_limit = hop_limit;
     159           0 : }
     160             : 
     161             : u8
     162           6 : sr_get_hop_limit (void)
     163             : {
     164           6 :   return sr_pr_encaps_hop_limit;
     165             : }
     166             : 
     167             : static clib_error_t *
     168           0 : set_sr_hop_limit_command_fn (vlib_main_t * vm, unformat_input_t * input,
     169             :                              vlib_cli_command_t * cmd)
     170             : {
     171           0 :   int hop_limit = sr_get_hop_limit ();
     172             : 
     173           0 :   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
     174           0 :     return clib_error_return (0, "No value specified");
     175           0 :   if (!unformat (input, "%d", &hop_limit))
     176           0 :     return clib_error_return (0, "Invalid value");
     177           0 :   if (hop_limit <= 0 || hop_limit > 255)
     178           0 :     return clib_error_return (0, "Value out of range [1-255]");
     179           0 :   sr_pr_encaps_hop_limit = (u8) hop_limit;
     180           0 :   return 0;
     181             : }
     182             : 
     183             : /* *INDENT-OFF* */
     184      272887 : VLIB_CLI_COMMAND (set_sr_hop_limit_command, static) = {
     185             :   .path = "set sr encaps hop-limit",
     186             :   .short_help = "set sr encaps hop-limit <value>",
     187             :   .function = set_sr_hop_limit_command_fn,
     188             : };
     189             : /* *INDENT-ON* */
     190             : 
     191             : /*********************** SR rewrite string computation ************************/
     192             : /**
     193             :  * @brief SR rewrite string computation for IPv6 encapsulation (inline)
     194             :  *
     195             :  * @param sl is a vector of IPv6 addresses composing the Segment List
     196             :  * @param src_v6addr is a encaps IPv6 source addr
     197             :  *
     198             :  * @return precomputed rewrite string for encapsulation
     199             :  */
     200             : static inline u8 *
     201           4 : compute_rewrite_encaps (ip6_address_t *sl, ip6_address_t *src_v6addr, u8 type)
     202             : {
     203             :   ip6_header_t *iph;
     204             :   ip6_sr_header_t *srh;
     205             :   ip6_sr_pt_tlv_t *srh_pt_tlv;
     206             :   ip6_address_t *addrp, *this_address;
     207           4 :   u32 header_length = 0;
     208           4 :   u8 *rs = NULL;
     209             : 
     210           4 :   header_length = 0;
     211           4 :   header_length += IPv6_DEFAULT_HEADER_LENGTH;
     212           4 :   if (type == SR_POLICY_TYPE_TEF)
     213             :     {
     214           0 :       header_length += sizeof (ip6_sr_header_t);
     215           0 :       header_length += vec_len (sl) * sizeof (ip6_address_t);
     216           0 :       header_length += sizeof (ip6_sr_pt_tlv_t);
     217             :     }
     218           4 :   else if (vec_len (sl) > 1)
     219             :     {
     220           3 :       header_length += sizeof (ip6_sr_header_t);
     221           3 :       header_length += vec_len (sl) * sizeof (ip6_address_t);
     222             :     }
     223             : 
     224           4 :   vec_validate (rs, header_length - 1);
     225             : 
     226           4 :   iph = (ip6_header_t *) rs;
     227           4 :   iph->ip_version_traffic_class_and_flow_label =
     228           4 :     clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
     229           4 :   iph->src_address.as_u64[0] = src_v6addr->as_u64[0];
     230           4 :   iph->src_address.as_u64[1] = src_v6addr->as_u64[1];
     231           4 :   iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
     232           4 :   iph->protocol = IP_PROTOCOL_IPV6;
     233           4 :   iph->hop_limit = sr_pr_encaps_hop_limit;
     234             : 
     235           4 :   if (type == SR_POLICY_TYPE_TEF)
     236             :     {
     237           0 :       srh = (ip6_sr_header_t *) (iph + 1);
     238           0 :       iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
     239           0 :       srh->protocol = IP_PROTOCOL_IPV6;
     240           0 :       srh->type = ROUTING_HEADER_TYPE_SR;
     241           0 :       srh->flags = 0x00;
     242           0 :       srh->tag = 0x0000;
     243           0 :       srh->segments_left = vec_len (sl) - 1;
     244           0 :       srh->last_entry = vec_len (sl) - 1;
     245           0 :       srh->length =
     246           0 :         ((sizeof (ip6_sr_header_t) + (vec_len (sl) * sizeof (ip6_address_t)) +
     247           0 :           sizeof (ip6_sr_pt_tlv_t)) /
     248           0 :          8) -
     249             :         1;
     250           0 :       addrp = srh->segments + vec_len (sl) - 1;
     251           0 :       vec_foreach (this_address, sl)
     252             :         {
     253           0 :           clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
     254             :                             sizeof (ip6_address_t));
     255           0 :           addrp--;
     256             :         }
     257           0 :       srh_pt_tlv = (ip6_sr_pt_tlv_t *) (srh->segments + vec_len (sl));
     258           0 :       srh_pt_tlv->type = IP6_SRH_PT_TLV_TYPE;
     259           0 :       srh_pt_tlv->length = IP6_SRH_PT_TLV_LEN;
     260             :     }
     261           4 :   else if (vec_len (sl) > 1)
     262             :     {
     263           3 :       srh = (ip6_sr_header_t *) (iph + 1);
     264           3 :       iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
     265           3 :       srh->protocol = IP_PROTOCOL_IPV6;
     266           3 :       srh->type = ROUTING_HEADER_TYPE_SR;
     267           3 :       srh->segments_left = vec_len (sl) - 1;
     268           3 :       srh->last_entry = vec_len (sl) - 1;
     269           3 :       srh->length = ((sizeof (ip6_sr_header_t) +
     270           3 :                       (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
     271           3 :       srh->flags = 0x00;
     272           3 :       srh->tag = 0x0000;
     273           3 :       addrp = srh->segments + vec_len (sl) - 1;
     274          10 :       vec_foreach (this_address, sl)
     275             :       {
     276           7 :         clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
     277             :                           sizeof (ip6_address_t));
     278           7 :         addrp--;
     279             :       }
     280             :     }
     281           4 :   iph->dst_address.as_u64[0] = sl->as_u64[0];
     282           4 :   iph->dst_address.as_u64[1] = sl->as_u64[1];
     283           4 :   return rs;
     284             : }
     285             : 
     286             : /**
     287             :  * @brief SR rewrite string computation for SRH insertion (inline)
     288             :  *
     289             :  * @param sl is a vector of IPv6 addresses composing the Segment List
     290             :  *
     291             :  * @return precomputed rewrite string for SRH insertion
     292             :  */
     293             : static inline u8 *
     294           0 : compute_rewrite_insert (ip6_address_t *sl, u8 type)
     295             : {
     296             :   ip6_sr_header_t *srh;
     297             :   ip6_address_t *addrp, *this_address;
     298           0 :   u32 header_length = 0;
     299           0 :   u8 *rs = NULL;
     300             : 
     301           0 :   header_length = 0;
     302           0 :   header_length += sizeof (ip6_sr_header_t);
     303           0 :   header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
     304             : 
     305           0 :   vec_validate (rs, header_length - 1);
     306             : 
     307           0 :   srh = (ip6_sr_header_t *) rs;
     308           0 :   srh->type = ROUTING_HEADER_TYPE_SR;
     309           0 :   srh->segments_left = vec_len (sl);
     310           0 :   srh->last_entry = vec_len (sl);
     311           0 :   srh->length = ((sizeof (ip6_sr_header_t) +
     312           0 :                   ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
     313           0 :   srh->flags = 0x00;
     314           0 :   srh->tag = 0x0000;
     315           0 :   addrp = srh->segments + vec_len (sl);
     316           0 :   vec_foreach (this_address, sl)
     317             :   {
     318           0 :     clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
     319             :                       sizeof (ip6_address_t));
     320           0 :     addrp--;
     321             :   }
     322           0 :   return rs;
     323             : }
     324             : 
     325             : /**
     326             :  * @brief SR rewrite string computation for SRH insertion with BSID (inline)
     327             :  *
     328             :  * @param sl is a vector of IPv6 addresses composing the Segment List
     329             :  *
     330             :  * @return precomputed rewrite string for SRH insertion with BSID
     331             :  */
     332             : static inline u8 *
     333           0 : compute_rewrite_bsid (ip6_address_t * sl)
     334             : {
     335             :   ip6_sr_header_t *srh;
     336             :   ip6_address_t *addrp, *this_address;
     337           0 :   u32 header_length = 0;
     338           0 :   u8 *rs = NULL;
     339             : 
     340           0 :   header_length = 0;
     341           0 :   header_length += sizeof (ip6_sr_header_t);
     342           0 :   header_length += vec_len (sl) * sizeof (ip6_address_t);
     343             : 
     344           0 :   vec_validate (rs, header_length - 1);
     345             : 
     346           0 :   srh = (ip6_sr_header_t *) rs;
     347           0 :   srh->type = ROUTING_HEADER_TYPE_SR;
     348           0 :   srh->segments_left = vec_len (sl) - 1;
     349           0 :   srh->last_entry = vec_len (sl) - 1;
     350           0 :   srh->length = ((sizeof (ip6_sr_header_t) +
     351           0 :                   (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
     352           0 :   srh->flags = 0x00;
     353           0 :   srh->tag = 0x0000;
     354           0 :   addrp = srh->segments + vec_len (sl) - 1;
     355           0 :   vec_foreach (this_address, sl)
     356             :   {
     357           0 :     clib_memcpy_fast (addrp->as_u8, this_address->as_u8,
     358             :                       sizeof (ip6_address_t));
     359           0 :     addrp--;
     360             :   }
     361           0 :   return rs;
     362             : }
     363             : 
     364             : /***************************  SR LB helper functions **************************/
     365             : /**
     366             :  * @brief Creates a Segment List and adds it to an SR policy
     367             :  *
     368             :  * Creates a Segment List and adds it to the SR policy. Notice that the SL are
     369             :  * not necessarily unique. Hence there might be two Segment List within the
     370             :  * same SR Policy with exactly the same segments and same weight.
     371             :  *
     372             :  * @param sr_policy is the SR policy where the SL will be added
     373             :  * @param sl is a vector of IPv6 addresses composing the Segment List
     374             :  * @param encap_src is a encaps IPv6 source addr. optional.
     375             :  * @param weight is the weight of the SegmentList (for load-balancing purposes)
     376             :  * @param is_encap represents the mode (SRH insertion vs Encapsulation)
     377             :  *
     378             :  * @return pointer to the just created segment list
     379             :  */
     380             : static inline ip6_sr_sl_t *
     381           4 : create_sl (ip6_sr_policy_t *sr_policy, ip6_address_t *sl,
     382             :            ip6_address_t *encap_src, u32 weight, u8 is_encap)
     383             : {
     384           4 :   ip6_sr_main_t *sm = &sr_main;
     385             :   ip6_sr_sl_t *segment_list;
     386           4 :   sr_policy_fn_registration_t *plugin = 0;
     387           4 :   ip6_address_t encap_srcv6 = sr_pr_encaps_src;
     388             : 
     389           4 :   pool_get (sm->sid_lists, segment_list);
     390           4 :   clib_memset (segment_list, 0, sizeof (*segment_list));
     391             : 
     392           4 :   vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
     393             : 
     394             :   /* Fill in segment list */
     395           4 :   segment_list->weight =
     396           4 :     (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
     397             : 
     398           4 :   segment_list->segments = vec_dup (sl);
     399           4 :   segment_list->policy_type = sr_policy->type;
     400             : 
     401           8 :   segment_list->egress_fib_table =
     402           4 :     ip6_fib_index_from_table_id (sr_policy->fib_table);
     403             : 
     404           4 :   if (is_encap)
     405             :     {
     406           4 :       if (encap_src)
     407             :         {
     408           1 :           clib_memcpy_fast (&encap_srcv6, encap_src, sizeof (ip6_address_t));
     409             :         }
     410           8 :       segment_list->rewrite =
     411           4 :         compute_rewrite_encaps (sl, &encap_srcv6, sr_policy->type);
     412           4 :       segment_list->rewrite_bsid = segment_list->rewrite;
     413           4 :       sr_policy->encap_src = encap_srcv6;
     414             :     }
     415             :   else
     416             :     {
     417           0 :       segment_list->rewrite = compute_rewrite_insert (sl, sr_policy->type);
     418           0 :       segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
     419             :     }
     420             : 
     421           4 :   if (sr_policy->plugin)
     422             :     {
     423           1 :       plugin =
     424           1 :         pool_elt_at_index (sm->policy_plugin_functions,
     425             :                            sr_policy->plugin - SR_BEHAVIOR_LAST);
     426             : 
     427           1 :       segment_list->plugin = sr_policy->plugin;
     428           1 :       segment_list->plugin_mem = sr_policy->plugin_mem;
     429             : 
     430           1 :       plugin->creation (sr_policy);
     431             :     }
     432             : 
     433             :   /* Create DPO */
     434           4 :   dpo_reset (&segment_list->bsid_dpo);
     435           4 :   dpo_reset (&segment_list->ip6_dpo);
     436           4 :   dpo_reset (&segment_list->ip4_dpo);
     437             : 
     438           4 :   if (is_encap)
     439             :     {
     440           4 :       if (!sr_policy->plugin)
     441             :         {
     442           3 :           dpo_set (&segment_list->ip6_dpo, sr_pr_encaps_dpo_type,
     443           3 :                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
     444           3 :           dpo_set (&segment_list->ip4_dpo, sr_pr_encaps_dpo_type,
     445           3 :                    DPO_PROTO_IP4, segment_list - sm->sid_lists);
     446           3 :           dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_encaps_dpo_type,
     447           3 :                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
     448             :         }
     449             :       else
     450             :         {
     451           1 :           dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
     452           1 :                    segment_list - sm->sid_lists);
     453           1 :           dpo_set (&segment_list->ip4_dpo, plugin->dpo, DPO_PROTO_IP4,
     454           1 :                    segment_list - sm->sid_lists);
     455           1 :           dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
     456           1 :                    segment_list - sm->sid_lists);
     457             :         }
     458             :     }
     459             :   else
     460             :     {
     461           0 :       if (!sr_policy->plugin)
     462             :         {
     463           0 :           dpo_set (&segment_list->ip6_dpo, sr_pr_insert_dpo_type,
     464           0 :                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
     465           0 :           dpo_set (&segment_list->bsid_dpo, sr_pr_bsid_insert_dpo_type,
     466           0 :                    DPO_PROTO_IP6, segment_list - sm->sid_lists);
     467             :         }
     468             :       else
     469             :         {
     470           0 :           dpo_set (&segment_list->ip6_dpo, plugin->dpo, DPO_PROTO_IP6,
     471           0 :                    segment_list - sm->sid_lists);
     472           0 :           dpo_set (&segment_list->bsid_dpo, plugin->dpo, DPO_PROTO_IP6,
     473           0 :                    segment_list - sm->sid_lists);
     474             :         }
     475             :     }
     476             : 
     477           4 :   return segment_list;
     478             : }
     479             : 
     480             : /**
     481             :  * @brief Updates the Load-Balancer after an SR Policy change
     482             :  *
     483             :  * @param sr_policy is the modified SR Policy
     484             :  */
     485             : static inline void
     486           4 : update_lb (ip6_sr_policy_t * sr_policy)
     487             : {
     488             :   flow_hash_config_t fhc;
     489             :   u32 *sl_index;
     490             :   ip6_sr_sl_t *segment_list;
     491           4 :   ip6_sr_main_t *sm = &sr_main;
     492             :   load_balance_path_t path;
     493           4 :   path.path_index = FIB_NODE_INDEX_INVALID;
     494           4 :   load_balance_path_t *ip4_path_vector = 0;
     495           4 :   load_balance_path_t *ip6_path_vector = 0;
     496           4 :   load_balance_path_t *b_path_vector = 0;
     497             : 
     498             :   /* In case LB does not exist, create it */
     499           4 :   if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
     500             :     {
     501           4 :       fib_prefix_t pfx = {
     502             :         .fp_proto = FIB_PROTOCOL_IP6,
     503             :         .fp_len = 128,
     504             :         .fp_addr = {
     505             :                     .ip6 = sr_policy->bsid,
     506             :                     }
     507             :       };
     508             : 
     509             :       /* Add FIB entry for BSID */
     510           4 :       fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
     511             :                                             FIB_PROTOCOL_IP6);
     512             : 
     513           4 :       dpo_set (&sr_policy->bsid_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
     514             :                load_balance_create (0, DPO_PROTO_IP6, fhc));
     515             : 
     516           4 :       dpo_set (&sr_policy->ip6_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP6,
     517             :                load_balance_create (0, DPO_PROTO_IP6, fhc));
     518             : 
     519             :       /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
     520           4 :       fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
     521             :                                                           sr_policy->fib_table),
     522             :                                           &pfx, FIB_SOURCE_SR,
     523             :                                           FIB_ENTRY_FLAG_EXCLUSIVE,
     524           4 :                                           &sr_policy->bsid_dpo);
     525             : 
     526           4 :       fib_table_entry_special_dpo_update (sm->fib_table_ip6,
     527             :                                           &pfx,
     528             :                                           FIB_SOURCE_SR,
     529             :                                           FIB_ENTRY_FLAG_EXCLUSIVE,
     530           4 :                                           &sr_policy->ip6_dpo);
     531             : 
     532           4 :       if (sr_policy->is_encap)
     533             :         {
     534           4 :           dpo_set (&sr_policy->ip4_dpo, DPO_LOAD_BALANCE, DPO_PROTO_IP4,
     535             :                    load_balance_create (0, DPO_PROTO_IP4, fhc));
     536             : 
     537           4 :           fib_table_entry_special_dpo_update (sm->fib_table_ip4,
     538             :                                               &pfx,
     539             :                                               FIB_SOURCE_SR,
     540             :                                               FIB_ENTRY_FLAG_EXCLUSIVE,
     541           4 :                                               &sr_policy->ip4_dpo);
     542             :         }
     543             : 
     544             :     }
     545             : 
     546             :   /* Create the LB path vector */
     547           8 :   vec_foreach (sl_index, sr_policy->segments_lists)
     548             :   {
     549           4 :     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
     550           4 :     path.path_dpo = segment_list->bsid_dpo;
     551           4 :     path.path_weight = segment_list->weight;
     552           4 :     vec_add1 (b_path_vector, path);
     553           4 :     path.path_dpo = segment_list->ip6_dpo;
     554           4 :     vec_add1 (ip6_path_vector, path);
     555           4 :     if (sr_policy->is_encap)
     556             :       {
     557           4 :         path.path_dpo = segment_list->ip4_dpo;
     558           4 :         vec_add1 (ip4_path_vector, path);
     559             :       }
     560             :   }
     561             : 
     562             :   /* Update LB multipath */
     563           4 :   load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
     564             :                                  LOAD_BALANCE_FLAG_NONE);
     565           4 :   load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
     566             :                                  LOAD_BALANCE_FLAG_NONE);
     567           4 :   if (sr_policy->is_encap)
     568           4 :     load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
     569             :                                    LOAD_BALANCE_FLAG_NONE);
     570             : 
     571             :   /* Cleanup */
     572           4 :   vec_free (b_path_vector);
     573           4 :   vec_free (ip6_path_vector);
     574           4 :   vec_free (ip4_path_vector);
     575           4 : }
     576             : 
     577             : /**
     578             :  * @brief Updates the Replicate DPO after an SR Policy change
     579             :  *
     580             :  * @param sr_policy is the modified SR Policy (type spray)
     581             :  */
     582             : static inline void
     583           0 : update_replicate (ip6_sr_policy_t * sr_policy)
     584             : {
     585             :   u32 *sl_index;
     586             :   ip6_sr_sl_t *segment_list;
     587           0 :   ip6_sr_main_t *sm = &sr_main;
     588             :   load_balance_path_t path;
     589           0 :   path.path_index = FIB_NODE_INDEX_INVALID;
     590           0 :   load_balance_path_t *b_path_vector = 0;
     591           0 :   load_balance_path_t *ip6_path_vector = 0;
     592           0 :   load_balance_path_t *ip4_path_vector = 0;
     593             : 
     594             :   /* In case LB does not exist, create it */
     595           0 :   if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
     596             :     {
     597           0 :       dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
     598             :                DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
     599             : 
     600           0 :       dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
     601             :                DPO_PROTO_IP6, replicate_create (0, DPO_PROTO_IP6));
     602             : 
     603             :       /* Update FIB entry's DPO to point to SR without LB */
     604           0 :       fib_prefix_t pfx = {
     605             :         .fp_proto = FIB_PROTOCOL_IP6,
     606             :         .fp_len = 128,
     607             :         .fp_addr = {
     608             :                     .ip6 = sr_policy->bsid,
     609             :                     }
     610             :       };
     611           0 :       fib_table_entry_special_dpo_update (fib_table_find (FIB_PROTOCOL_IP6,
     612             :                                                           sr_policy->fib_table),
     613             :                                           &pfx, FIB_SOURCE_SR,
     614             :                                           FIB_ENTRY_FLAG_EXCLUSIVE,
     615           0 :                                           &sr_policy->bsid_dpo);
     616             : 
     617           0 :       fib_table_entry_special_dpo_update (sm->fib_table_ip6,
     618             :                                           &pfx,
     619             :                                           FIB_SOURCE_SR,
     620             :                                           FIB_ENTRY_FLAG_EXCLUSIVE,
     621           0 :                                           &sr_policy->ip6_dpo);
     622             : 
     623           0 :       if (sr_policy->is_encap)
     624             :         {
     625           0 :           dpo_set (&sr_policy->ip4_dpo, DPO_REPLICATE, DPO_PROTO_IP4,
     626             :                    replicate_create (0, DPO_PROTO_IP4));
     627             : 
     628           0 :           fib_table_entry_special_dpo_update (sm->fib_table_ip4,
     629             :                                               &pfx,
     630             :                                               FIB_SOURCE_SR,
     631             :                                               FIB_ENTRY_FLAG_EXCLUSIVE,
     632           0 :                                               &sr_policy->ip4_dpo);
     633             :         }
     634             : 
     635             :     }
     636             : 
     637             :   /* Create the replicate path vector */
     638           0 :   path.path_weight = 1;
     639           0 :   vec_foreach (sl_index, sr_policy->segments_lists)
     640             :   {
     641           0 :     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
     642           0 :     path.path_dpo = segment_list->bsid_dpo;
     643           0 :     vec_add1 (b_path_vector, path);
     644           0 :     path.path_dpo = segment_list->ip6_dpo;
     645           0 :     vec_add1 (ip6_path_vector, path);
     646           0 :     if (sr_policy->is_encap)
     647             :       {
     648           0 :         path.path_dpo = segment_list->ip4_dpo;
     649           0 :         vec_add1 (ip4_path_vector, path);
     650             :       }
     651             :   }
     652             : 
     653             :   /* Update replicate multipath */
     654           0 :   replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
     655           0 :   replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
     656           0 :   if (sr_policy->is_encap)
     657           0 :     replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
     658           0 : }
     659             : 
     660             : /******************************* SR rewrite API *******************************/
     661             : /* Three functions for handling sr policies:
     662             :  *   -> sr_policy_add
     663             :  *   -> sr_policy_del
     664             :  *   -> sr_policy_mod
     665             :  * All of them are API. CLI function on sr_policy_command_fn                  */
     666             : 
     667             : /**
     668             :  * @brief Create a new SR policy
     669             :  *
     670             :  * @param bsid is the bindingSID of the SR Policy
     671             :  * @param segments is a vector of IPv6 address composing the segment list
     672             :  * @param encap_src is a encaps IPv6 source addr. optional.
     673             :  * @param weight is the weight of the sid list. optional.
     674             :  * @param behavior is the behavior of the SR policy. (default//spray)
     675             :  * @param fib_table is the VRF where to install the FIB entry for the BSID
     676             :  * @param is_encap (bool) whether SR policy should behave as Encap/SRH
     677             :  * Insertion
     678             :  *
     679             :  * @return 0 if correct, else error
     680             :  */
     681             : int
     682           4 : sr_policy_add (ip6_address_t *bsid, ip6_address_t *segments,
     683             :                ip6_address_t *encap_src, u32 weight, u8 type, u32 fib_table,
     684             :                u8 is_encap, u16 plugin, void *ls_plugin_mem)
     685             : {
     686           4 :   ip6_sr_main_t *sm = &sr_main;
     687           4 :   ip6_sr_policy_t *sr_policy = 0;
     688             :   uword *p;
     689             : 
     690             :   /* Search for existing keys (BSID) */
     691           4 :   p = mhash_get (&sm->sr_policies_index_hash, bsid);
     692           4 :   if (p)
     693             :     {
     694             :       /* Add SR policy that already exists; complain */
     695           0 :       return -12;
     696             :     }
     697             : 
     698             :   /* Search collision in FIB entries */
     699             :   /* Explanation: It might be possible that some other entity has already
     700             :    * created a route for the BSID. This in theory is impossible, but in
     701             :    * practise we could see it. Assert it and scream if needed */
     702           4 :   fib_prefix_t pfx = {
     703             :     .fp_proto = FIB_PROTOCOL_IP6,
     704             :     .fp_len = 128,
     705             :     .fp_addr = {
     706             :                 .ip6 = *bsid,
     707             :                 }
     708             :   };
     709             : 
     710             :   /* Lookup the FIB index associated to the table selected */
     711           4 :   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
     712             :                                   (fib_table != (u32) ~ 0 ? fib_table : 0));
     713           4 :   if (fib_index == ~0)
     714           0 :     return -13;
     715             : 
     716             :   /* Lookup whether there exists an entry for the BSID */
     717           4 :   fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
     718           4 :   if (FIB_NODE_INDEX_INVALID != fei)
     719           0 :     return -12;                 //There is an entry for such lookup
     720             : 
     721             :   /* Add an SR policy object */
     722           4 :   pool_get (sm->sr_policies, sr_policy);
     723           4 :   clib_memset (sr_policy, 0, sizeof (*sr_policy));
     724           4 :   clib_memcpy_fast (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
     725           4 :   sr_policy->type = type;
     726           4 :   sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0);   //Is default FIB 0 ?
     727           4 :   sr_policy->is_encap = is_encap;
     728             : 
     729           4 :   if (plugin)
     730             :     {
     731           1 :       sr_policy->plugin = plugin;
     732           1 :       sr_policy->plugin_mem = ls_plugin_mem;
     733             :     }
     734             : 
     735             :   /* Copy the key */
     736           4 :   mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
     737             :              NULL);
     738             : 
     739             :   /* Create a segment list and add the index to the SR policy */
     740           4 :   create_sl (sr_policy, segments, encap_src, weight, is_encap);
     741             : 
     742             :   /* If FIB doesnt exist, create them */
     743           4 :   if (sm->fib_table_ip6 == (u32) ~ 0)
     744             :     {
     745           3 :       sm->fib_table_ip6 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
     746             :                                                      FIB_SOURCE_SR,
     747             :                                                      "SRv6 steering of IP6 prefixes through BSIDs");
     748           3 :       sm->fib_table_ip4 = fib_table_create_and_lock (FIB_PROTOCOL_IP6,
     749             :                                                      FIB_SOURCE_SR,
     750             :                                                      "SRv6 steering of IP4 prefixes through BSIDs");
     751             :     }
     752             : 
     753             :   /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
     754           4 :   if (sr_policy->type == SR_POLICY_TYPE_DEFAULT ||
     755           0 :       sr_policy->type == SR_POLICY_TYPE_TEF)
     756           4 :     update_lb (sr_policy);
     757           0 :   else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
     758           0 :     update_replicate (sr_policy);
     759           4 :   return 0;
     760             : }
     761             : 
     762             : /**
     763             :  * @brief Delete a SR policy
     764             :  *
     765             :  * @param bsid is the bindingSID of the SR Policy
     766             :  * @param index is the index of the SR policy
     767             :  *
     768             :  * @return 0 if correct, else error
     769             :  */
     770             : int
     771           1 : sr_policy_del (ip6_address_t * bsid, u32 index)
     772             : {
     773           1 :   ip6_sr_main_t *sm = &sr_main;
     774           1 :   ip6_sr_policy_t *sr_policy = 0;
     775             :   ip6_sr_sl_t *segment_list;
     776             :   u32 *sl_index;
     777             :   uword *p;
     778             : 
     779           1 :   if (bsid)
     780             :     {
     781           1 :       p = mhash_get (&sm->sr_policies_index_hash, bsid);
     782           1 :       if (p)
     783           1 :         sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
     784             :       else
     785           0 :         return -1;
     786             :     }
     787             :   else
     788             :     {
     789           0 :       sr_policy = pool_elt_at_index (sm->sr_policies, index);
     790             :     }
     791             : 
     792             :   /* Remove BindingSID FIB entry */
     793           1 :   fib_prefix_t pfx = {
     794             :     .fp_proto = FIB_PROTOCOL_IP6,
     795             :     .fp_len = 128,
     796             :     .fp_addr = {
     797             :                 .ip6 = sr_policy->bsid,
     798             :                 }
     799             :     ,
     800             :   };
     801             : 
     802           1 :   fib_table_entry_special_remove (fib_table_find (FIB_PROTOCOL_IP6,
     803             :                                                   sr_policy->fib_table),
     804             :                                   &pfx, FIB_SOURCE_SR);
     805             : 
     806           1 :   fib_table_entry_special_remove (sm->fib_table_ip6, &pfx, FIB_SOURCE_SR);
     807             : 
     808           1 :   if (sr_policy->is_encap)
     809           1 :     fib_table_entry_special_remove (sm->fib_table_ip4, &pfx, FIB_SOURCE_SR);
     810             : 
     811           1 :   if (dpo_id_is_valid (&sr_policy->bsid_dpo))
     812             :     {
     813           1 :       dpo_reset (&sr_policy->bsid_dpo);
     814           1 :       dpo_reset (&sr_policy->ip4_dpo);
     815           1 :       dpo_reset (&sr_policy->ip6_dpo);
     816             :     }
     817             : 
     818             :   /* Clean SID Lists */
     819           2 :   vec_foreach (sl_index, sr_policy->segments_lists)
     820             :   {
     821           1 :     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
     822           1 :     vec_free (segment_list->segments);
     823           1 :     vec_free (segment_list->rewrite);
     824           1 :     if (!sr_policy->is_encap)
     825           0 :       vec_free (segment_list->rewrite_bsid);
     826           1 :     pool_put_index (sm->sid_lists, *sl_index);
     827             :   }
     828             : 
     829           1 :   if (sr_policy->plugin)
     830             :     {
     831           0 :       sr_policy_fn_registration_t *plugin = 0;
     832             : 
     833           0 :       plugin =
     834           0 :         pool_elt_at_index (sm->policy_plugin_functions,
     835             :                            sr_policy->plugin - SR_BEHAVIOR_LAST);
     836             : 
     837           0 :       plugin->removal (sr_policy);
     838           0 :       sr_policy->plugin = 0;
     839           0 :       sr_policy->plugin_mem = NULL;
     840             :     }
     841             : 
     842             :   /* Remove SR policy entry */
     843           1 :   mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
     844           1 :   pool_put (sm->sr_policies, sr_policy);
     845             : 
     846             :   /* If FIB empty unlock it */
     847           1 :   if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
     848             :     {
     849           1 :       fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
     850           1 :       fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6, FIB_SOURCE_SR);
     851           1 :       sm->fib_table_ip6 = (u32) ~ 0;
     852           1 :       sm->fib_table_ip4 = (u32) ~ 0;
     853             :     }
     854             : 
     855           1 :   return 0;
     856             : }
     857             : 
     858             : /**
     859             :  * @brief Modify an existing SR policy
     860             :  *
     861             :  * The possible modifications are adding a new Segment List, modifying an
     862             :  * existing Segment List (modify the weight only) and delete a given
     863             :  * Segment List from the SR Policy.
     864             :  *
     865             :  * @param bsid is the bindingSID of the SR Policy
     866             :  * @param index is the index of the SR policy
     867             :  * @param fib_table is the VRF where to install the FIB entry for the BSID
     868             :  * @param operation is the operation to perform (among the top ones)
     869             :  * @param segments is a vector of IPv6 address composing the segment list
     870             :  * @param encap_src is a encaps IPv6 source addr. optional.
     871             :  * @param sl_index is the index of the Segment List to modify/delete
     872             :  * @param weight is the weight of the sid list. optional.
     873             :  * @param is_encap Mode. Encapsulation or SRH insertion.
     874             :  *
     875             :  * @return 0 if correct, else error
     876             :  */
     877             : int
     878           0 : sr_policy_mod (ip6_address_t *bsid, u32 index, u32 fib_table, u8 operation,
     879             :                ip6_address_t *segments, ip6_address_t *encap_src, u32 sl_index,
     880             :                u32 weight)
     881             : {
     882           0 :   ip6_sr_main_t *sm = &sr_main;
     883           0 :   ip6_sr_policy_t *sr_policy = 0;
     884             :   ip6_sr_sl_t *segment_list;
     885             :   u32 *sl_index_iterate;
     886             :   uword *p;
     887             : 
     888           0 :   if (bsid)
     889             :     {
     890           0 :       p = mhash_get (&sm->sr_policies_index_hash, bsid);
     891           0 :       if (p)
     892           0 :         sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
     893             :       else
     894           0 :         return -1;
     895             :     }
     896             :   else
     897             :     {
     898           0 :       sr_policy = pool_elt_at_index (sm->sr_policies, index);
     899             :     }
     900             : 
     901           0 :   if (operation == 1)           /* Add SR List to an existing SR policy */
     902             :     {
     903             :       /* Create the new SL */
     904           0 :       segment_list = create_sl (sr_policy, segments, encap_src, weight,
     905           0 :                                 sr_policy->is_encap);
     906             : 
     907             :       /* Create a new LB DPO */
     908           0 :       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
     909           0 :         update_lb (sr_policy);
     910           0 :       else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
     911           0 :         update_replicate (sr_policy);
     912             :     }
     913           0 :   else if (operation == 2)      /* Delete SR List from an existing SR policy */
     914             :     {
     915             :       /* Check that currently there are more than one SID list */
     916           0 :       if (vec_len (sr_policy->segments_lists) == 1)
     917           0 :         return -21;
     918             : 
     919             :       /* Check that the SR list does exist and is assigned to the sr policy */
     920           0 :       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
     921           0 :         if (*sl_index_iterate == sl_index)
     922           0 :         break;
     923             : 
     924           0 :       if (*sl_index_iterate != sl_index)
     925           0 :         return -22;
     926             : 
     927             :       /* Remove the lucky SR list that is being kicked out */
     928           0 :       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
     929           0 :       vec_free (segment_list->segments);
     930           0 :       vec_free (segment_list->rewrite);
     931           0 :       if (!sr_policy->is_encap)
     932           0 :         vec_free (segment_list->rewrite_bsid);
     933           0 :       pool_put_index (sm->sid_lists, sl_index);
     934           0 :       vec_del1 (sr_policy->segments_lists,
     935             :                 sl_index_iterate - sr_policy->segments_lists);
     936             : 
     937             :       /* Create a new LB DPO */
     938           0 :       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
     939           0 :         update_lb (sr_policy);
     940           0 :       else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
     941           0 :         update_replicate (sr_policy);
     942             :     }
     943           0 :   else if (operation == 3)      /* Modify the weight of an existing SR List */
     944             :     {
     945             :       /* Find the corresponding SL */
     946           0 :       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
     947           0 :         if (*sl_index_iterate == sl_index)
     948           0 :         break;
     949             : 
     950           0 :       if (*sl_index_iterate != sl_index)
     951           0 :         return -32;
     952             : 
     953             :       /* Change the weight */
     954           0 :       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
     955           0 :       segment_list->weight = weight;
     956             : 
     957             :       /* Update LB */
     958           0 :       if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
     959           0 :         update_lb (sr_policy);
     960             :     }
     961             :   else                          /* Incorrect op. */
     962           0 :     return -1;
     963             : 
     964           0 :   return 0;
     965             : }
     966             : 
     967             : /**
     968             :  * @brief CLI for 'sr policies' command family
     969             :  */
     970             : static clib_error_t *
     971           3 : sr_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
     972             :                       vlib_cli_command_t * cmd)
     973             : {
     974           3 :   ip6_sr_main_t *sm = &sr_main;
     975           3 :   int rv = -1;
     976           3 :   char is_del = 0, is_add = 0, is_mod = 0;
     977           3 :   char policy_set = 0;
     978             :   ip6_address_t bsid, next_address, src_v6addr;
     979           3 :   u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
     980           3 :   u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
     981           3 :   ip6_address_t *segments = 0, *this_seg;
     982           3 :   u8 operation = 0;
     983           3 :   char is_encap = 1;
     984           3 :   u8 type = SR_POLICY_TYPE_DEFAULT;
     985           3 :   u16 behavior = 0;
     986           3 :   void *ls_plugin_mem = 0;
     987           3 :   ip6_address_t *encap_src = 0;
     988             : 
     989          14 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     990             :     {
     991          11 :       if (!is_add && !is_mod && !is_del && unformat (input, "add"))
     992           3 :         is_add = 1;
     993           8 :       else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
     994           0 :         is_del = 1;
     995           8 :       else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
     996           0 :         is_mod = 1;
     997           8 :       else if (!policy_set
     998           3 :                && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
     999           3 :         policy_set = 1;
    1000           5 :       else if (!is_add && !policy_set
    1001           0 :                && unformat (input, "index %d", &sr_policy_index))
    1002           0 :         policy_set = 1;
    1003           5 :       else if (unformat (input, "weight %d", &weight));
    1004             :       else
    1005           5 :         if (unformat (input, "next %U", unformat_ip6_address, &next_address))
    1006             :         {
    1007           4 :           vec_add2 (segments, this_seg, 1);
    1008           4 :           clib_memcpy_fast (this_seg->as_u8, next_address.as_u8,
    1009             :                             sizeof (*this_seg));
    1010             :         }
    1011           1 :       else if (unformat (input, "v6src %U", unformat_ip6_address, &src_v6addr))
    1012             :         {
    1013           0 :           encap_src = &src_v6addr;
    1014             :         }
    1015           1 :       else if (unformat (input, "add sl"))
    1016           0 :         operation = 1;
    1017           1 :       else if (unformat (input, "del sl index %d", &sl_index))
    1018           0 :         operation = 2;
    1019           1 :       else if (unformat (input, "mod sl index %d", &sl_index))
    1020           0 :         operation = 3;
    1021           1 :       else if (fib_table == (u32) ~ 0
    1022           1 :                && unformat (input, "fib-table %d", &fib_table));
    1023           1 :       else if (unformat (input, "encap"))
    1024           0 :         is_encap = 1;
    1025           1 :       else if (unformat (input, "insert"))
    1026           0 :         is_encap = 0;
    1027           1 :       else if (unformat (input, "spray"))
    1028           0 :         type = SR_POLICY_TYPE_SPRAY;
    1029           1 :       else if (unformat (input, "tef"))
    1030           0 :         type = SR_POLICY_TYPE_TEF;
    1031           1 :       else if (!behavior && unformat (input, "behavior"))
    1032             :         {
    1033           1 :           sr_policy_fn_registration_t *plugin = 0, **vec_plugins = 0;
    1034           1 :           sr_policy_fn_registration_t **plugin_it = 0;
    1035             : 
    1036             :           /* *INDENT-OFF* */
    1037           4 :           pool_foreach (plugin, sm->policy_plugin_functions)
    1038             :             {
    1039           3 :               vec_add1 (vec_plugins, plugin);
    1040             :             }
    1041             :           /* *INDENT-ON* */
    1042             : 
    1043           1 :           vec_foreach (plugin_it, vec_plugins)
    1044             :           {
    1045           1 :             if (unformat
    1046           1 :                 (input, "%U", (*plugin_it)->ls_unformat, &ls_plugin_mem))
    1047             :               {
    1048           1 :                 behavior = (*plugin_it)->sr_policy_function_number;
    1049           1 :                 break;
    1050             :               }
    1051             :           }
    1052             : 
    1053           1 :           if (!behavior)
    1054             :             {
    1055           0 :               return clib_error_return (0, "Invalid behavior");
    1056             :             }
    1057             :         }
    1058             :       else
    1059             :         break;
    1060             :     }
    1061             : 
    1062           3 :   if (!is_add && !is_mod && !is_del)
    1063           0 :     return clib_error_return (0, "Incorrect CLI");
    1064             : 
    1065           3 :   if (!policy_set)
    1066           0 :     return clib_error_return (0, "No SR policy BSID or index specified");
    1067             : 
    1068           3 :   if (is_add)
    1069             :     {
    1070           3 :       if (behavior && vec_len (segments) == 0)
    1071             :         {
    1072           1 :           vec_add2 (segments, this_seg, 1);
    1073           1 :           clib_memset (this_seg, 0, sizeof (*this_seg));
    1074             :         }
    1075             : 
    1076           3 :       if (vec_len (segments) == 0)
    1077           0 :         return clib_error_return (0, "No Segment List specified");
    1078             : 
    1079           3 :       rv = sr_policy_add (&bsid, segments, encap_src, weight, type, fib_table,
    1080             :                           is_encap, behavior, ls_plugin_mem);
    1081             : 
    1082           3 :       vec_free (segments);
    1083             :     }
    1084           0 :   else if (is_del)
    1085           0 :     rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
    1086             :                         sr_policy_index);
    1087           0 :   else if (is_mod)
    1088             :     {
    1089           0 :       if (!operation)
    1090           0 :         return clib_error_return (0, "No SL modification specified");
    1091           0 :       if (operation != 1 && sl_index == (u32) ~ 0)
    1092           0 :         return clib_error_return (0, "No Segment List index specified");
    1093           0 :       if (operation == 1 && vec_len (segments) == 0)
    1094           0 :         return clib_error_return (0, "No Segment List specified");
    1095           0 :       if (operation == 3 && weight == (u32) ~ 0)
    1096           0 :         return clib_error_return (0, "No new weight for the SL specified");
    1097             : 
    1098           0 :       rv = sr_policy_mod ((sr_policy_index != (u32) ~0 ? NULL : &bsid),
    1099             :                           sr_policy_index, fib_table, operation, segments,
    1100             :                           encap_src, sl_index, weight);
    1101             : 
    1102           0 :       if (segments)
    1103           0 :         vec_free (segments);
    1104             :     }
    1105             : 
    1106           3 :   switch (rv)
    1107             :     {
    1108           3 :     case 0:
    1109           3 :       break;
    1110           0 :     case 1:
    1111           0 :       return 0;
    1112           0 :     case -12:
    1113           0 :       return clib_error_return (0,
    1114             :                                 "There is already a FIB entry for the BindingSID address.\n"
    1115             :                                 "The SR policy could not be created.");
    1116           0 :     case -13:
    1117           0 :       return clib_error_return (0, "The specified FIB table does not exist.");
    1118           0 :     case -21:
    1119           0 :       return clib_error_return (0,
    1120             :                                 "The selected SR policy only contains ONE segment list. "
    1121             :                                 "Please remove the SR policy instead");
    1122           0 :     case -22:
    1123           0 :       return clib_error_return (0,
    1124             :                                 "Could not delete the segment list. "
    1125             :                                 "It is not associated with that SR policy.");
    1126           0 :     case -32:
    1127           0 :       return clib_error_return (0,
    1128             :                                 "Could not modify the segment list. "
    1129             :                                 "The given SL is not associated with such SR policy.");
    1130           0 :     default:
    1131           0 :       return clib_error_return (0, "BUG: sr policy returns %d", rv);
    1132             :     }
    1133           3 :   return 0;
    1134             : }
    1135             : 
    1136             : /* *INDENT-OFF* */
    1137      272887 : VLIB_CLI_COMMAND (sr_policy_command, static) = {
    1138             :   .path = "sr policy",
    1139             :   .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
    1140             :     "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
    1141             :   .long_help =
    1142             :     "Manipulation of SR policies.\n"
    1143             :     "A Segment Routing policy may contain several SID lists. Each SID list has\n"
    1144             :     "an associated weight (default 1), which will result in wECMP (uECMP).\n"
    1145             :     "Segment Routing policies might be of type encapsulation or srh insertion\n"
    1146             :     "Each SR policy will be associated with a unique BindingSID.\n"
    1147             :     "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
    1148             :     "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
    1149             :     "The add command will create a SR policy with its first segment list (sl)\n"
    1150             :     "The mod command allows you to add, remove, or modify the existing segment lists\n"
    1151             :     "within an SR policy.\n"
    1152             :     "The del command allows you to delete a SR policy along with all its associated\n"
    1153             :     "SID lists.\n",
    1154             :   .function = sr_policy_command_fn,
    1155             : };
    1156             : /* *INDENT-ON* */
    1157             : 
    1158             : /**
    1159             :  * @brief CLI to display onscreen all the SR policies
    1160             :  */
    1161             : static clib_error_t *
    1162           4 : show_sr_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
    1163             :                              vlib_cli_command_t * cmd)
    1164             : {
    1165           4 :   ip6_sr_main_t *sm = &sr_main;
    1166             :   u32 *sl_index;
    1167           4 :   ip6_sr_sl_t *segment_list = 0;
    1168           4 :   ip6_sr_policy_t *sr_policy = 0;
    1169           4 :   ip6_sr_policy_t **vec_policies = 0;
    1170             :   ip6_address_t *addr;
    1171             :   u8 *s;
    1172           4 :   int i = 0;
    1173             : 
    1174           4 :   vlib_cli_output (vm, "SR policies:");
    1175             : 
    1176             :   /* *INDENT-OFF* */
    1177           8 :   pool_foreach (sr_policy, sm->sr_policies)
    1178           4 :                 {vec_add1 (vec_policies, sr_policy); }
    1179             :   /* *INDENT-ON* */
    1180             : 
    1181           8 :   vec_foreach_index (i, vec_policies)
    1182             :   {
    1183           4 :     sr_policy = vec_policies[i];
    1184           4 :     vlib_cli_output (vm, "[%u].-\tBSID: %U",
    1185           4 :                      (u32) (sr_policy - sm->sr_policies),
    1186             :                      format_ip6_address, &sr_policy->bsid);
    1187           4 :     vlib_cli_output (vm, "\tBehavior: %s",
    1188           4 :                      (sr_policy->is_encap ? "Encapsulation" :
    1189             :                       "SRH insertion"));
    1190           4 :     if (sr_policy->is_encap)
    1191             :       {
    1192           4 :         vlib_cli_output (vm, "\tEncapSrcIP: %U", format_ip6_address,
    1193             :                          &sr_policy->encap_src);
    1194             :       }
    1195           4 :     switch (sr_policy->type)
    1196             :       {
    1197           0 :       case SR_POLICY_TYPE_SPRAY:
    1198           0 :         vlib_cli_output (vm, "\tType: %s", "Spray");
    1199           0 :         break;
    1200           0 :       case SR_POLICY_TYPE_TEF:
    1201           0 :         vlib_cli_output (vm, "\tType: %s",
    1202             :                          "TEF (Timestamp, Encapsulate, and Forward)");
    1203           0 :         break;
    1204           4 :       default:
    1205           4 :         vlib_cli_output (vm, "\tType: %s", "Default");
    1206           4 :         break;
    1207             :       }
    1208           4 :     vlib_cli_output (vm, "\tFIB table: %u",
    1209           4 :                      (sr_policy->fib_table !=
    1210             :                       (u32) ~ 0 ? sr_policy->fib_table : 0));
    1211           4 :     vlib_cli_output (vm, "\tSegment Lists:");
    1212           8 :     vec_foreach (sl_index, sr_policy->segments_lists)
    1213             :     {
    1214           4 :       s = NULL;
    1215           4 :       s = format (s, "\t[%u].- ", *sl_index);
    1216           4 :       segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
    1217           4 :       s = format (s, "< ");
    1218          12 :       vec_foreach (addr, segment_list->segments)
    1219             :       {
    1220           8 :         s = format (s, "%U, ", format_ip6_address, addr);
    1221             :       }
    1222           4 :       s = format (s, "\b\b > ");
    1223           4 :       s = format (s, "weight: %u", segment_list->weight);
    1224           4 :       vlib_cli_output (vm, "  %v", s);
    1225             :     }
    1226           4 :     vlib_cli_output (vm, "-----------");
    1227             :   }
    1228           4 :   return 0;
    1229             : }
    1230             : 
    1231             : /* *INDENT-OFF* */
    1232      272887 : VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
    1233             :   .path = "show sr policies",
    1234             :   .short_help = "show sr policies",
    1235             :   .function = show_sr_policies_command_fn,
    1236             : };
    1237             : /* *INDENT-ON* */
    1238             : 
    1239             : /**
    1240             :  * @brief CLI to display onscreen the SR encaps source addr
    1241             :  */
    1242             : static clib_error_t *
    1243           0 : show_sr_encaps_source_command_fn (vlib_main_t * vm, unformat_input_t * input,
    1244             :                                   vlib_cli_command_t * cmd)
    1245             : {
    1246           0 :   vlib_cli_output (vm, "SR encaps source addr = %U", format_ip6_address,
    1247             :                    sr_get_encaps_source ());
    1248             : 
    1249           0 :   return 0;
    1250             : }
    1251             : 
    1252             : /* *INDENT-OFF* */
    1253      272887 : VLIB_CLI_COMMAND (show_sr_encaps_source_command, static) = {
    1254             :   .path = "show sr encaps source addr",
    1255             :   .short_help = "show sr encaps source addr",
    1256             :   .function = show_sr_encaps_source_command_fn,
    1257             : };
    1258             : /* *INDENT-ON* */
    1259             : 
    1260             : /**
    1261             :  * @brief CLI to display onscreen the hop-limit value used for SRv6 encapsulation
    1262             :  */
    1263             : static clib_error_t *
    1264           0 : show_sr_encaps_hop_limit_command_fn (vlib_main_t * vm,
    1265             :                                      unformat_input_t * input,
    1266             :                                      vlib_cli_command_t * cmd)
    1267             : {
    1268           0 :   vlib_cli_output (vm, "SR encaps hop-limit = %u", sr_get_hop_limit ());
    1269             : 
    1270           0 :   return 0;
    1271             : }
    1272             : 
    1273             : /* *INDENT-OFF* */
    1274      272887 : VLIB_CLI_COMMAND (show_sr_encaps_hop_limit_command, static) = {
    1275             :   .path = "show sr encaps hop-limit",
    1276             :   .short_help = "show sr encaps hop-limit",
    1277             :   .function = show_sr_encaps_hop_limit_command_fn,
    1278             : };
    1279             : /* *INDENT-ON* */
    1280             : 
    1281             : /*************************** SR rewrite graph node ****************************/
    1282             : /**
    1283             :  * @brief Trace for the SR Policy Rewrite graph node
    1284             :  */
    1285             : static u8 *
    1286           9 : format_sr_policy_rewrite_trace (u8 * s, va_list * args)
    1287             : {
    1288             :   //TODO
    1289           9 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1290           9 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1291           9 :   sr_policy_rewrite_trace_t *t = va_arg (*args, sr_policy_rewrite_trace_t *);
    1292             : 
    1293           9 :   s = format
    1294             :     (s, "SR-policy-rewrite: src %U dst %U",
    1295             :      format_ip6_address, &t->src, format_ip6_address, &t->dst);
    1296             : 
    1297           9 :   return s;
    1298             : }
    1299             : /**
    1300             :  * @brief SRv6 TEF (Timestamp, Encapsulate, and Forward) behavior
    1301             :  */
    1302             : static_always_inline void
    1303           0 : srv6_tef_behavior (vlib_node_runtime_t *node, vlib_buffer_t *b0,
    1304             :                    ip6_header_t *ip0)
    1305             : {
    1306             :   ip6_sr_header_t *srh;
    1307             :   ip6_sr_pt_tlv_t *srh_pt_tlv;
    1308             :   timestamp_64_t ts;
    1309           0 :   sr_pt_iface_t *ls = 0;
    1310           0 :   u16 id_ld = 0;
    1311           0 :   srh = (ip6_sr_header_t *) (ip0 + 1);
    1312             : 
    1313           0 :   srh_pt_tlv =
    1314             :     (ip6_sr_pt_tlv_t *) ((u8 *) ip0 + sizeof (ip6_header_t) +
    1315           0 :                          sizeof (ip6_sr_header_t) +
    1316           0 :                          sizeof (ip6_address_t) * (srh->last_entry + 1));
    1317             : 
    1318           0 :   unix_time_now_nsec_fraction (&ts.sec, &ts.nsec);
    1319           0 :   srh_pt_tlv->t64.sec = clib_host_to_net_u32 (ts.sec);
    1320           0 :   srh_pt_tlv->t64.nsec = clib_host_to_net_u32 (ts.nsec);
    1321           0 :   ls = sr_pt_find_iface (vnet_buffer (b0)->sw_if_index[VLIB_RX]);
    1322           0 :   if (ls)
    1323             :     {
    1324           0 :       id_ld = ls->id << 4;
    1325           0 :       id_ld |= ls->ingress_load;
    1326           0 :       srh_pt_tlv->id_ld = clib_host_to_net_u16 (id_ld);
    1327             :     }
    1328           0 : }
    1329             : 
    1330             : /**
    1331             :  * @brief IPv6 encapsulation processing as per RFC2473
    1332             :  */
    1333             : static_always_inline void
    1334           9 : encaps_processing_v6 (vlib_node_runtime_t *node, vlib_buffer_t *b0,
    1335             :                       ip6_header_t *ip0, ip6_header_t *ip0_encap,
    1336             :                       u8 policy_type)
    1337             : {
    1338             :   u32 new_l0;
    1339             :   u32 flow_label;
    1340             : 
    1341           9 :   ip0_encap->hop_limit -= 1;
    1342           9 :   new_l0 =
    1343          18 :     ip0->payload_length + sizeof (ip6_header_t) +
    1344           9 :     clib_net_to_host_u16 (ip0_encap->payload_length);
    1345           9 :   ip0->payload_length = clib_host_to_net_u16 (new_l0);
    1346             : 
    1347           9 :   flow_label = ip6_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
    1348          18 :   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    1349           9 :     0 |
    1350           9 :     (clib_net_to_host_u32 (
    1351             :        ip0_encap->ip_version_traffic_class_and_flow_label) &
    1352             :      0xfff00000) |
    1353           9 :     (flow_label & 0x0000ffff));
    1354           9 :   if (policy_type == SR_POLICY_TYPE_TEF)
    1355           0 :     srv6_tef_behavior (node, b0, ip0);
    1356           9 : }
    1357             : 
    1358             : /**
    1359             :  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
    1360             :  */
    1361             : static uword
    1362           1 : sr_policy_rewrite_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
    1363             :                           vlib_frame_t * from_frame)
    1364             : {
    1365           1 :   ip6_sr_main_t *sm = &sr_main;
    1366             :   u32 n_left_from, next_index, *from, *to_next;
    1367             : 
    1368           1 :   from = vlib_frame_vector_args (from_frame);
    1369           1 :   n_left_from = from_frame->n_vectors;
    1370             : 
    1371           1 :   next_index = node->cached_next_index;
    1372             : 
    1373           1 :   int encap_pkts = 0, bsid_pkts = 0;
    1374             : 
    1375           2 :   while (n_left_from > 0)
    1376             :     {
    1377             :       u32 n_left_to_next;
    1378             : 
    1379           1 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1380             : 
    1381             :       /* Quad - Loop */
    1382           2 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    1383             :         {
    1384             :           u32 bi0, bi1, bi2, bi3;
    1385             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    1386             :           u32 next0, next1, next2, next3;
    1387           1 :           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    1388             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    1389             :           ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
    1390             :           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
    1391             : 
    1392             :           /* Prefetch next iteration. */
    1393             :           {
    1394             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    1395             : 
    1396           1 :             p4 = vlib_get_buffer (vm, from[4]);
    1397           1 :             p5 = vlib_get_buffer (vm, from[5]);
    1398           1 :             p6 = vlib_get_buffer (vm, from[6]);
    1399           1 :             p7 = vlib_get_buffer (vm, from[7]);
    1400             : 
    1401             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    1402           1 :             vlib_prefetch_buffer_header (p4, LOAD);
    1403           1 :             vlib_prefetch_buffer_header (p5, LOAD);
    1404           1 :             vlib_prefetch_buffer_header (p6, LOAD);
    1405           1 :             vlib_prefetch_buffer_header (p7, LOAD);
    1406             : 
    1407           1 :             clib_prefetch_store (p4->data);
    1408           1 :             clib_prefetch_store (p5->data);
    1409           1 :             clib_prefetch_store (p6->data);
    1410           1 :             clib_prefetch_store (p7->data);
    1411             :           }
    1412             : 
    1413           1 :           to_next[0] = bi0 = from[0];
    1414           1 :           to_next[1] = bi1 = from[1];
    1415           1 :           to_next[2] = bi2 = from[2];
    1416           1 :           to_next[3] = bi3 = from[3];
    1417           1 :           from += 4;
    1418           1 :           to_next += 4;
    1419           1 :           n_left_from -= 4;
    1420           1 :           n_left_to_next -= 4;
    1421             : 
    1422           1 :           b0 = vlib_get_buffer (vm, bi0);
    1423           1 :           b1 = vlib_get_buffer (vm, bi1);
    1424           1 :           b2 = vlib_get_buffer (vm, bi2);
    1425           1 :           b3 = vlib_get_buffer (vm, bi3);
    1426             : 
    1427           1 :           sl0 =
    1428           1 :             pool_elt_at_index (sm->sid_lists,
    1429             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1430           1 :           sl1 =
    1431           1 :             pool_elt_at_index (sm->sid_lists,
    1432             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    1433           1 :           sl2 =
    1434           1 :             pool_elt_at_index (sm->sid_lists,
    1435             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    1436           1 :           sl3 =
    1437           1 :             pool_elt_at_index (sm->sid_lists,
    1438             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    1439             : 
    1440           1 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1441             :                   vec_len (sl0->rewrite));
    1442           1 :           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1443             :                   vec_len (sl1->rewrite));
    1444           1 :           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1445             :                   vec_len (sl2->rewrite));
    1446           1 :           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1447             :                   vec_len (sl3->rewrite));
    1448             : 
    1449           1 :           ip0_encap = vlib_buffer_get_current (b0);
    1450           1 :           ip1_encap = vlib_buffer_get_current (b1);
    1451           1 :           ip2_encap = vlib_buffer_get_current (b2);
    1452           1 :           ip3_encap = vlib_buffer_get_current (b3);
    1453             : 
    1454           2 :           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
    1455           2 :                             sl0->rewrite, vec_len (sl0->rewrite));
    1456           2 :           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
    1457           2 :                             sl1->rewrite, vec_len (sl1->rewrite));
    1458           2 :           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
    1459           2 :                             sl2->rewrite, vec_len (sl2->rewrite));
    1460           2 :           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
    1461           2 :                             sl3->rewrite, vec_len (sl3->rewrite));
    1462             : 
    1463           1 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    1464           1 :           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
    1465           1 :           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
    1466           1 :           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
    1467             : 
    1468           1 :           ip0 = vlib_buffer_get_current (b0);
    1469           1 :           ip1 = vlib_buffer_get_current (b1);
    1470           1 :           ip2 = vlib_buffer_get_current (b2);
    1471           1 :           ip3 = vlib_buffer_get_current (b3);
    1472             : 
    1473           1 :           encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
    1474           1 :           encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
    1475           1 :           encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
    1476           1 :           encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
    1477             : 
    1478           1 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
    1479           1 :           vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
    1480           1 :           vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
    1481           1 :           vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
    1482             : 
    1483           1 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    1484             :             {
    1485           1 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1486             :                 {
    1487             :                   sr_policy_rewrite_trace_t *tr =
    1488           1 :                     vlib_add_trace (vm, node, b0, sizeof (*tr));
    1489           1 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    1490             :                                     sizeof (tr->src.as_u8));
    1491           1 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    1492             :                                     sizeof (tr->dst.as_u8));
    1493             :                 }
    1494             : 
    1495           1 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    1496             :                 {
    1497             :                   sr_policy_rewrite_trace_t *tr =
    1498           1 :                     vlib_add_trace (vm, node, b1, sizeof (*tr));
    1499           1 :                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
    1500             :                                     sizeof (tr->src.as_u8));
    1501           1 :                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
    1502             :                                     sizeof (tr->dst.as_u8));
    1503             :                 }
    1504             : 
    1505           1 :               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    1506             :                 {
    1507             :                   sr_policy_rewrite_trace_t *tr =
    1508           1 :                     vlib_add_trace (vm, node, b2, sizeof (*tr));
    1509           1 :                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
    1510             :                                     sizeof (tr->src.as_u8));
    1511           1 :                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
    1512             :                                     sizeof (tr->dst.as_u8));
    1513             :                 }
    1514             : 
    1515           1 :               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    1516             :                 {
    1517             :                   sr_policy_rewrite_trace_t *tr =
    1518           1 :                     vlib_add_trace (vm, node, b3, sizeof (*tr));
    1519           1 :                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
    1520             :                                     sizeof (tr->src.as_u8));
    1521           1 :                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
    1522             :                                     sizeof (tr->dst.as_u8));
    1523             :                 }
    1524             :             }
    1525             : 
    1526           1 :           encap_pkts += 4;
    1527           1 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    1528             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    1529             :                                            next0, next1, next2, next3);
    1530             :         }
    1531             : 
    1532             :       /* Single loop for potentially the last three packets */
    1533           6 :       while (n_left_from > 0 && n_left_to_next > 0)
    1534             :         {
    1535             :           u32 bi0;
    1536             :           vlib_buffer_t *b0;
    1537           5 :           ip6_header_t *ip0 = 0, *ip0_encap = 0;
    1538             :           ip6_sr_sl_t *sl0;
    1539           5 :           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    1540             : 
    1541           5 :           bi0 = from[0];
    1542           5 :           to_next[0] = bi0;
    1543           5 :           from += 1;
    1544           5 :           to_next += 1;
    1545           5 :           n_left_from -= 1;
    1546           5 :           n_left_to_next -= 1;
    1547           5 :           b0 = vlib_get_buffer (vm, bi0);
    1548             : 
    1549           5 :           sl0 =
    1550           5 :             pool_elt_at_index (sm->sid_lists,
    1551             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1552           5 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1553             :                   vec_len (sl0->rewrite));
    1554             : 
    1555           5 :           ip0_encap = vlib_buffer_get_current (b0);
    1556             : 
    1557          10 :           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
    1558          10 :                             sl0->rewrite, vec_len (sl0->rewrite));
    1559           5 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    1560             : 
    1561           5 :           ip0 = vlib_buffer_get_current (b0);
    1562             : 
    1563           5 :           encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
    1564             : 
    1565           5 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
    1566             : 
    1567           5 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
    1568           5 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1569             :             {
    1570             :               sr_policy_rewrite_trace_t *tr =
    1571           5 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1572           5 :               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    1573             :                                 sizeof (tr->src.as_u8));
    1574           5 :               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    1575             :                                 sizeof (tr->dst.as_u8));
    1576             :             }
    1577             : 
    1578           5 :           encap_pkts++;
    1579           5 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    1580             :                                            n_left_to_next, bi0, next0);
    1581             :         }
    1582             : 
    1583           1 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1584             :     }
    1585             : 
    1586             :   /* Update counters */
    1587           1 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    1588             :                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
    1589             :                                encap_pkts);
    1590           1 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    1591             :                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
    1592             :                                bsid_pkts);
    1593             : 
    1594           1 :   return from_frame->n_vectors;
    1595             : }
    1596             : 
    1597             : /* *INDENT-OFF* */
    1598      178120 : VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node) = {
    1599             :   .function = sr_policy_rewrite_encaps,
    1600             :   .name = "sr-pl-rewrite-encaps",
    1601             :   .vector_size = sizeof (u32),
    1602             :   .format_trace = format_sr_policy_rewrite_trace,
    1603             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1604             :   .n_errors = SR_POLICY_REWRITE_N_ERROR,
    1605             :   .error_strings = sr_policy_rewrite_error_strings,
    1606             :   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
    1607             :   .next_nodes = {
    1608             : #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
    1609             :     foreach_sr_policy_rewrite_next
    1610             : #undef _
    1611             :   },
    1612             : };
    1613             : /* *INDENT-ON* */
    1614             : 
    1615             : /**
    1616             :  * @brief IPv4 encapsulation processing as per RFC2473
    1617             :  */
    1618             : static_always_inline void
    1619           0 : encaps_processing_v4 (vlib_node_runtime_t * node,
    1620             :                       vlib_buffer_t * b0,
    1621             :                       ip6_header_t * ip0, ip4_header_t * ip0_encap)
    1622             : {
    1623             :   u32 new_l0;
    1624             :   ip6_sr_header_t *sr0;
    1625             : 
    1626             :   u32 checksum0;
    1627             :   u32 flow_label;
    1628             : 
    1629             :   /* Inner IPv4: Decrement TTL & update checksum */
    1630           0 :   ip0_encap->ttl -= 1;
    1631           0 :   checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
    1632           0 :   checksum0 += checksum0 >= 0xffff;
    1633           0 :   ip0_encap->checksum = checksum0;
    1634             : 
    1635             :   /* Outer IPv6: Update length, FL, proto */
    1636           0 :   new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
    1637           0 :   ip0->payload_length = clib_host_to_net_u16 (new_l0);
    1638           0 :   flow_label = ip4_compute_flow_hash (ip0_encap, IP_FLOW_HASH_DEFAULT);
    1639           0 :   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    1640           0 :     0 | ((6 & 0xF) << 28) | ((ip0_encap->tos & 0xFF) << 20) |
    1641           0 :     (flow_label & 0x0000ffff));
    1642           0 :   if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
    1643             :     {
    1644           0 :       sr0 = (void *) (ip0 + 1);
    1645           0 :       sr0->protocol = IP_PROTOCOL_IP_IN_IP;
    1646             :     }
    1647             :   else
    1648           0 :     ip0->protocol = IP_PROTOCOL_IP_IN_IP;
    1649           0 : }
    1650             : 
    1651             : /**
    1652             :  * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
    1653             :  */
    1654             : static uword
    1655           0 : sr_policy_rewrite_encaps_v4 (vlib_main_t * vm, vlib_node_runtime_t * node,
    1656             :                              vlib_frame_t * from_frame)
    1657             : {
    1658           0 :   ip6_sr_main_t *sm = &sr_main;
    1659             :   u32 n_left_from, next_index, *from, *to_next;
    1660             : 
    1661           0 :   from = vlib_frame_vector_args (from_frame);
    1662           0 :   n_left_from = from_frame->n_vectors;
    1663             : 
    1664           0 :   next_index = node->cached_next_index;
    1665             : 
    1666           0 :   int encap_pkts = 0, bsid_pkts = 0;
    1667             : 
    1668           0 :   while (n_left_from > 0)
    1669             :     {
    1670             :       u32 n_left_to_next;
    1671             : 
    1672           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1673             : 
    1674             :       /* Quad - Loop */
    1675           0 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    1676             :         {
    1677             :           u32 bi0, bi1, bi2, bi3;
    1678             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    1679             :           u32 next0, next1, next2, next3;
    1680           0 :           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    1681             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    1682             :           ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
    1683             :           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
    1684             : 
    1685             :           /* Prefetch next iteration. */
    1686             :           {
    1687             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    1688             : 
    1689           0 :             p4 = vlib_get_buffer (vm, from[4]);
    1690           0 :             p5 = vlib_get_buffer (vm, from[5]);
    1691           0 :             p6 = vlib_get_buffer (vm, from[6]);
    1692           0 :             p7 = vlib_get_buffer (vm, from[7]);
    1693             : 
    1694             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    1695           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    1696           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    1697           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    1698           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    1699             : 
    1700           0 :             clib_prefetch_store (p4->data);
    1701           0 :             clib_prefetch_store (p5->data);
    1702           0 :             clib_prefetch_store (p6->data);
    1703           0 :             clib_prefetch_store (p7->data);
    1704             :           }
    1705             : 
    1706           0 :           to_next[0] = bi0 = from[0];
    1707           0 :           to_next[1] = bi1 = from[1];
    1708           0 :           to_next[2] = bi2 = from[2];
    1709           0 :           to_next[3] = bi3 = from[3];
    1710           0 :           from += 4;
    1711           0 :           to_next += 4;
    1712           0 :           n_left_from -= 4;
    1713           0 :           n_left_to_next -= 4;
    1714             : 
    1715           0 :           b0 = vlib_get_buffer (vm, bi0);
    1716           0 :           b1 = vlib_get_buffer (vm, bi1);
    1717           0 :           b2 = vlib_get_buffer (vm, bi2);
    1718           0 :           b3 = vlib_get_buffer (vm, bi3);
    1719             : 
    1720           0 :           sl0 =
    1721           0 :             pool_elt_at_index (sm->sid_lists,
    1722             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1723           0 :           sl1 =
    1724           0 :             pool_elt_at_index (sm->sid_lists,
    1725             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    1726           0 :           sl2 =
    1727           0 :             pool_elt_at_index (sm->sid_lists,
    1728             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    1729           0 :           sl3 =
    1730           0 :             pool_elt_at_index (sm->sid_lists,
    1731             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    1732           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1733             :                   vec_len (sl0->rewrite));
    1734           0 :           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1735             :                   vec_len (sl1->rewrite));
    1736           0 :           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1737             :                   vec_len (sl2->rewrite));
    1738           0 :           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1739             :                   vec_len (sl3->rewrite));
    1740             : 
    1741           0 :           ip0_encap = vlib_buffer_get_current (b0);
    1742           0 :           ip1_encap = vlib_buffer_get_current (b1);
    1743           0 :           ip2_encap = vlib_buffer_get_current (b2);
    1744           0 :           ip3_encap = vlib_buffer_get_current (b3);
    1745             : 
    1746           0 :           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
    1747           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    1748           0 :           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
    1749           0 :                             sl1->rewrite, vec_len (sl1->rewrite));
    1750           0 :           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
    1751           0 :                             sl2->rewrite, vec_len (sl2->rewrite));
    1752           0 :           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
    1753           0 :                             sl3->rewrite, vec_len (sl3->rewrite));
    1754             : 
    1755           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    1756           0 :           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
    1757           0 :           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
    1758           0 :           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
    1759             : 
    1760           0 :           ip0 = vlib_buffer_get_current (b0);
    1761           0 :           ip1 = vlib_buffer_get_current (b1);
    1762           0 :           ip2 = vlib_buffer_get_current (b2);
    1763           0 :           ip3 = vlib_buffer_get_current (b3);
    1764             : 
    1765           0 :           encaps_processing_v4 (node, b0, ip0, ip0_encap);
    1766           0 :           encaps_processing_v4 (node, b1, ip1, ip1_encap);
    1767           0 :           encaps_processing_v4 (node, b2, ip2, ip2_encap);
    1768           0 :           encaps_processing_v4 (node, b3, ip3, ip3_encap);
    1769             : 
    1770           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
    1771           0 :           vnet_buffer (b1)->sw_if_index[VLIB_TX] = sl1->egress_fib_table;
    1772           0 :           vnet_buffer (b2)->sw_if_index[VLIB_TX] = sl2->egress_fib_table;
    1773           0 :           vnet_buffer (b3)->sw_if_index[VLIB_TX] = sl3->egress_fib_table;
    1774             : 
    1775           0 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    1776             :             {
    1777           0 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1778             :                 {
    1779             :                   sr_policy_rewrite_trace_t *tr =
    1780           0 :                     vlib_add_trace (vm, node, b0, sizeof (*tr));
    1781           0 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    1782             :                                     sizeof (tr->src.as_u8));
    1783           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    1784             :                                     sizeof (tr->dst.as_u8));
    1785             :                 }
    1786             : 
    1787           0 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    1788             :                 {
    1789             :                   sr_policy_rewrite_trace_t *tr =
    1790           0 :                     vlib_add_trace (vm, node, b1, sizeof (*tr));
    1791           0 :                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
    1792             :                                     sizeof (tr->src.as_u8));
    1793           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
    1794             :                                     sizeof (tr->dst.as_u8));
    1795             :                 }
    1796             : 
    1797           0 :               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    1798             :                 {
    1799             :                   sr_policy_rewrite_trace_t *tr =
    1800           0 :                     vlib_add_trace (vm, node, b2, sizeof (*tr));
    1801           0 :                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
    1802             :                                     sizeof (tr->src.as_u8));
    1803           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
    1804             :                                     sizeof (tr->dst.as_u8));
    1805             :                 }
    1806             : 
    1807           0 :               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    1808             :                 {
    1809             :                   sr_policy_rewrite_trace_t *tr =
    1810           0 :                     vlib_add_trace (vm, node, b3, sizeof (*tr));
    1811           0 :                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
    1812             :                                     sizeof (tr->src.as_u8));
    1813           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
    1814             :                                     sizeof (tr->dst.as_u8));
    1815             :                 }
    1816             :             }
    1817             : 
    1818           0 :           encap_pkts += 4;
    1819           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    1820             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    1821             :                                            next0, next1, next2, next3);
    1822             :         }
    1823             : 
    1824             :       /* Single loop for potentially the last three packets */
    1825           0 :       while (n_left_from > 0 && n_left_to_next > 0)
    1826             :         {
    1827             :           u32 bi0;
    1828             :           vlib_buffer_t *b0;
    1829           0 :           ip6_header_t *ip0 = 0;
    1830           0 :           ip4_header_t *ip0_encap = 0;
    1831             :           ip6_sr_sl_t *sl0;
    1832           0 :           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    1833             : 
    1834           0 :           bi0 = from[0];
    1835           0 :           to_next[0] = bi0;
    1836           0 :           from += 1;
    1837           0 :           to_next += 1;
    1838           0 :           n_left_from -= 1;
    1839           0 :           n_left_to_next -= 1;
    1840           0 :           b0 = vlib_get_buffer (vm, bi0);
    1841             : 
    1842           0 :           sl0 =
    1843           0 :             pool_elt_at_index (sm->sid_lists,
    1844             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    1845           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    1846             :                   vec_len (sl0->rewrite));
    1847             : 
    1848           0 :           ip0_encap = vlib_buffer_get_current (b0);
    1849             : 
    1850           0 :           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
    1851           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    1852           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    1853             : 
    1854           0 :           ip0 = vlib_buffer_get_current (b0);
    1855             : 
    1856           0 :           encaps_processing_v4 (node, b0, ip0, ip0_encap);
    1857             : 
    1858           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sl0->egress_fib_table;
    1859             : 
    1860           0 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
    1861           0 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    1862             :             {
    1863             :               sr_policy_rewrite_trace_t *tr =
    1864           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    1865           0 :               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    1866             :                                 sizeof (tr->src.as_u8));
    1867           0 :               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    1868             :                                 sizeof (tr->dst.as_u8));
    1869             :             }
    1870             : 
    1871           0 :           encap_pkts++;
    1872           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    1873             :                                            n_left_to_next, bi0, next0);
    1874             :         }
    1875             : 
    1876           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1877             :     }
    1878             : 
    1879             :   /* Update counters */
    1880           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    1881             :                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
    1882             :                                encap_pkts);
    1883           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    1884             :                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
    1885             :                                bsid_pkts);
    1886             : 
    1887           0 :   return from_frame->n_vectors;
    1888             : }
    1889             : 
    1890             : /* *INDENT-OFF* */
    1891      178120 : VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node) = {
    1892             :   .function = sr_policy_rewrite_encaps_v4,
    1893             :   .name = "sr-pl-rewrite-encaps-v4",
    1894             :   .vector_size = sizeof (u32),
    1895             :   .format_trace = format_sr_policy_rewrite_trace,
    1896             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1897             :   .n_errors = SR_POLICY_REWRITE_N_ERROR,
    1898             :   .error_strings = sr_policy_rewrite_error_strings,
    1899             :   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
    1900             :   .next_nodes = {
    1901             : #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
    1902             :     foreach_sr_policy_rewrite_next
    1903             : #undef _
    1904             :   },
    1905             : };
    1906             : /* *INDENT-ON* */
    1907             : 
    1908             : always_inline u32
    1909           0 : ip_flow_hash (void *data)
    1910             : {
    1911           0 :   ip4_header_t *iph = (ip4_header_t *) data;
    1912             : 
    1913           0 :   if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
    1914           0 :     return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
    1915             :   else
    1916           0 :     return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
    1917             : }
    1918             : 
    1919             : always_inline u64
    1920           0 : mac_to_u64 (u8 * m)
    1921             : {
    1922           0 :   return (*((u64 *) m) & 0xffffffffffff);
    1923             : }
    1924             : 
    1925             : always_inline u32
    1926           0 : l2_flow_hash (vlib_buffer_t * b0)
    1927             : {
    1928             :   ethernet_header_t *eh;
    1929             :   u64 a, b, c;
    1930             :   uword is_ip, eh_size;
    1931             :   u16 eh_type;
    1932             : 
    1933           0 :   eh = vlib_buffer_get_current (b0);
    1934           0 :   eh_type = clib_net_to_host_u16 (eh->type);
    1935           0 :   eh_size = ethernet_buffer_header_size (b0);
    1936             : 
    1937           0 :   is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
    1938             : 
    1939             :   /* since we have 2 cache lines, use them */
    1940           0 :   if (is_ip)
    1941           0 :     a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
    1942             :   else
    1943           0 :     a = eh->type;
    1944             : 
    1945           0 :   b = mac_to_u64 ((u8 *) eh->dst_address);
    1946           0 :   c = mac_to_u64 ((u8 *) eh->src_address);
    1947           0 :   hash_mix64 (a, b, c);
    1948             : 
    1949           0 :   return (u32) c;
    1950             : }
    1951             : 
    1952             : /**
    1953             :  * @brief Graph node for applying a SR policy into a L2 frame
    1954             :  */
    1955             : static uword
    1956           0 : sr_policy_rewrite_encaps_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
    1957             :                              vlib_frame_t * from_frame)
    1958             : {
    1959           0 :   ip6_sr_main_t *sm = &sr_main;
    1960             :   u32 n_left_from, next_index, *from, *to_next;
    1961             : 
    1962           0 :   from = vlib_frame_vector_args (from_frame);
    1963           0 :   n_left_from = from_frame->n_vectors;
    1964             : 
    1965           0 :   next_index = node->cached_next_index;
    1966             : 
    1967           0 :   int encap_pkts = 0, bsid_pkts = 0;
    1968             : 
    1969           0 :   while (n_left_from > 0)
    1970             :     {
    1971             :       u32 n_left_to_next;
    1972             : 
    1973           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    1974             : 
    1975             :       /* Quad - Loop */
    1976           0 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    1977             :         {
    1978             :           u32 bi0, bi1, bi2, bi3;
    1979             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    1980             :           u32 next0, next1, next2, next3;
    1981           0 :           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    1982             :           ethernet_header_t *en0, *en1, *en2, *en3;
    1983             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    1984             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    1985             :           ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
    1986             :           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
    1987             :           u32 flow_label0, flow_label1, flow_label2, flow_label3;
    1988             : 
    1989             :           /* Prefetch next iteration. */
    1990             :           {
    1991             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    1992             : 
    1993           0 :             p4 = vlib_get_buffer (vm, from[4]);
    1994           0 :             p5 = vlib_get_buffer (vm, from[5]);
    1995           0 :             p6 = vlib_get_buffer (vm, from[6]);
    1996           0 :             p7 = vlib_get_buffer (vm, from[7]);
    1997             : 
    1998             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    1999           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    2000           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    2001           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    2002           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    2003             : 
    2004           0 :             clib_prefetch_store (p4->data);
    2005           0 :             clib_prefetch_store (p5->data);
    2006           0 :             clib_prefetch_store (p6->data);
    2007           0 :             clib_prefetch_store (p7->data);
    2008             :           }
    2009             : 
    2010           0 :           to_next[0] = bi0 = from[0];
    2011           0 :           to_next[1] = bi1 = from[1];
    2012           0 :           to_next[2] = bi2 = from[2];
    2013           0 :           to_next[3] = bi3 = from[3];
    2014           0 :           from += 4;
    2015           0 :           to_next += 4;
    2016           0 :           n_left_from -= 4;
    2017           0 :           n_left_to_next -= 4;
    2018             : 
    2019           0 :           b0 = vlib_get_buffer (vm, bi0);
    2020           0 :           b1 = vlib_get_buffer (vm, bi1);
    2021           0 :           b2 = vlib_get_buffer (vm, bi2);
    2022           0 :           b3 = vlib_get_buffer (vm, bi3);
    2023             : 
    2024           0 :           sp0 = pool_elt_at_index (sm->sr_policies,
    2025             :                                    sm->sw_iface_sr_policies[vnet_buffer
    2026             :                                                             (b0)->sw_if_index
    2027             :                                                             [VLIB_RX]]);
    2028             : 
    2029           0 :           sp1 = pool_elt_at_index (sm->sr_policies,
    2030             :                                    sm->sw_iface_sr_policies[vnet_buffer
    2031             :                                                             (b1)->sw_if_index
    2032             :                                                             [VLIB_RX]]);
    2033             : 
    2034           0 :           sp2 = pool_elt_at_index (sm->sr_policies,
    2035             :                                    sm->sw_iface_sr_policies[vnet_buffer
    2036             :                                                             (b2)->sw_if_index
    2037             :                                                             [VLIB_RX]]);
    2038             : 
    2039           0 :           sp3 = pool_elt_at_index (sm->sr_policies,
    2040             :                                    sm->sw_iface_sr_policies[vnet_buffer
    2041             :                                                             (b3)->sw_if_index
    2042             :                                                             [VLIB_RX]]);
    2043           0 :           flow_label0 = l2_flow_hash (b0);
    2044           0 :           flow_label1 = l2_flow_hash (b1);
    2045           0 :           flow_label2 = l2_flow_hash (b2);
    2046           0 :           flow_label3 = l2_flow_hash (b3);
    2047             : 
    2048           0 :           if (vec_len (sp0->segments_lists) == 1)
    2049           0 :             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
    2050             :           else
    2051             :             {
    2052           0 :               vnet_buffer (b0)->ip.flow_hash = flow_label0;
    2053           0 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
    2054           0 :                 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
    2055           0 :                                      (vec_len (sp0->segments_lists) - 1))];
    2056             :             }
    2057             : 
    2058           0 :           if (vec_len (sp1->segments_lists) == 1)
    2059           0 :             vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
    2060             :           else
    2061             :             {
    2062           0 :               vnet_buffer (b1)->ip.flow_hash = flow_label1;
    2063           0 :               vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
    2064           0 :                 sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
    2065           0 :                                      (vec_len (sp1->segments_lists) - 1))];
    2066             :             }
    2067             : 
    2068           0 :           if (vec_len (sp2->segments_lists) == 1)
    2069           0 :             vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
    2070             :           else
    2071             :             {
    2072           0 :               vnet_buffer (b2)->ip.flow_hash = flow_label2;
    2073           0 :               vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
    2074           0 :                 sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
    2075           0 :                                      (vec_len (sp2->segments_lists) - 1))];
    2076             :             }
    2077             : 
    2078           0 :           if (vec_len (sp3->segments_lists) == 1)
    2079           0 :             vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
    2080             :           else
    2081             :             {
    2082           0 :               vnet_buffer (b3)->ip.flow_hash = flow_label3;
    2083           0 :               vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
    2084           0 :                 sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
    2085           0 :                                      (vec_len (sp3->segments_lists) - 1))];
    2086             :             }
    2087             : 
    2088           0 :           sl0 =
    2089           0 :             pool_elt_at_index (sm->sid_lists,
    2090             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2091           0 :           sl1 =
    2092           0 :             pool_elt_at_index (sm->sid_lists,
    2093             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    2094           0 :           sl2 =
    2095           0 :             pool_elt_at_index (sm->sid_lists,
    2096             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    2097           0 :           sl3 =
    2098           0 :             pool_elt_at_index (sm->sid_lists,
    2099             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    2100             : 
    2101           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2102             :                   vec_len (sl0->rewrite));
    2103           0 :           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2104             :                   vec_len (sl1->rewrite));
    2105           0 :           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2106             :                   vec_len (sl2->rewrite));
    2107           0 :           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2108             :                   vec_len (sl3->rewrite));
    2109             : 
    2110           0 :           en0 = vlib_buffer_get_current (b0);
    2111           0 :           en1 = vlib_buffer_get_current (b1);
    2112           0 :           en2 = vlib_buffer_get_current (b2);
    2113           0 :           en3 = vlib_buffer_get_current (b3);
    2114             : 
    2115           0 :           clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
    2116           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    2117           0 :           clib_memcpy_fast (((u8 *) en1) - vec_len (sl1->rewrite),
    2118           0 :                             sl1->rewrite, vec_len (sl1->rewrite));
    2119           0 :           clib_memcpy_fast (((u8 *) en2) - vec_len (sl2->rewrite),
    2120           0 :                             sl2->rewrite, vec_len (sl2->rewrite));
    2121           0 :           clib_memcpy_fast (((u8 *) en3) - vec_len (sl3->rewrite),
    2122           0 :                             sl3->rewrite, vec_len (sl3->rewrite));
    2123             : 
    2124           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    2125           0 :           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
    2126           0 :           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
    2127           0 :           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
    2128             : 
    2129           0 :           ip0 = vlib_buffer_get_current (b0);
    2130           0 :           ip1 = vlib_buffer_get_current (b1);
    2131           0 :           ip2 = vlib_buffer_get_current (b2);
    2132           0 :           ip3 = vlib_buffer_get_current (b3);
    2133             : 
    2134           0 :           ip0->payload_length =
    2135           0 :             clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
    2136           0 :           ip1->payload_length =
    2137           0 :             clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
    2138           0 :           ip2->payload_length =
    2139           0 :             clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
    2140           0 :           ip3->payload_length =
    2141           0 :             clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
    2142             : 
    2143           0 :           if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
    2144             :             {
    2145           0 :               sr0 = (void *) (ip0 + 1);
    2146           0 :               sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2147             :             }
    2148             :           else
    2149           0 :             ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2150             : 
    2151           0 :           if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
    2152             :             {
    2153           0 :               sr1 = (void *) (ip1 + 1);
    2154           0 :               sr1->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2155             :             }
    2156             :           else
    2157           0 :             ip1->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2158             : 
    2159           0 :           if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
    2160             :             {
    2161           0 :               sr2 = (void *) (ip2 + 1);
    2162           0 :               sr2->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2163             :             }
    2164             :           else
    2165           0 :             ip2->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2166             : 
    2167           0 :           if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
    2168             :             {
    2169           0 :               sr3 = (void *) (ip3 + 1);
    2170           0 :               sr3->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2171             :             }
    2172             :           else
    2173           0 :             ip3->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2174             : 
    2175             :           /* TC is set to 0 for all ethernet frames, should be taken from COS
    2176             :            * od DSCP of encapsulated packet in the future */
    2177           0 :           ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    2178           0 :             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
    2179           0 :           ip1->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    2180           0 :             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label1 & 0xffff));
    2181           0 :           ip2->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    2182           0 :             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label2 & 0xffff));
    2183           0 :           ip3->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    2184           0 :             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label3 & 0xffff));
    2185             : 
    2186           0 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    2187             :             {
    2188           0 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2189             :                 {
    2190             :                   sr_policy_rewrite_trace_t *tr =
    2191           0 :                     vlib_add_trace (vm, node, b0, sizeof (*tr));
    2192           0 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    2193             :                                     sizeof (tr->src.as_u8));
    2194           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    2195             :                                     sizeof (tr->dst.as_u8));
    2196             :                 }
    2197             : 
    2198           0 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    2199             :                 {
    2200             :                   sr_policy_rewrite_trace_t *tr =
    2201           0 :                     vlib_add_trace (vm, node, b1, sizeof (*tr));
    2202           0 :                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
    2203             :                                     sizeof (tr->src.as_u8));
    2204           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
    2205             :                                     sizeof (tr->dst.as_u8));
    2206             :                 }
    2207             : 
    2208           0 :               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    2209             :                 {
    2210             :                   sr_policy_rewrite_trace_t *tr =
    2211           0 :                     vlib_add_trace (vm, node, b2, sizeof (*tr));
    2212           0 :                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
    2213             :                                     sizeof (tr->src.as_u8));
    2214           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
    2215             :                                     sizeof (tr->dst.as_u8));
    2216             :                 }
    2217             : 
    2218           0 :               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    2219             :                 {
    2220             :                   sr_policy_rewrite_trace_t *tr =
    2221           0 :                     vlib_add_trace (vm, node, b3, sizeof (*tr));
    2222           0 :                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
    2223             :                                     sizeof (tr->src.as_u8));
    2224           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
    2225             :                                     sizeof (tr->dst.as_u8));
    2226             :                 }
    2227             :             }
    2228             : 
    2229           0 :           encap_pkts += 4;
    2230           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    2231             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    2232             :                                            next0, next1, next2, next3);
    2233             :         }
    2234             : 
    2235             :       /* Single loop for potentially the last three packets */
    2236           0 :       while (n_left_from > 0 && n_left_to_next > 0)
    2237             :         {
    2238             :           u32 bi0;
    2239             :           vlib_buffer_t *b0;
    2240           0 :           ip6_header_t *ip0 = 0;
    2241             :           ip6_sr_header_t *sr0;
    2242             :           ethernet_header_t *en0;
    2243             :           ip6_sr_policy_t *sp0;
    2244             :           ip6_sr_sl_t *sl0;
    2245           0 :           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    2246             :           u32 flow_label0;
    2247             : 
    2248           0 :           bi0 = from[0];
    2249           0 :           to_next[0] = bi0;
    2250           0 :           from += 1;
    2251           0 :           to_next += 1;
    2252           0 :           n_left_from -= 1;
    2253           0 :           n_left_to_next -= 1;
    2254           0 :           b0 = vlib_get_buffer (vm, bi0);
    2255             : 
    2256             :           /* Find the SR policy */
    2257           0 :           sp0 = pool_elt_at_index (sm->sr_policies,
    2258             :                                    sm->sw_iface_sr_policies[vnet_buffer
    2259             :                                                             (b0)->sw_if_index
    2260             :                                                             [VLIB_RX]]);
    2261           0 :           flow_label0 = l2_flow_hash (b0);
    2262             : 
    2263             :           /* In case there is more than one SL, LB among them */
    2264           0 :           if (vec_len (sp0->segments_lists) == 1)
    2265           0 :             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
    2266             :           else
    2267             :             {
    2268           0 :               vnet_buffer (b0)->ip.flow_hash = flow_label0;
    2269           0 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
    2270           0 :                 sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
    2271           0 :                                      (vec_len (sp0->segments_lists) - 1))];
    2272             :             }
    2273           0 :           sl0 =
    2274           0 :             pool_elt_at_index (sm->sid_lists,
    2275             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2276           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2277             :                   vec_len (sl0->rewrite));
    2278             : 
    2279           0 :           en0 = vlib_buffer_get_current (b0);
    2280             : 
    2281           0 :           clib_memcpy_fast (((u8 *) en0) - vec_len (sl0->rewrite),
    2282           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    2283             : 
    2284           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    2285             : 
    2286           0 :           ip0 = vlib_buffer_get_current (b0);
    2287             : 
    2288           0 :           ip0->payload_length =
    2289           0 :             clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
    2290             : 
    2291           0 :           if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
    2292             :             {
    2293           0 :               sr0 = (void *) (ip0 + 1);
    2294           0 :               sr0->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2295             :             }
    2296             :           else
    2297           0 :             ip0->protocol = IP_PROTOCOL_IP6_ETHERNET;
    2298             : 
    2299           0 :           ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (
    2300           0 :             0 | ((6 & 0xF) << 28) | ((0x00) << 20) | (flow_label0 & 0xffff));
    2301             : 
    2302           0 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
    2303           0 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2304             :             {
    2305             :               sr_policy_rewrite_trace_t *tr =
    2306           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    2307           0 :               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    2308             :                                 sizeof (tr->src.as_u8));
    2309           0 :               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    2310             :                                 sizeof (tr->dst.as_u8));
    2311             :             }
    2312             : 
    2313           0 :           encap_pkts++;
    2314           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    2315             :                                            n_left_to_next, bi0, next0);
    2316             :         }
    2317             : 
    2318           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    2319             :     }
    2320             : 
    2321             :   /* Update counters */
    2322           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    2323             :                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
    2324             :                                encap_pkts);
    2325           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    2326             :                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
    2327             :                                bsid_pkts);
    2328             : 
    2329           0 :   return from_frame->n_vectors;
    2330             : }
    2331             : 
    2332             : /* *INDENT-OFF* */
    2333      178120 : VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node) = {
    2334             :   .function = sr_policy_rewrite_encaps_l2,
    2335             :   .name = "sr-pl-rewrite-encaps-l2",
    2336             :   .vector_size = sizeof (u32),
    2337             :   .format_trace = format_sr_policy_rewrite_trace,
    2338             :   .type = VLIB_NODE_TYPE_INTERNAL,
    2339             :   .n_errors = SR_POLICY_REWRITE_N_ERROR,
    2340             :   .error_strings = sr_policy_rewrite_error_strings,
    2341             :   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
    2342             :   .next_nodes = {
    2343             : #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
    2344             :     foreach_sr_policy_rewrite_next
    2345             : #undef _
    2346             :   },
    2347             : };
    2348             : /* *INDENT-ON* */
    2349             : 
    2350             : /**
    2351             :  * @brief Graph node for applying a SR policy into a packet. SRH insertion.
    2352             :  */
    2353             : static uword
    2354           0 : sr_policy_rewrite_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
    2355             :                           vlib_frame_t * from_frame)
    2356             : {
    2357           0 :   ip6_sr_main_t *sm = &sr_main;
    2358             :   u32 n_left_from, next_index, *from, *to_next;
    2359             : 
    2360           0 :   from = vlib_frame_vector_args (from_frame);
    2361           0 :   n_left_from = from_frame->n_vectors;
    2362             : 
    2363           0 :   next_index = node->cached_next_index;
    2364             : 
    2365           0 :   int insert_pkts = 0, bsid_pkts = 0;
    2366             : 
    2367           0 :   while (n_left_from > 0)
    2368             :     {
    2369             :       u32 n_left_to_next;
    2370             : 
    2371           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    2372             : 
    2373             :       /* Quad - Loop */
    2374           0 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    2375             :         {
    2376             :           u32 bi0, bi1, bi2, bi3;
    2377             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    2378             :           u32 next0, next1, next2, next3;
    2379           0 :           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    2380             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    2381             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    2382             :           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
    2383             :           u16 new_l0, new_l1, new_l2, new_l3;
    2384             : 
    2385             :           /* Prefetch next iteration. */
    2386             :           {
    2387             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    2388             : 
    2389           0 :             p4 = vlib_get_buffer (vm, from[4]);
    2390           0 :             p5 = vlib_get_buffer (vm, from[5]);
    2391           0 :             p6 = vlib_get_buffer (vm, from[6]);
    2392           0 :             p7 = vlib_get_buffer (vm, from[7]);
    2393             : 
    2394             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    2395           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    2396           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    2397           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    2398           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    2399             : 
    2400           0 :             clib_prefetch_store (p4->data);
    2401           0 :             clib_prefetch_store (p5->data);
    2402           0 :             clib_prefetch_store (p6->data);
    2403           0 :             clib_prefetch_store (p7->data);
    2404             :           }
    2405             : 
    2406           0 :           to_next[0] = bi0 = from[0];
    2407           0 :           to_next[1] = bi1 = from[1];
    2408           0 :           to_next[2] = bi2 = from[2];
    2409           0 :           to_next[3] = bi3 = from[3];
    2410           0 :           from += 4;
    2411           0 :           to_next += 4;
    2412           0 :           n_left_from -= 4;
    2413           0 :           n_left_to_next -= 4;
    2414             : 
    2415           0 :           b0 = vlib_get_buffer (vm, bi0);
    2416           0 :           b1 = vlib_get_buffer (vm, bi1);
    2417           0 :           b2 = vlib_get_buffer (vm, bi2);
    2418           0 :           b3 = vlib_get_buffer (vm, bi3);
    2419             : 
    2420           0 :           sl0 =
    2421           0 :             pool_elt_at_index (sm->sid_lists,
    2422             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2423           0 :           sl1 =
    2424           0 :             pool_elt_at_index (sm->sid_lists,
    2425             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    2426           0 :           sl2 =
    2427           0 :             pool_elt_at_index (sm->sid_lists,
    2428             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    2429           0 :           sl3 =
    2430           0 :             pool_elt_at_index (sm->sid_lists,
    2431             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    2432           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2433             :                   vec_len (sl0->rewrite));
    2434           0 :           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2435             :                   vec_len (sl1->rewrite));
    2436           0 :           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2437             :                   vec_len (sl2->rewrite));
    2438           0 :           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2439             :                   vec_len (sl3->rewrite));
    2440             : 
    2441           0 :           ip0 = vlib_buffer_get_current (b0);
    2442           0 :           ip1 = vlib_buffer_get_current (b1);
    2443           0 :           ip2 = vlib_buffer_get_current (b2);
    2444           0 :           ip3 = vlib_buffer_get_current (b3);
    2445             : 
    2446           0 :           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2447           0 :             sr0 =
    2448           0 :               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
    2449           0 :                                    ip6_ext_header_len (ip0 + 1));
    2450             :           else
    2451           0 :             sr0 = (ip6_sr_header_t *) (ip0 + 1);
    2452             : 
    2453           0 :           if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2454           0 :             sr1 =
    2455           0 :               (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
    2456           0 :                                    ip6_ext_header_len (ip1 + 1));
    2457             :           else
    2458           0 :             sr1 = (ip6_sr_header_t *) (ip1 + 1);
    2459             : 
    2460           0 :           if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2461           0 :             sr2 =
    2462           0 :               (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
    2463           0 :                                    ip6_ext_header_len (ip2 + 1));
    2464             :           else
    2465           0 :             sr2 = (ip6_sr_header_t *) (ip2 + 1);
    2466             : 
    2467           0 :           if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2468           0 :             sr3 =
    2469           0 :               (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
    2470           0 :                                    ip6_ext_header_len (ip3 + 1));
    2471             :           else
    2472           0 :             sr3 = (ip6_sr_header_t *) (ip3 + 1);
    2473             : 
    2474           0 :           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
    2475           0 :                             (void *) sr0 - (void *) ip0);
    2476           0 :           clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
    2477           0 :                             (void *) sr1 - (void *) ip1);
    2478           0 :           clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
    2479           0 :                             (void *) sr2 - (void *) ip2);
    2480           0 :           clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
    2481           0 :                             (void *) sr3 - (void *) ip3);
    2482             : 
    2483           0 :           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
    2484           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    2485           0 :           clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite)),
    2486           0 :                             sl1->rewrite, vec_len (sl1->rewrite));
    2487           0 :           clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite)),
    2488           0 :                             sl2->rewrite, vec_len (sl2->rewrite));
    2489           0 :           clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite)),
    2490           0 :                             sl3->rewrite, vec_len (sl3->rewrite));
    2491             : 
    2492           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    2493           0 :           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
    2494           0 :           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
    2495           0 :           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
    2496             : 
    2497           0 :           ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
    2498           0 :           ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
    2499           0 :           ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
    2500           0 :           ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
    2501             : 
    2502           0 :           ip0->hop_limit -= 1;
    2503           0 :           ip1->hop_limit -= 1;
    2504           0 :           ip2->hop_limit -= 1;
    2505           0 :           ip3->hop_limit -= 1;
    2506             : 
    2507           0 :           new_l0 =
    2508           0 :             clib_net_to_host_u16 (ip0->payload_length) +
    2509           0 :             vec_len (sl0->rewrite);
    2510           0 :           new_l1 =
    2511           0 :             clib_net_to_host_u16 (ip1->payload_length) +
    2512           0 :             vec_len (sl1->rewrite);
    2513           0 :           new_l2 =
    2514           0 :             clib_net_to_host_u16 (ip2->payload_length) +
    2515           0 :             vec_len (sl2->rewrite);
    2516           0 :           new_l3 =
    2517           0 :             clib_net_to_host_u16 (ip3->payload_length) +
    2518           0 :             vec_len (sl3->rewrite);
    2519             : 
    2520           0 :           ip0->payload_length = clib_host_to_net_u16 (new_l0);
    2521           0 :           ip1->payload_length = clib_host_to_net_u16 (new_l1);
    2522           0 :           ip2->payload_length = clib_host_to_net_u16 (new_l2);
    2523           0 :           ip3->payload_length = clib_host_to_net_u16 (new_l3);
    2524             : 
    2525           0 :           sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
    2526           0 :           sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
    2527           0 :           sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
    2528           0 :           sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
    2529             : 
    2530           0 :           sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
    2531           0 :           sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
    2532           0 :           sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
    2533           0 :           sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
    2534           0 :           sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
    2535           0 :           sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
    2536           0 :           sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
    2537           0 :           sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
    2538             : 
    2539           0 :           ip0->dst_address.as_u64[0] =
    2540           0 :             (sr0->segments + sr0->segments_left)->as_u64[0];
    2541           0 :           ip0->dst_address.as_u64[1] =
    2542           0 :             (sr0->segments + sr0->segments_left)->as_u64[1];
    2543           0 :           ip1->dst_address.as_u64[0] =
    2544           0 :             (sr1->segments + sr1->segments_left)->as_u64[0];
    2545           0 :           ip1->dst_address.as_u64[1] =
    2546           0 :             (sr1->segments + sr1->segments_left)->as_u64[1];
    2547           0 :           ip2->dst_address.as_u64[0] =
    2548           0 :             (sr2->segments + sr2->segments_left)->as_u64[0];
    2549           0 :           ip2->dst_address.as_u64[1] =
    2550           0 :             (sr2->segments + sr2->segments_left)->as_u64[1];
    2551           0 :           ip3->dst_address.as_u64[0] =
    2552           0 :             (sr3->segments + sr3->segments_left)->as_u64[0];
    2553           0 :           ip3->dst_address.as_u64[1] =
    2554           0 :             (sr3->segments + sr3->segments_left)->as_u64[1];
    2555             : 
    2556             :           ip6_ext_header_t *ip_ext;
    2557           0 :           if (ip0 + 1 == (void *) sr0)
    2558             :             {
    2559           0 :               sr0->protocol = ip0->protocol;
    2560           0 :               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2561             :             }
    2562             :           else
    2563             :             {
    2564           0 :               ip_ext = (void *) (ip0 + 1);
    2565           0 :               sr0->protocol = ip_ext->next_hdr;
    2566           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2567             :             }
    2568             : 
    2569           0 :           if (ip1 + 1 == (void *) sr1)
    2570             :             {
    2571           0 :               sr1->protocol = ip1->protocol;
    2572           0 :               ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2573             :             }
    2574             :           else
    2575             :             {
    2576           0 :               ip_ext = (void *) (ip2 + 1);
    2577           0 :               sr2->protocol = ip_ext->next_hdr;
    2578           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2579             :             }
    2580             : 
    2581           0 :           if (ip2 + 1 == (void *) sr2)
    2582             :             {
    2583           0 :               sr2->protocol = ip2->protocol;
    2584           0 :               ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2585             :             }
    2586             :           else
    2587             :             {
    2588           0 :               ip_ext = (void *) (ip2 + 1);
    2589           0 :               sr2->protocol = ip_ext->next_hdr;
    2590           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2591             :             }
    2592             : 
    2593           0 :           if (ip3 + 1 == (void *) sr3)
    2594             :             {
    2595           0 :               sr3->protocol = ip3->protocol;
    2596           0 :               ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2597             :             }
    2598             :           else
    2599             :             {
    2600           0 :               ip_ext = (void *) (ip3 + 1);
    2601           0 :               sr3->protocol = ip_ext->next_hdr;
    2602           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2603             :             }
    2604             : 
    2605           0 :           insert_pkts += 4;
    2606             : 
    2607           0 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    2608             :             {
    2609           0 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2610             :                 {
    2611             :                   sr_policy_rewrite_trace_t *tr =
    2612           0 :                     vlib_add_trace (vm, node, b0, sizeof (*tr));
    2613           0 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    2614             :                                     sizeof (tr->src.as_u8));
    2615           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    2616             :                                     sizeof (tr->dst.as_u8));
    2617             :                 }
    2618             : 
    2619           0 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    2620             :                 {
    2621             :                   sr_policy_rewrite_trace_t *tr =
    2622           0 :                     vlib_add_trace (vm, node, b1, sizeof (*tr));
    2623           0 :                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
    2624             :                                     sizeof (tr->src.as_u8));
    2625           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
    2626             :                                     sizeof (tr->dst.as_u8));
    2627             :                 }
    2628             : 
    2629           0 :               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    2630             :                 {
    2631             :                   sr_policy_rewrite_trace_t *tr =
    2632           0 :                     vlib_add_trace (vm, node, b2, sizeof (*tr));
    2633           0 :                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
    2634             :                                     sizeof (tr->src.as_u8));
    2635           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
    2636             :                                     sizeof (tr->dst.as_u8));
    2637             :                 }
    2638             : 
    2639           0 :               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    2640             :                 {
    2641             :                   sr_policy_rewrite_trace_t *tr =
    2642           0 :                     vlib_add_trace (vm, node, b3, sizeof (*tr));
    2643           0 :                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
    2644             :                                     sizeof (tr->src.as_u8));
    2645           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
    2646             :                                     sizeof (tr->dst.as_u8));
    2647             :                 }
    2648             :             }
    2649             : 
    2650           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    2651             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    2652             :                                            next0, next1, next2, next3);
    2653             :         }
    2654             : 
    2655             :       /* Single loop for potentially the last three packets */
    2656           0 :       while (n_left_from > 0 && n_left_to_next > 0)
    2657             :         {
    2658             :           u32 bi0;
    2659             :           vlib_buffer_t *b0;
    2660           0 :           ip6_header_t *ip0 = 0;
    2661           0 :           ip6_sr_header_t *sr0 = 0;
    2662             :           ip6_sr_sl_t *sl0;
    2663           0 :           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    2664           0 :           u16 new_l0 = 0;
    2665             : 
    2666           0 :           bi0 = from[0];
    2667           0 :           to_next[0] = bi0;
    2668           0 :           from += 1;
    2669           0 :           to_next += 1;
    2670           0 :           n_left_from -= 1;
    2671           0 :           n_left_to_next -= 1;
    2672             : 
    2673           0 :           b0 = vlib_get_buffer (vm, bi0);
    2674           0 :           sl0 =
    2675           0 :             pool_elt_at_index (sm->sid_lists,
    2676             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2677           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2678             :                   vec_len (sl0->rewrite));
    2679             : 
    2680           0 :           ip0 = vlib_buffer_get_current (b0);
    2681             : 
    2682           0 :           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2683           0 :             sr0 =
    2684           0 :               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
    2685           0 :                                    ip6_ext_header_len (ip0 + 1));
    2686             :           else
    2687           0 :             sr0 = (ip6_sr_header_t *) (ip0 + 1);
    2688             : 
    2689           0 :           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
    2690           0 :                             (void *) sr0 - (void *) ip0);
    2691           0 :           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite)),
    2692           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    2693             : 
    2694           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    2695             : 
    2696           0 :           ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
    2697           0 :           ip0->hop_limit -= 1;
    2698           0 :           new_l0 =
    2699           0 :             clib_net_to_host_u16 (ip0->payload_length) +
    2700           0 :             vec_len (sl0->rewrite);
    2701           0 :           ip0->payload_length = clib_host_to_net_u16 (new_l0);
    2702             : 
    2703           0 :           sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
    2704           0 :           sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
    2705           0 :           sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
    2706             : 
    2707           0 :           ip0->dst_address.as_u64[0] =
    2708           0 :             (sr0->segments + sr0->segments_left)->as_u64[0];
    2709           0 :           ip0->dst_address.as_u64[1] =
    2710           0 :             (sr0->segments + sr0->segments_left)->as_u64[1];
    2711             : 
    2712           0 :           if (ip0 + 1 == (void *) sr0)
    2713             :             {
    2714           0 :               sr0->protocol = ip0->protocol;
    2715           0 :               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2716             :             }
    2717             :           else
    2718             :             {
    2719           0 :               ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
    2720           0 :               sr0->protocol = ip_ext->next_hdr;
    2721           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2722             :             }
    2723             : 
    2724           0 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
    2725           0 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    2726             :             {
    2727             :               sr_policy_rewrite_trace_t *tr =
    2728           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    2729           0 :               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    2730             :                                 sizeof (tr->src.as_u8));
    2731           0 :               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    2732             :                                 sizeof (tr->dst.as_u8));
    2733             :             }
    2734             : 
    2735           0 :           insert_pkts++;
    2736             : 
    2737           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    2738             :                                            n_left_to_next, bi0, next0);
    2739             :         }
    2740             : 
    2741           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    2742             :     }
    2743             : 
    2744             :   /* Update counters */
    2745           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
    2746             :                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
    2747             :                                insert_pkts);
    2748           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
    2749             :                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
    2750             :                                bsid_pkts);
    2751           0 :   return from_frame->n_vectors;
    2752             : }
    2753             : 
    2754             : /* *INDENT-OFF* */
    2755      178120 : VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node) = {
    2756             :   .function = sr_policy_rewrite_insert,
    2757             :   .name = "sr-pl-rewrite-insert",
    2758             :   .vector_size = sizeof (u32),
    2759             :   .format_trace = format_sr_policy_rewrite_trace,
    2760             :   .type = VLIB_NODE_TYPE_INTERNAL,
    2761             :   .n_errors = SR_POLICY_REWRITE_N_ERROR,
    2762             :   .error_strings = sr_policy_rewrite_error_strings,
    2763             :   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
    2764             :   .next_nodes = {
    2765             : #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
    2766             :     foreach_sr_policy_rewrite_next
    2767             : #undef _
    2768             :   },
    2769             : };
    2770             : /* *INDENT-ON* */
    2771             : 
    2772             : /**
    2773             :  * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
    2774             :  */
    2775             : static uword
    2776           0 : sr_policy_rewrite_b_insert (vlib_main_t * vm, vlib_node_runtime_t * node,
    2777             :                             vlib_frame_t * from_frame)
    2778             : {
    2779           0 :   ip6_sr_main_t *sm = &sr_main;
    2780             :   u32 n_left_from, next_index, *from, *to_next;
    2781             : 
    2782           0 :   from = vlib_frame_vector_args (from_frame);
    2783           0 :   n_left_from = from_frame->n_vectors;
    2784             : 
    2785           0 :   next_index = node->cached_next_index;
    2786             : 
    2787           0 :   int insert_pkts = 0, bsid_pkts = 0;
    2788             : 
    2789           0 :   while (n_left_from > 0)
    2790             :     {
    2791             :       u32 n_left_to_next;
    2792             : 
    2793           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    2794             : 
    2795             :       /* Quad - Loop */
    2796           0 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    2797             :         {
    2798             :           u32 bi0, bi1, bi2, bi3;
    2799             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    2800             :           u32 next0, next1, next2, next3;
    2801           0 :           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    2802             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    2803             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    2804             :           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
    2805             :           u16 new_l0, new_l1, new_l2, new_l3;
    2806             : 
    2807             :           /* Prefetch next iteration. */
    2808             :           {
    2809             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    2810             : 
    2811           0 :             p4 = vlib_get_buffer (vm, from[4]);
    2812           0 :             p5 = vlib_get_buffer (vm, from[5]);
    2813           0 :             p6 = vlib_get_buffer (vm, from[6]);
    2814           0 :             p7 = vlib_get_buffer (vm, from[7]);
    2815             : 
    2816             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    2817           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    2818           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    2819           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    2820           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    2821             : 
    2822           0 :             clib_prefetch_store (p4->data);
    2823           0 :             clib_prefetch_store (p5->data);
    2824           0 :             clib_prefetch_store (p6->data);
    2825           0 :             clib_prefetch_store (p7->data);
    2826             :           }
    2827             : 
    2828           0 :           to_next[0] = bi0 = from[0];
    2829           0 :           to_next[1] = bi1 = from[1];
    2830           0 :           to_next[2] = bi2 = from[2];
    2831           0 :           to_next[3] = bi3 = from[3];
    2832           0 :           from += 4;
    2833           0 :           to_next += 4;
    2834           0 :           n_left_from -= 4;
    2835           0 :           n_left_to_next -= 4;
    2836             : 
    2837           0 :           b0 = vlib_get_buffer (vm, bi0);
    2838           0 :           b1 = vlib_get_buffer (vm, bi1);
    2839           0 :           b2 = vlib_get_buffer (vm, bi2);
    2840           0 :           b3 = vlib_get_buffer (vm, bi3);
    2841             : 
    2842           0 :           sl0 =
    2843           0 :             pool_elt_at_index (sm->sid_lists,
    2844             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    2845           0 :           sl1 =
    2846           0 :             pool_elt_at_index (sm->sid_lists,
    2847             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    2848           0 :           sl2 =
    2849           0 :             pool_elt_at_index (sm->sid_lists,
    2850             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    2851           0 :           sl3 =
    2852           0 :             pool_elt_at_index (sm->sid_lists,
    2853             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    2854           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2855             :                   vec_len (sl0->rewrite_bsid));
    2856           0 :           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2857             :                   vec_len (sl1->rewrite_bsid));
    2858           0 :           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2859             :                   vec_len (sl2->rewrite_bsid));
    2860           0 :           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    2861             :                   vec_len (sl3->rewrite_bsid));
    2862             : 
    2863           0 :           ip0 = vlib_buffer_get_current (b0);
    2864           0 :           ip1 = vlib_buffer_get_current (b1);
    2865           0 :           ip2 = vlib_buffer_get_current (b2);
    2866           0 :           ip3 = vlib_buffer_get_current (b3);
    2867             : 
    2868           0 :           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2869           0 :             sr0 =
    2870           0 :               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
    2871           0 :                                    ip6_ext_header_len (ip0 + 1));
    2872             :           else
    2873           0 :             sr0 = (ip6_sr_header_t *) (ip0 + 1);
    2874             : 
    2875           0 :           if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2876           0 :             sr1 =
    2877           0 :               (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
    2878           0 :                                    ip6_ext_header_len (ip1 + 1));
    2879             :           else
    2880           0 :             sr1 = (ip6_sr_header_t *) (ip1 + 1);
    2881             : 
    2882           0 :           if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2883           0 :             sr2 =
    2884           0 :               (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
    2885           0 :                                    ip6_ext_header_len (ip2 + 1));
    2886             :           else
    2887           0 :             sr2 = (ip6_sr_header_t *) (ip2 + 1);
    2888             : 
    2889           0 :           if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    2890           0 :             sr3 =
    2891           0 :               (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
    2892           0 :                                    ip6_ext_header_len (ip3 + 1));
    2893             :           else
    2894           0 :             sr3 = (ip6_sr_header_t *) (ip3 + 1);
    2895             : 
    2896           0 :           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
    2897           0 :                             (u8 *) ip0, (void *) sr0 - (void *) ip0);
    2898           0 :           clib_memcpy_fast ((u8 *) ip1 - vec_len (sl1->rewrite_bsid),
    2899           0 :                             (u8 *) ip1, (void *) sr1 - (void *) ip1);
    2900           0 :           clib_memcpy_fast ((u8 *) ip2 - vec_len (sl2->rewrite_bsid),
    2901           0 :                             (u8 *) ip2, (void *) sr2 - (void *) ip2);
    2902           0 :           clib_memcpy_fast ((u8 *) ip3 - vec_len (sl3->rewrite_bsid),
    2903           0 :                             (u8 *) ip3, (void *) sr3 - (void *) ip3);
    2904             : 
    2905           0 :           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
    2906           0 :                             sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
    2907           0 :           clib_memcpy_fast (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
    2908           0 :                             sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
    2909           0 :           clib_memcpy_fast (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
    2910           0 :                             sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
    2911           0 :           clib_memcpy_fast (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
    2912           0 :                             sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
    2913             : 
    2914           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
    2915           0 :           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
    2916           0 :           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
    2917           0 :           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
    2918             : 
    2919           0 :           ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
    2920           0 :           ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
    2921           0 :           ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
    2922           0 :           ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
    2923             : 
    2924           0 :           ip0->hop_limit -= 1;
    2925           0 :           ip1->hop_limit -= 1;
    2926           0 :           ip2->hop_limit -= 1;
    2927           0 :           ip3->hop_limit -= 1;
    2928             : 
    2929           0 :           new_l0 =
    2930           0 :             clib_net_to_host_u16 (ip0->payload_length) +
    2931           0 :             vec_len (sl0->rewrite_bsid);
    2932           0 :           new_l1 =
    2933           0 :             clib_net_to_host_u16 (ip1->payload_length) +
    2934           0 :             vec_len (sl1->rewrite_bsid);
    2935           0 :           new_l2 =
    2936           0 :             clib_net_to_host_u16 (ip2->payload_length) +
    2937           0 :             vec_len (sl2->rewrite_bsid);
    2938           0 :           new_l3 =
    2939           0 :             clib_net_to_host_u16 (ip3->payload_length) +
    2940           0 :             vec_len (sl3->rewrite_bsid);
    2941             : 
    2942           0 :           ip0->payload_length = clib_host_to_net_u16 (new_l0);
    2943           0 :           ip1->payload_length = clib_host_to_net_u16 (new_l1);
    2944           0 :           ip2->payload_length = clib_host_to_net_u16 (new_l2);
    2945           0 :           ip3->payload_length = clib_host_to_net_u16 (new_l3);
    2946             : 
    2947           0 :           sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
    2948           0 :           sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
    2949           0 :           sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
    2950           0 :           sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
    2951             : 
    2952           0 :           ip0->dst_address.as_u64[0] =
    2953           0 :             (sr0->segments + sr0->segments_left)->as_u64[0];
    2954           0 :           ip0->dst_address.as_u64[1] =
    2955           0 :             (sr0->segments + sr0->segments_left)->as_u64[1];
    2956           0 :           ip1->dst_address.as_u64[0] =
    2957           0 :             (sr1->segments + sr1->segments_left)->as_u64[0];
    2958           0 :           ip1->dst_address.as_u64[1] =
    2959           0 :             (sr1->segments + sr1->segments_left)->as_u64[1];
    2960           0 :           ip2->dst_address.as_u64[0] =
    2961           0 :             (sr2->segments + sr2->segments_left)->as_u64[0];
    2962           0 :           ip2->dst_address.as_u64[1] =
    2963           0 :             (sr2->segments + sr2->segments_left)->as_u64[1];
    2964           0 :           ip3->dst_address.as_u64[0] =
    2965           0 :             (sr3->segments + sr3->segments_left)->as_u64[0];
    2966           0 :           ip3->dst_address.as_u64[1] =
    2967           0 :             (sr3->segments + sr3->segments_left)->as_u64[1];
    2968             : 
    2969             :           ip6_ext_header_t *ip_ext;
    2970           0 :           if (ip0 + 1 == (void *) sr0)
    2971             :             {
    2972           0 :               sr0->protocol = ip0->protocol;
    2973           0 :               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2974             :             }
    2975             :           else
    2976             :             {
    2977           0 :               ip_ext = (void *) (ip0 + 1);
    2978           0 :               sr0->protocol = ip_ext->next_hdr;
    2979           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2980             :             }
    2981             : 
    2982           0 :           if (ip1 + 1 == (void *) sr1)
    2983             :             {
    2984           0 :               sr1->protocol = ip1->protocol;
    2985           0 :               ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2986             :             }
    2987             :           else
    2988             :             {
    2989           0 :               ip_ext = (void *) (ip2 + 1);
    2990           0 :               sr2->protocol = ip_ext->next_hdr;
    2991           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    2992             :             }
    2993             : 
    2994           0 :           if (ip2 + 1 == (void *) sr2)
    2995             :             {
    2996           0 :               sr2->protocol = ip2->protocol;
    2997           0 :               ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
    2998             :             }
    2999             :           else
    3000             :             {
    3001           0 :               ip_ext = (void *) (ip2 + 1);
    3002           0 :               sr2->protocol = ip_ext->next_hdr;
    3003           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    3004             :             }
    3005             : 
    3006           0 :           if (ip3 + 1 == (void *) sr3)
    3007             :             {
    3008           0 :               sr3->protocol = ip3->protocol;
    3009           0 :               ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
    3010             :             }
    3011             :           else
    3012             :             {
    3013           0 :               ip_ext = (void *) (ip3 + 1);
    3014           0 :               sr3->protocol = ip_ext->next_hdr;
    3015           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    3016             :             }
    3017             : 
    3018           0 :           insert_pkts += 4;
    3019             : 
    3020           0 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    3021             :             {
    3022           0 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    3023             :                 {
    3024             :                   sr_policy_rewrite_trace_t *tr =
    3025           0 :                     vlib_add_trace (vm, node, b0, sizeof (*tr));
    3026           0 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    3027             :                                     sizeof (tr->src.as_u8));
    3028           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    3029             :                                     sizeof (tr->dst.as_u8));
    3030             :                 }
    3031             : 
    3032           0 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    3033             :                 {
    3034             :                   sr_policy_rewrite_trace_t *tr =
    3035           0 :                     vlib_add_trace (vm, node, b1, sizeof (*tr));
    3036           0 :                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
    3037             :                                     sizeof (tr->src.as_u8));
    3038           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
    3039             :                                     sizeof (tr->dst.as_u8));
    3040             :                 }
    3041             : 
    3042           0 :               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    3043             :                 {
    3044             :                   sr_policy_rewrite_trace_t *tr =
    3045           0 :                     vlib_add_trace (vm, node, b2, sizeof (*tr));
    3046           0 :                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
    3047             :                                     sizeof (tr->src.as_u8));
    3048           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
    3049             :                                     sizeof (tr->dst.as_u8));
    3050             :                 }
    3051             : 
    3052           0 :               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    3053             :                 {
    3054             :                   sr_policy_rewrite_trace_t *tr =
    3055           0 :                     vlib_add_trace (vm, node, b3, sizeof (*tr));
    3056           0 :                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
    3057             :                                     sizeof (tr->src.as_u8));
    3058           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
    3059             :                                     sizeof (tr->dst.as_u8));
    3060             :                 }
    3061             :             }
    3062             : 
    3063           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    3064             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    3065             :                                            next0, next1, next2, next3);
    3066             :         }
    3067             : 
    3068             :       /* Single loop for potentially the last three packets */
    3069           0 :       while (n_left_from > 0 && n_left_to_next > 0)
    3070             :         {
    3071             :           u32 bi0;
    3072             :           vlib_buffer_t *b0;
    3073           0 :           ip6_header_t *ip0 = 0;
    3074           0 :           ip6_sr_header_t *sr0 = 0;
    3075             :           ip6_sr_sl_t *sl0;
    3076           0 :           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    3077           0 :           u16 new_l0 = 0;
    3078             : 
    3079           0 :           bi0 = from[0];
    3080           0 :           to_next[0] = bi0;
    3081           0 :           from += 1;
    3082           0 :           to_next += 1;
    3083           0 :           n_left_from -= 1;
    3084           0 :           n_left_to_next -= 1;
    3085             : 
    3086           0 :           b0 = vlib_get_buffer (vm, bi0);
    3087           0 :           sl0 =
    3088           0 :             pool_elt_at_index (sm->sid_lists,
    3089             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    3090           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    3091             :                   vec_len (sl0->rewrite_bsid));
    3092             : 
    3093           0 :           ip0 = vlib_buffer_get_current (b0);
    3094             : 
    3095           0 :           if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
    3096           0 :             sr0 =
    3097           0 :               (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
    3098           0 :                                    ip6_ext_header_len (ip0 + 1));
    3099             :           else
    3100           0 :             sr0 = (ip6_sr_header_t *) (ip0 + 1);
    3101             : 
    3102           0 :           clib_memcpy_fast ((u8 *) ip0 - vec_len (sl0->rewrite_bsid),
    3103           0 :                             (u8 *) ip0, (void *) sr0 - (void *) ip0);
    3104           0 :           clib_memcpy_fast (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
    3105           0 :                             sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
    3106             : 
    3107           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
    3108             : 
    3109           0 :           ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
    3110           0 :           ip0->hop_limit -= 1;
    3111           0 :           new_l0 =
    3112           0 :             clib_net_to_host_u16 (ip0->payload_length) +
    3113           0 :             vec_len (sl0->rewrite_bsid);
    3114           0 :           ip0->payload_length = clib_host_to_net_u16 (new_l0);
    3115             : 
    3116           0 :           sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
    3117             : 
    3118           0 :           ip0->dst_address.as_u64[0] =
    3119           0 :             (sr0->segments + sr0->segments_left)->as_u64[0];
    3120           0 :           ip0->dst_address.as_u64[1] =
    3121           0 :             (sr0->segments + sr0->segments_left)->as_u64[1];
    3122             : 
    3123           0 :           if (ip0 + 1 == (void *) sr0)
    3124             :             {
    3125           0 :               sr0->protocol = ip0->protocol;
    3126           0 :               ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
    3127             :             }
    3128             :           else
    3129             :             {
    3130           0 :               ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
    3131           0 :               sr0->protocol = ip_ext->next_hdr;
    3132           0 :               ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
    3133             :             }
    3134             : 
    3135           0 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
    3136           0 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    3137             :             {
    3138             :               sr_policy_rewrite_trace_t *tr =
    3139           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    3140           0 :               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    3141             :                                 sizeof (tr->src.as_u8));
    3142           0 :               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    3143             :                                 sizeof (tr->dst.as_u8));
    3144             :             }
    3145             : 
    3146           0 :           insert_pkts++;
    3147             : 
    3148           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    3149             :                                            n_left_to_next, bi0, next0);
    3150             :         }
    3151             : 
    3152           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    3153             :     }
    3154             : 
    3155             :   /* Update counters */
    3156           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
    3157             :                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
    3158             :                                insert_pkts);
    3159           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_insert_node.index,
    3160             :                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
    3161             :                                bsid_pkts);
    3162           0 :   return from_frame->n_vectors;
    3163             : }
    3164             : 
    3165             : /* *INDENT-OFF* */
    3166      178120 : VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node) = {
    3167             :   .function = sr_policy_rewrite_b_insert,
    3168             :   .name = "sr-pl-rewrite-b-insert",
    3169             :   .vector_size = sizeof (u32),
    3170             :   .format_trace = format_sr_policy_rewrite_trace,
    3171             :   .type = VLIB_NODE_TYPE_INTERNAL,
    3172             :   .n_errors = SR_POLICY_REWRITE_N_ERROR,
    3173             :   .error_strings = sr_policy_rewrite_error_strings,
    3174             :   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
    3175             :   .next_nodes = {
    3176             : #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
    3177             :     foreach_sr_policy_rewrite_next
    3178             : #undef _
    3179             :   },
    3180             : };
    3181             : /* *INDENT-ON* */
    3182             : 
    3183             : /**
    3184             :  * @brief Function BSID encapsulation
    3185             :  */
    3186             : static_always_inline void
    3187           0 : end_bsid_encaps_srh_processing (vlib_node_runtime_t *node, vlib_buffer_t *b0,
    3188             :                                 ip6_header_t *ip0, ip6_sr_header_t *sr0,
    3189             :                                 u32 *next0, u8 policy_type)
    3190             : {
    3191             :   ip6_address_t *new_dst0;
    3192             : 
    3193           0 :   if (PREDICT_FALSE (!sr0))
    3194           0 :     goto error_bsid_encaps;
    3195             : 
    3196           0 :   if (PREDICT_TRUE (sr0->type == ROUTING_HEADER_TYPE_SR))
    3197             :     {
    3198           0 :       if (PREDICT_TRUE (sr0->segments_left != 0))
    3199             :         {
    3200           0 :           sr0->segments_left -= 1;
    3201           0 :           new_dst0 = (ip6_address_t *) (sr0->segments);
    3202           0 :           new_dst0 += sr0->segments_left;
    3203           0 :           ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
    3204           0 :           ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
    3205           0 :           return;
    3206             :         }
    3207           0 :       else if (sr0->segments_left == 0 && policy_type == SR_POLICY_TYPE_TEF)
    3208           0 :         return;
    3209             :     }
    3210             : 
    3211           0 : error_bsid_encaps:
    3212           0 :   *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
    3213           0 :   b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
    3214             : }
    3215             : 
    3216             : /**
    3217             :  * @brief Graph node for applying a SR policy BSID - Encapsulation
    3218             :  */
    3219             : static uword
    3220           0 : sr_policy_rewrite_b_encaps (vlib_main_t * vm, vlib_node_runtime_t * node,
    3221             :                             vlib_frame_t * from_frame)
    3222             : {
    3223           0 :   ip6_sr_main_t *sm = &sr_main;
    3224             :   u32 n_left_from, next_index, *from, *to_next;
    3225             : 
    3226           0 :   from = vlib_frame_vector_args (from_frame);
    3227           0 :   n_left_from = from_frame->n_vectors;
    3228             : 
    3229           0 :   next_index = node->cached_next_index;
    3230             : 
    3231           0 :   int encap_pkts = 0, bsid_pkts = 0;
    3232             : 
    3233           0 :   while (n_left_from > 0)
    3234             :     {
    3235             :       u32 n_left_to_next;
    3236             : 
    3237           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    3238             : 
    3239             :       /* Quad - Loop */
    3240           0 :       while (n_left_from >= 8 && n_left_to_next >= 4)
    3241             :         {
    3242             :           u32 bi0, bi1, bi2, bi3;
    3243             :           vlib_buffer_t *b0, *b1, *b2, *b3;
    3244             :           u32 next0, next1, next2, next3;
    3245           0 :           next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    3246             :           ip6_header_t *ip0, *ip1, *ip2, *ip3;
    3247             :           ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
    3248             :           ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
    3249             :           ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
    3250             : 
    3251             :           /* Prefetch next iteration. */
    3252             :           {
    3253             :             vlib_buffer_t *p4, *p5, *p6, *p7;
    3254             : 
    3255           0 :             p4 = vlib_get_buffer (vm, from[4]);
    3256           0 :             p5 = vlib_get_buffer (vm, from[5]);
    3257           0 :             p6 = vlib_get_buffer (vm, from[6]);
    3258           0 :             p7 = vlib_get_buffer (vm, from[7]);
    3259             : 
    3260             :             /* Prefetch the buffer header and packet for the N+2 loop iteration */
    3261           0 :             vlib_prefetch_buffer_header (p4, LOAD);
    3262           0 :             vlib_prefetch_buffer_header (p5, LOAD);
    3263           0 :             vlib_prefetch_buffer_header (p6, LOAD);
    3264           0 :             vlib_prefetch_buffer_header (p7, LOAD);
    3265             : 
    3266           0 :             clib_prefetch_store (p4->data);
    3267           0 :             clib_prefetch_store (p5->data);
    3268           0 :             clib_prefetch_store (p6->data);
    3269           0 :             clib_prefetch_store (p7->data);
    3270             :           }
    3271             : 
    3272           0 :           to_next[0] = bi0 = from[0];
    3273           0 :           to_next[1] = bi1 = from[1];
    3274           0 :           to_next[2] = bi2 = from[2];
    3275           0 :           to_next[3] = bi3 = from[3];
    3276           0 :           from += 4;
    3277           0 :           to_next += 4;
    3278           0 :           n_left_from -= 4;
    3279           0 :           n_left_to_next -= 4;
    3280             : 
    3281           0 :           b0 = vlib_get_buffer (vm, bi0);
    3282           0 :           b1 = vlib_get_buffer (vm, bi1);
    3283           0 :           b2 = vlib_get_buffer (vm, bi2);
    3284           0 :           b3 = vlib_get_buffer (vm, bi3);
    3285             : 
    3286           0 :           sl0 =
    3287           0 :             pool_elt_at_index (sm->sid_lists,
    3288             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    3289           0 :           sl1 =
    3290           0 :             pool_elt_at_index (sm->sid_lists,
    3291             :                                vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
    3292           0 :           sl2 =
    3293           0 :             pool_elt_at_index (sm->sid_lists,
    3294             :                                vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
    3295           0 :           sl3 =
    3296           0 :             pool_elt_at_index (sm->sid_lists,
    3297             :                                vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
    3298           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    3299             :                   vec_len (sl0->rewrite));
    3300           0 :           ASSERT (b1->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    3301             :                   vec_len (sl1->rewrite));
    3302           0 :           ASSERT (b2->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    3303             :                   vec_len (sl2->rewrite));
    3304           0 :           ASSERT (b3->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    3305             :                   vec_len (sl3->rewrite));
    3306             : 
    3307           0 :           ip0_encap = vlib_buffer_get_current (b0);
    3308           0 :           ip1_encap = vlib_buffer_get_current (b1);
    3309           0 :           ip2_encap = vlib_buffer_get_current (b2);
    3310           0 :           ip3_encap = vlib_buffer_get_current (b3);
    3311             : 
    3312             :           sr0 =
    3313           0 :             ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
    3314             :                                  NULL);
    3315             :           sr1 =
    3316           0 :             ip6_ext_header_find (vm, b1, ip1_encap, IP_PROTOCOL_IPV6_ROUTE,
    3317             :                                  NULL);
    3318             :           sr2 =
    3319           0 :             ip6_ext_header_find (vm, b2, ip2_encap, IP_PROTOCOL_IPV6_ROUTE,
    3320             :                                  NULL);
    3321             :           sr3 =
    3322           0 :             ip6_ext_header_find (vm, b3, ip3_encap, IP_PROTOCOL_IPV6_ROUTE,
    3323             :                                  NULL);
    3324             : 
    3325           0 :           end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
    3326           0 :                                           sl0->policy_type);
    3327           0 :           end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1,
    3328           0 :                                           sl1->policy_type);
    3329           0 :           end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2,
    3330           0 :                                           sl2->policy_type);
    3331           0 :           end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3,
    3332           0 :                                           sl3->policy_type);
    3333             : 
    3334           0 :           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
    3335           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    3336           0 :           clib_memcpy_fast (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
    3337           0 :                             sl1->rewrite, vec_len (sl1->rewrite));
    3338           0 :           clib_memcpy_fast (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
    3339           0 :                             sl2->rewrite, vec_len (sl2->rewrite));
    3340           0 :           clib_memcpy_fast (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
    3341           0 :                             sl3->rewrite, vec_len (sl3->rewrite));
    3342             : 
    3343           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    3344           0 :           vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
    3345           0 :           vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
    3346           0 :           vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
    3347             : 
    3348           0 :           ip0 = vlib_buffer_get_current (b0);
    3349           0 :           ip1 = vlib_buffer_get_current (b1);
    3350           0 :           ip2 = vlib_buffer_get_current (b2);
    3351           0 :           ip3 = vlib_buffer_get_current (b3);
    3352             : 
    3353           0 :           encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
    3354           0 :           encaps_processing_v6 (node, b1, ip1, ip1_encap, sl1->policy_type);
    3355           0 :           encaps_processing_v6 (node, b2, ip2, ip2_encap, sl2->policy_type);
    3356           0 :           encaps_processing_v6 (node, b3, ip3, ip3_encap, sl3->policy_type);
    3357             : 
    3358           0 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
    3359             :             {
    3360           0 :               if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    3361             :                 {
    3362             :                   sr_policy_rewrite_trace_t *tr =
    3363           0 :                     vlib_add_trace (vm, node, b0, sizeof (*tr));
    3364           0 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    3365             :                                     sizeof (tr->src.as_u8));
    3366           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    3367             :                                     sizeof (tr->dst.as_u8));
    3368             :                 }
    3369             : 
    3370           0 :               if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
    3371             :                 {
    3372             :                   sr_policy_rewrite_trace_t *tr =
    3373           0 :                     vlib_add_trace (vm, node, b1, sizeof (*tr));
    3374           0 :                   clib_memcpy_fast (tr->src.as_u8, ip1->src_address.as_u8,
    3375             :                                     sizeof (tr->src.as_u8));
    3376           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip1->dst_address.as_u8,
    3377             :                                     sizeof (tr->dst.as_u8));
    3378             :                 }
    3379             : 
    3380           0 :               if (PREDICT_FALSE (b2->flags & VLIB_BUFFER_IS_TRACED))
    3381             :                 {
    3382             :                   sr_policy_rewrite_trace_t *tr =
    3383           0 :                     vlib_add_trace (vm, node, b2, sizeof (*tr));
    3384           0 :                   clib_memcpy_fast (tr->src.as_u8, ip2->src_address.as_u8,
    3385             :                                     sizeof (tr->src.as_u8));
    3386           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip2->dst_address.as_u8,
    3387             :                                     sizeof (tr->dst.as_u8));
    3388             :                 }
    3389             : 
    3390           0 :               if (PREDICT_FALSE (b3->flags & VLIB_BUFFER_IS_TRACED))
    3391             :                 {
    3392             :                   sr_policy_rewrite_trace_t *tr =
    3393           0 :                     vlib_add_trace (vm, node, b3, sizeof (*tr));
    3394           0 :                   clib_memcpy_fast (tr->src.as_u8, ip3->src_address.as_u8,
    3395             :                                     sizeof (tr->src.as_u8));
    3396           0 :                   clib_memcpy_fast (tr->dst.as_u8, ip3->dst_address.as_u8,
    3397             :                                     sizeof (tr->dst.as_u8));
    3398             :                 }
    3399             :             }
    3400             : 
    3401           0 :           encap_pkts += 4;
    3402           0 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
    3403             :                                            n_left_to_next, bi0, bi1, bi2, bi3,
    3404             :                                            next0, next1, next2, next3);
    3405             :         }
    3406             : 
    3407             :       /* Single loop for potentially the last three packets */
    3408           0 :       while (n_left_from > 0 && n_left_to_next > 0)
    3409             :         {
    3410             :           u32 bi0;
    3411             :           vlib_buffer_t *b0;
    3412           0 :           ip6_header_t *ip0 = 0, *ip0_encap = 0;
    3413             :           ip6_sr_header_t *sr0;
    3414             :           ip6_sr_sl_t *sl0;
    3415           0 :           u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
    3416             : 
    3417           0 :           bi0 = from[0];
    3418           0 :           to_next[0] = bi0;
    3419           0 :           from += 1;
    3420           0 :           to_next += 1;
    3421           0 :           n_left_from -= 1;
    3422           0 :           n_left_to_next -= 1;
    3423           0 :           b0 = vlib_get_buffer (vm, bi0);
    3424             : 
    3425           0 :           sl0 =
    3426           0 :             pool_elt_at_index (sm->sid_lists,
    3427             :                                vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
    3428           0 :           ASSERT (b0->current_data + VLIB_BUFFER_PRE_DATA_SIZE >=
    3429             :                   vec_len (sl0->rewrite));
    3430             : 
    3431           0 :           ip0_encap = vlib_buffer_get_current (b0);
    3432             :           sr0 =
    3433           0 :             ip6_ext_header_find (vm, b0, ip0_encap, IP_PROTOCOL_IPV6_ROUTE,
    3434             :                                  NULL);
    3435           0 :           end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0,
    3436           0 :                                           sl0->policy_type);
    3437             : 
    3438           0 :           clib_memcpy_fast (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
    3439           0 :                             sl0->rewrite, vec_len (sl0->rewrite));
    3440           0 :           vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
    3441             : 
    3442           0 :           ip0 = vlib_buffer_get_current (b0);
    3443             : 
    3444           0 :           encaps_processing_v6 (node, b0, ip0, ip0_encap, sl0->policy_type);
    3445             : 
    3446           0 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
    3447           0 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
    3448             :             {
    3449             :               sr_policy_rewrite_trace_t *tr =
    3450           0 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
    3451           0 :               clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
    3452             :                                 sizeof (tr->src.as_u8));
    3453           0 :               clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
    3454             :                                 sizeof (tr->dst.as_u8));
    3455             :             }
    3456             : 
    3457           0 :           encap_pkts++;
    3458           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    3459             :                                            n_left_to_next, bi0, next0);
    3460             :         }
    3461             : 
    3462           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    3463             :     }
    3464             : 
    3465             :   /* Update counters */
    3466           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    3467             :                                SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
    3468             :                                encap_pkts);
    3469           0 :   vlib_node_increment_counter (vm, sr_policy_rewrite_encaps_node.index,
    3470             :                                SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
    3471             :                                bsid_pkts);
    3472             : 
    3473           0 :   return from_frame->n_vectors;
    3474             : }
    3475             : 
    3476             : /* *INDENT-OFF* */
    3477      178120 : VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node) = {
    3478             :   .function = sr_policy_rewrite_b_encaps,
    3479             :   .name = "sr-pl-rewrite-b-encaps",
    3480             :   .vector_size = sizeof (u32),
    3481             :   .format_trace = format_sr_policy_rewrite_trace,
    3482             :   .type = VLIB_NODE_TYPE_INTERNAL,
    3483             :   .n_errors = SR_POLICY_REWRITE_N_ERROR,
    3484             :   .error_strings = sr_policy_rewrite_error_strings,
    3485             :   .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
    3486             :   .next_nodes = {
    3487             : #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
    3488             :     foreach_sr_policy_rewrite_next
    3489             : #undef _
    3490             :   },
    3491             : };
    3492             : /* *INDENT-ON* */
    3493             : 
    3494             : /*************************** SR Policy plugins ******************************/
    3495             : /**
    3496             :  * @brief SR Policy plugin registry
    3497             :  */
    3498             : int
    3499        1677 : sr_policy_register_function (vlib_main_t * vm, u8 * fn_name,
    3500             :                              u8 * keyword_str, u8 * def_str,
    3501             :                              u8 * params_str, u8 prefix_length,
    3502             :                              dpo_type_t * dpo,
    3503             :                              format_function_t * ls_format,
    3504             :                              unformat_function_t * ls_unformat,
    3505             :                              sr_p_plugin_callback_t * creation_fn,
    3506             :                              sr_p_plugin_callback_t * removal_fn)
    3507             : {
    3508        1677 :   ip6_sr_main_t *sm = &sr_main;
    3509             :   uword *p;
    3510             : 
    3511             :   sr_policy_fn_registration_t *plugin;
    3512             : 
    3513             :   /* Did this function exist? If so update it */
    3514        1677 :   p = hash_get_mem (sm->policy_plugin_functions_by_key, fn_name);
    3515        1677 :   if (p)
    3516             :     {
    3517           0 :       plugin = pool_elt_at_index (sm->policy_plugin_functions, p[0]);
    3518             :     }
    3519             :   /* Else create a new one and set hash key */
    3520             :   else
    3521             :     {
    3522        1677 :       pool_get (sm->policy_plugin_functions, plugin);
    3523        3354 :       hash_set_mem (sm->policy_plugin_functions_by_key, fn_name,
    3524             :                     plugin - sm->policy_plugin_functions);
    3525             :     }
    3526             : 
    3527        1677 :   clib_memset (plugin, 0, sizeof (*plugin));
    3528             : 
    3529        1677 :   plugin->sr_policy_function_number = (plugin - sm->policy_plugin_functions);
    3530        1677 :   plugin->sr_policy_function_number += SR_BEHAVIOR_LAST;
    3531        1677 :   plugin->prefix_length = prefix_length;
    3532        1677 :   plugin->ls_format = ls_format;
    3533        1677 :   plugin->ls_unformat = ls_unformat;
    3534        1677 :   plugin->creation = creation_fn;
    3535        1677 :   plugin->removal = removal_fn;
    3536        1677 :   clib_memcpy (&plugin->dpo, dpo, sizeof (dpo_type_t));
    3537        1677 :   plugin->function_name = format (0, "%s%c", fn_name, 0);
    3538        1677 :   plugin->keyword_str = format (0, "%s%c", keyword_str, 0);
    3539        1677 :   plugin->def_str = format (0, "%s%c", def_str, 0);
    3540        1677 :   plugin->params_str = format (0, "%s%c", params_str, 0);
    3541             : 
    3542        1677 :   return plugin->sr_policy_function_number;
    3543             : }
    3544             : 
    3545             : /**
    3546             :  * @brief CLI function to 'show' all available SR LocalSID behaviors
    3547             :  */
    3548             : static clib_error_t *
    3549           0 : show_sr_policy_behaviors_command_fn (vlib_main_t * vm,
    3550             :                                      unformat_input_t * input,
    3551             :                                      vlib_cli_command_t * cmd)
    3552             : {
    3553           0 :   ip6_sr_main_t *sm = &sr_main;
    3554             :   sr_policy_fn_registration_t *plugin;
    3555           0 :   sr_policy_fn_registration_t **plugins_vec = 0;
    3556             :   int i;
    3557             : 
    3558           0 :   vlib_cli_output (vm, "SR Policy behaviors:\n-----------------------\n\n");
    3559             : 
    3560             :   /* *INDENT-OFF* */
    3561           0 :   pool_foreach (plugin, sm->policy_plugin_functions)
    3562           0 :      { vec_add1 (plugins_vec, plugin); }
    3563             :   /* *INDENT-ON* */
    3564             : 
    3565           0 :   vlib_cli_output (vm, "Plugin behaviors:\n");
    3566           0 :   for (i = 0; i < vec_len (plugins_vec); i++)
    3567             :     {
    3568           0 :       plugin = plugins_vec[i];
    3569           0 :       vlib_cli_output (vm, "\t%s\t-> %s.\n", plugin->keyword_str,
    3570             :                        plugin->def_str);
    3571           0 :       vlib_cli_output (vm, "\t\tParameters: '%s'\n", plugin->params_str);
    3572             :     }
    3573           0 :   return 0;
    3574             : }
    3575             : 
    3576             : /* *INDENT-OFF* */
    3577      272887 : VLIB_CLI_COMMAND (show_sr_policy_behaviors_command, static) = {
    3578             :   .path = "show sr policy behaviors",
    3579             :   .short_help = "show sr policy behaviors",
    3580             :   .function = show_sr_policy_behaviors_command_fn,
    3581             : };
    3582             : /* *INDENT-ON* */
    3583             : 
    3584             : /*************************** SR Segment Lists DPOs ****************************/
    3585             : static u8 *
    3586           0 : format_sr_segment_list_dpo (u8 * s, va_list * args)
    3587             : {
    3588           0 :   ip6_sr_main_t *sm = &sr_main;
    3589             :   ip6_address_t *addr;
    3590             :   ip6_sr_sl_t *sl;
    3591             : 
    3592           0 :   index_t index = va_arg (*args, index_t);
    3593           0 :   CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
    3594           0 :   s = format (s, "SR: Segment List index:[%d]", index);
    3595           0 :   s = format (s, "\n\tSegments:");
    3596             : 
    3597           0 :   sl = pool_elt_at_index (sm->sid_lists, index);
    3598             : 
    3599           0 :   s = format (s, "< ");
    3600           0 :   vec_foreach (addr, sl->segments)
    3601             :   {
    3602           0 :     s = format (s, "%U, ", format_ip6_address, addr);
    3603             :   }
    3604           0 :   s = format (s, "\b\b > - ");
    3605           0 :   s = format (s, "Weight: %u", sl->weight);
    3606             : 
    3607           0 :   return s;
    3608             : }
    3609             : 
    3610             : const static dpo_vft_t sr_policy_rewrite_vft = {
    3611             :   .dv_lock = sr_dpo_lock,
    3612             :   .dv_unlock = sr_dpo_unlock,
    3613             :   .dv_format = format_sr_segment_list_dpo,
    3614             : };
    3615             : 
    3616             : const static char *const sr_pr_encaps_ip6_nodes[] = {
    3617             :   "sr-pl-rewrite-encaps",
    3618             :   NULL,
    3619             : };
    3620             : 
    3621             : const static char *const sr_pr_encaps_ip4_nodes[] = {
    3622             :   "sr-pl-rewrite-encaps-v4",
    3623             :   NULL,
    3624             : };
    3625             : 
    3626             : const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
    3627             :   [DPO_PROTO_IP6] = sr_pr_encaps_ip6_nodes,
    3628             :   [DPO_PROTO_IP4] = sr_pr_encaps_ip4_nodes,
    3629             : };
    3630             : 
    3631             : const static char *const sr_pr_insert_ip6_nodes[] = {
    3632             :   "sr-pl-rewrite-insert",
    3633             :   NULL,
    3634             : };
    3635             : 
    3636             : const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
    3637             :   [DPO_PROTO_IP6] = sr_pr_insert_ip6_nodes,
    3638             : };
    3639             : 
    3640             : const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
    3641             :   "sr-pl-rewrite-b-insert",
    3642             :   NULL,
    3643             : };
    3644             : 
    3645             : const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
    3646             :   [DPO_PROTO_IP6] = sr_pr_bsid_insert_ip6_nodes,
    3647             : };
    3648             : 
    3649             : const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
    3650             :   "sr-pl-rewrite-b-encaps",
    3651             :   NULL,
    3652             : };
    3653             : 
    3654             : const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
    3655             :   [DPO_PROTO_IP6] = sr_pr_bsid_encaps_ip6_nodes,
    3656             : };
    3657             : 
    3658             : /********************* SR Policy Rewrite initialization ***********************/
    3659             : /**
    3660             :  * @brief SR Policy Rewrite initialization
    3661             :  */
    3662             : clib_error_t *
    3663         559 : sr_policy_rewrite_init (vlib_main_t * vm)
    3664             : {
    3665         559 :   ip6_sr_main_t *sm = &sr_main;
    3666             : 
    3667             :   /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
    3668         559 :   mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
    3669             :               sizeof (ip6_address_t));
    3670             : 
    3671             :   /* Init SR VPO DPOs type */
    3672         559 :   sr_pr_encaps_dpo_type =
    3673         559 :     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
    3674             : 
    3675         559 :   sr_pr_insert_dpo_type =
    3676         559 :     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
    3677             : 
    3678         559 :   sr_pr_bsid_encaps_dpo_type =
    3679         559 :     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
    3680             : 
    3681         559 :   sr_pr_bsid_insert_dpo_type =
    3682         559 :     dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
    3683             : 
    3684             :   /* Register the L2 encaps node used in HW redirect */
    3685         559 :   sm->l2_sr_policy_rewrite_index = sr_policy_rewrite_encaps_node.index;
    3686             : 
    3687         559 :   sm->fib_table_ip6 = (u32) ~ 0;
    3688         559 :   sm->fib_table_ip4 = (u32) ~ 0;
    3689             : 
    3690         559 :   return 0;
    3691             : }
    3692             : 
    3693       66639 : VLIB_INIT_FUNCTION (sr_policy_rewrite_init);
    3694             : 
    3695             : 
    3696             : /*
    3697             : * fd.io coding-style-patch-verification: ON
    3698             : *
    3699             : * Local Variables:
    3700             : * eval: (c-set-style "gnu")
    3701             : * End:
    3702             : */

Generated by: LCOV version 1.14