LCOV - code coverage report
Current view: top level - plugins/srv6-ad-flow - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 296 406 72.9 %
Date: 2023-10-26 01:39:38 Functions: 18 21 85.7 %

          Line data    Source code
       1             : /*
       2             :  * node.c
       3             :  *
       4             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/vnet.h>
      20             : #include <vppinfra/error.h>
      21             : #include <srv6-ad-flow/ad-flow.h>
      22             : 
      23             : /****************************** Packet tracing ******************************/
      24             : 
      25             : typedef struct
      26             : {
      27             :   u32 localsid_index;
      28             : } srv6_ad_flow_localsid_trace_t;
      29             : 
      30             : typedef struct
      31             : {
      32             :   u8 error;
      33             :   ip6_address_t src, dst;
      34             : } srv6_ad_flow_rewrite_trace_t;
      35             : 
      36             : static u8 *
      37           0 : format_srv6_ad_flow_localsid_trace (u8 *s, va_list *args)
      38             : {
      39           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      40           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      41           0 :   srv6_ad_flow_localsid_trace_t *t =
      42             :     va_arg (*args, srv6_ad_flow_localsid_trace_t *);
      43             : 
      44           0 :   return format (s, "SRv6-AD-Flow-localsid: localsid_index %d",
      45             :                  t->localsid_index);
      46             : }
      47             : 
      48             : static u8 *
      49           6 : format_srv6_ad_flow_rewrite_trace (u8 *s, va_list *args)
      50             : {
      51           6 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      52           6 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      53           6 :   srv6_ad_flow_rewrite_trace_t *t =
      54             :     va_arg (*args, srv6_ad_flow_rewrite_trace_t *);
      55             : 
      56           6 :   if (PREDICT_FALSE (t->error != 0))
      57             :     {
      58           0 :       return format (s, "SRv6-AD-Flow-rewrite: cache is empty");
      59             :     }
      60             : 
      61           6 :   return format (s, "SRv6-AD-Flow-rewrite: src %U dst %U", format_ip6_address,
      62             :                  &t->src, format_ip6_address, &t->dst);
      63             : }
      64             : 
      65             : /**************************** Nodes registration *****************************/
      66             : 
      67             : vlib_node_registration_t srv6_ad4_flow_rewrite_node;
      68             : vlib_node_registration_t srv6_ad6_flow_rewrite_node;
      69             : 
      70             : /****************************** Packet counters ******************************/
      71             : 
      72             : #define foreach_srv6_ad_flow_rewrite_counter                                  \
      73             :   _ (PROCESSED, "srv6-ad-flow rewritten packets")                             \
      74             :   _ (NO_RW, "(Error) No header for rewriting.")
      75             : 
      76             : typedef enum
      77             : {
      78             : #define _(sym, str) SRV6_AD_FLOW_REWRITE_COUNTER_##sym,
      79             :   foreach_srv6_ad_flow_rewrite_counter
      80             : #undef _
      81             :     SRV6_AD_FLOW_REWRITE_N_COUNTERS,
      82             : } srv6_ad_flow_rewrite_counters;
      83             : 
      84             : static char *srv6_ad_flow_rewrite_counter_strings[] = {
      85             : #define _(sym, string) string,
      86             :   foreach_srv6_ad_flow_rewrite_counter
      87             : #undef _
      88             : };
      89             : 
      90             : /******************************** Next nodes *********************************/
      91             : 
      92             : typedef enum
      93             : {
      94             :   SRV6_AD_FLOW_LOCALSID_NEXT_ERROR,
      95             :   SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE4,
      96             :   SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE6,
      97             :   SRV6_AD_FLOW_LOCALSID_NEXT_BYPASS,
      98             :   SRV6_AD_FLOW_LOCALSID_NEXT_PUNT,
      99             :   SRV6_AD_FLOW_LOCALSID_N_NEXT,
     100             : } srv6_ad_flow_localsid_next_t;
     101             : 
     102             : typedef enum
     103             : {
     104             :   SRV6_AD_FLOW_REWRITE_NEXT_ERROR,
     105             :   SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP,
     106             :   SRV6_AD_FLOW_REWRITE_N_NEXT,
     107             : } srv6_ad_flow_rewrite_next_t;
     108             : 
     109             : /***************************** Inline functions ******************************/
     110             : 
     111             : static_always_inline int
     112           2 : ad_flow_lru_insert (srv6_ad_flow_localsid_t *ls, srv6_ad_flow_entry_t *e,
     113             :                     f64 now)
     114             : {
     115             :   dlist_elt_t *lru_list_elt;
     116           2 :   pool_get (ls->lru_pool, lru_list_elt);
     117           2 :   e->lru_index = lru_list_elt - ls->lru_pool;
     118           2 :   clib_dlist_addtail (ls->lru_pool, ls->lru_head_index, e->lru_index);
     119           2 :   lru_list_elt->value = e - ls->cache;
     120           2 :   e->last_lru_update = now;
     121           2 :   return 1;
     122             : }
     123             : 
     124             : always_inline void
     125           6 : ad_flow_entry_update_lru (srv6_ad_flow_localsid_t *ls, srv6_ad_flow_entry_t *e)
     126             : {
     127             :   /* don't update too often - timeout is in magnitude of seconds anyway */
     128           6 :   if (e->last_heard > e->last_lru_update + 1)
     129             :     {
     130           0 :       clib_dlist_remove (ls->lru_pool, e->lru_index);
     131           0 :       clib_dlist_addtail (ls->lru_pool, ls->lru_head_index, e->lru_index);
     132           0 :       e->last_lru_update = e->last_heard;
     133             :     }
     134           6 : }
     135             : 
     136             : always_inline void
     137           0 : ad_flow_entry_delete (srv6_ad_flow_localsid_t *ls, srv6_ad_flow_entry_t *e,
     138             :                       int lru_delete)
     139             : {
     140             :   clib_bihash_kv_40_8_t kv;
     141             : 
     142           0 :   if (ls->inner_type == AD_TYPE_IP4)
     143             :     {
     144           0 :       kv.key[0] = ((u64) e->key.s_addr.ip4.as_u32 << 32) |
     145           0 :                   (u64) e->key.d_addr.ip4.as_u32;
     146           0 :       kv.key[1] = ((u64) e->key.s_port << 16) | ((u64) e->key.d_port);
     147           0 :       kv.key[2] = 0;
     148           0 :       kv.key[3] = 0;
     149           0 :       kv.key[4] = 0;
     150             :     }
     151             :   else
     152             :     {
     153           0 :       kv.key[0] = e->key.s_addr.ip6.as_u64[0];
     154           0 :       kv.key[1] = e->key.s_addr.ip6.as_u64[1];
     155           0 :       kv.key[2] = e->key.d_addr.ip6.as_u64[0];
     156           0 :       kv.key[3] = e->key.d_addr.ip6.as_u64[1];
     157           0 :       kv.key[4] = ((u64) e->key.s_port << 16) | ((u64) e->key.d_port);
     158             :     }
     159             : 
     160           0 :   clib_bihash_add_del_40_8 (&ls->ftable, &kv, 0);
     161             : 
     162           0 :   vec_free (e->rw_data);
     163             : 
     164           0 :   if (lru_delete)
     165             :     {
     166           0 :       clib_dlist_remove (ls->lru_pool, e->lru_index);
     167             :     }
     168           0 :   pool_put_index (ls->lru_pool, e->lru_index);
     169           0 :   pool_put (ls->cache, e);
     170           0 : }
     171             : 
     172             : static_always_inline int
     173           2 : ad_flow_lru_free_one (srv6_ad_flow_localsid_t *ls, f64 now)
     174             : {
     175           2 :   srv6_ad_flow_entry_t *e = NULL;
     176             :   dlist_elt_t *oldest_elt;
     177             :   f64 entry_timeout_time;
     178             :   u32 oldest_index;
     179           2 :   oldest_index = clib_dlist_remove_head (ls->lru_pool, ls->lru_head_index);
     180           2 :   if (~0 != oldest_index)
     181             :     {
     182           0 :       oldest_elt = pool_elt_at_index (ls->lru_pool, oldest_index);
     183           0 :       e = pool_elt_at_index (ls->cache, oldest_elt->value);
     184             : 
     185           0 :       entry_timeout_time = e->last_heard + (f64) SRV6_AD_CACHE_TIMEOUT;
     186           0 :       if (now >= entry_timeout_time)
     187             :         {
     188           0 :           ad_flow_entry_delete (ls, e, 0);
     189           0 :           return 1;
     190             :         }
     191             :       else
     192             :         {
     193           0 :           clib_dlist_addhead (ls->lru_pool, ls->lru_head_index, oldest_index);
     194             :         }
     195             :     }
     196           2 :   return 0;
     197             : }
     198             : 
     199             : static_always_inline srv6_ad_flow_entry_t *
     200           2 : ad_flow_entry_alloc (srv6_ad_flow_localsid_t *ls, f64 now)
     201             : {
     202             :   srv6_ad_flow_entry_t *e;
     203             : 
     204           2 :   ad_flow_lru_free_one (ls, now);
     205             : 
     206           2 :   pool_get (ls->cache, e);
     207           2 :   clib_memset (e, 0, sizeof *e);
     208             : 
     209           2 :   ad_flow_lru_insert (ls, e, now);
     210             : 
     211           2 :   return e;
     212             : }
     213             : 
     214             : always_inline u32
     215          10 : ad_flow_value_get_session_index (clib_bihash_kv_40_8_t *value)
     216             : {
     217          10 :   return value->value & ~(u32) 0;
     218             : }
     219             : 
     220             : int
     221           0 : ad_flow_is_idle_entry_cb (clib_bihash_kv_40_8_t *kv, void *arg)
     222             : {
     223           0 :   srv6_ad_is_idle_entry_ctx_t *ctx = arg;
     224             :   srv6_ad_flow_entry_t *e;
     225             :   u64 entry_timeout_time;
     226           0 :   srv6_ad_flow_localsid_t *ls = ctx->ls;
     227             : 
     228           0 :   e = pool_elt_at_index (ls->cache, ad_flow_value_get_session_index (kv));
     229           0 :   entry_timeout_time = e->last_heard + (f64) SRV6_AD_CACHE_TIMEOUT;
     230           0 :   if (ctx->now >= entry_timeout_time)
     231             :     {
     232           0 :       ad_flow_entry_delete (ls, e, 1);
     233           0 :       return 1;
     234             :     }
     235           0 :   return 0;
     236             : }
     237             : 
     238             : /****************************** Local SID node *******************************/
     239             : 
     240             : /**
     241             :  * @brief Function doing SRH processing for AD behavior
     242             :  */
     243             : static_always_inline int
     244          12 : end_ad_flow_walk_expect_first_hdr (vlib_main_t *vm, vlib_buffer_t *b,
     245             :                                    ip6_ext_header_t *first_hdr,
     246             :                                    u8 first_hdr_type, u8 expected_hdr_type,
     247             :                                    u32 *encap_length, u8 **found_hdr)
     248             : {
     249          12 :   if (PREDICT_TRUE (first_hdr_type == expected_hdr_type))
     250             :     {
     251          12 :       *found_hdr = (void *) first_hdr;
     252             :     }
     253             :   else
     254             :     {
     255           0 :       u8 ext_hdr_type = first_hdr_type;
     256           0 :       ip6_ext_header_t *ext_hdr = first_hdr;
     257             : 
     258           0 :       if (!ip6_ext_hdr (ext_hdr_type))
     259             :         {
     260           0 :           *found_hdr = NULL;
     261           0 :           return -1;
     262             :         }
     263             : 
     264           0 :       u32 ext_hdr_length = ip6_ext_header_len (ext_hdr);
     265           0 :       if (!vlib_object_within_buffer_data (vm, b, ext_hdr, ext_hdr_length))
     266             :         {
     267           0 :           *found_hdr = NULL;
     268           0 :           return -2;
     269             :         }
     270           0 :       *encap_length += ext_hdr_length;
     271           0 :       ext_hdr_type = ext_hdr->next_hdr;
     272             : 
     273           0 :       while (ext_hdr_type != expected_hdr_type && ip6_ext_hdr (ext_hdr_type))
     274             :         {
     275           0 :           ext_hdr = ip6_ext_next_header (ext_hdr);
     276           0 :           ext_hdr_length = ip6_ext_header_len (ext_hdr);
     277           0 :           if (!vlib_object_within_buffer_data (vm, b, ext_hdr, ext_hdr_length))
     278             :             {
     279           0 :               *found_hdr = NULL;
     280           0 :               return -2;
     281             :             }
     282           0 :           *encap_length += ext_hdr_length;
     283           0 :           ext_hdr_type = ext_hdr->next_hdr;
     284             :         }
     285             : 
     286           0 :       if (ext_hdr_type != expected_hdr_type)
     287             :         {
     288           0 :           *found_hdr = NULL;
     289           0 :           return -1;
     290             :         }
     291             : 
     292           0 :       *found_hdr = ip6_ext_next_header (ext_hdr);
     293             :     }
     294             : 
     295          12 :   return 0;
     296             : }
     297             : 
     298             : /**
     299             :  * @brief Function doing SRH processing for per-flow AD behavior (IPv6 inner
     300             :  * traffic)
     301             :  */
     302             : static_always_inline void
     303           3 : end_ad_flow_processing_v6 (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip,
     304             :                            srv6_ad_flow_localsid_t *ls_mem, u32 *next,
     305             :                            vlib_combined_counter_main_t **cnt, u32 *cnt_idx,
     306             :                            f64 now)
     307             : {
     308           3 :   ip6_sr_main_t *srm = &sr_main;
     309           3 :   srv6_ad_flow_main_t *sm = &srv6_ad_flow_main;
     310             :   ip6_address_t *new_dst;
     311           3 :   u32 encap_length = sizeof (ip6_header_t);
     312             :   ip6_sr_header_t *srh;
     313           3 :   clib_bihash_40_8_t *h = &ls_mem->ftable;
     314           3 :   ip6_header_t *ulh = NULL;
     315           3 :   u16 src_port = 0, dst_port = 0;
     316           3 :   srv6_ad_flow_entry_t *e = NULL;
     317             :   clib_bihash_kv_40_8_t kv, value;
     318             :   srv6_ad_is_idle_entry_ctx_t ctx;
     319             : 
     320             :   /* Find SRH in the extension header chain */
     321           3 :   end_ad_flow_walk_expect_first_hdr (vm, b, (void *) (ip + 1), ip->protocol,
     322             :                                      IP_PROTOCOL_IPV6_ROUTE, &encap_length,
     323             :                                      (u8 **) &srh);
     324             : 
     325             :   /* Punt the packet if no SRH or SRH with SL = 0 */
     326           3 :   if (PREDICT_FALSE (srh == NULL || srh->type != ROUTING_HEADER_TYPE_SR ||
     327             :                      srh->segments_left == 0))
     328             :     {
     329           0 :       *next = SRV6_AD_FLOW_LOCALSID_NEXT_PUNT;
     330           0 :       *cnt = &(sm->sid_punt_counters);
     331           0 :       *cnt_idx = ls_mem->index;
     332           0 :       return;
     333             :     }
     334             : 
     335             :   /* Decrement Segments Left and update Destination Address */
     336           3 :   srh->segments_left -= 1;
     337           3 :   new_dst = (ip6_address_t *) (srh->segments) + srh->segments_left;
     338           3 :   ip->dst_address.as_u64[0] = new_dst->as_u64[0];
     339           3 :   ip->dst_address.as_u64[1] = new_dst->as_u64[1];
     340             : 
     341             :   /* Compute the total encapsulation size and determine ULH type */
     342           3 :   encap_length += ip6_ext_header_len ((ip6_ext_header_t *) srh);
     343             : 
     344             :   /* Find the inner IPv6 header (ULH) */
     345           3 :   int ret = end_ad_flow_walk_expect_first_hdr (
     346           3 :     vm, b, ip6_ext_next_header ((ip6_ext_header_t *) srh), srh->protocol,
     347             :     IP_PROTOCOL_IPV6, &encap_length, (u8 **) &ulh);
     348             : 
     349           3 :   if (PREDICT_FALSE (ulh == NULL))
     350             :     {
     351           0 :       if (ret == -1) /* Bypass the NF if ULH is not of expected type */
     352             :         {
     353           0 :           *next = SRV6_AD_FLOW_LOCALSID_NEXT_BYPASS;
     354           0 :           *cnt = &(sm->sid_bypass_counters);
     355           0 :           *cnt_idx = ls_mem->index;
     356             :         }
     357             :       else
     358             :         {
     359           0 :           *next = SRV6_AD_FLOW_LOCALSID_NEXT_ERROR;
     360           0 :           *cnt = &(srm->sr_ls_invalid_counters);
     361             :         }
     362           0 :       return;
     363             :     }
     364             : 
     365             :   /* Compute flow hash on ULH */
     366           3 :   if (PREDICT_TRUE (ulh->protocol == IP_PROTOCOL_UDP ||
     367             :                     ulh->protocol == IP_PROTOCOL_TCP))
     368             :     {
     369           3 :       udp_header_t *ulh_l4_hdr = (udp_header_t *) (ulh + 1);
     370           3 :       src_port = ulh_l4_hdr->src_port;
     371           3 :       dst_port = ulh_l4_hdr->dst_port;
     372             :     }
     373             : 
     374           3 :   kv.key[0] = ulh->src_address.as_u64[0];
     375           3 :   kv.key[1] = ulh->src_address.as_u64[1];
     376           3 :   kv.key[2] = ulh->dst_address.as_u64[0];
     377           3 :   kv.key[3] = ulh->dst_address.as_u64[1];
     378           3 :   kv.key[4] = ((u64) src_port << 16) | ((u64) dst_port);
     379             : 
     380             :   /* Lookup flow in hashtable */
     381           3 :   if (!clib_bihash_search_40_8 (h, &kv, &value))
     382             :     {
     383           2 :       e = pool_elt_at_index (ls_mem->cache,
     384             :                              ad_flow_value_get_session_index (&value));
     385             :     }
     386             : 
     387           3 :   if (!e)
     388             :     {
     389           1 :       if (pool_elts (ls_mem->cache) >= ls_mem->cache_size)
     390             :         {
     391           0 :           if (!ad_flow_lru_free_one (ls_mem, now))
     392             :             {
     393           0 :               *next = SRV6_AD_FLOW_LOCALSID_NEXT_ERROR;
     394           0 :               *cnt = &(sm->sid_cache_full_counters);
     395           0 :               *cnt_idx = ls_mem->index;
     396           0 :               return;
     397             :             }
     398             :         }
     399             : 
     400           1 :       e = ad_flow_entry_alloc (ls_mem, now);
     401           1 :       ASSERT (e);
     402           1 :       e->key.s_addr.ip6.as_u64[0] = ulh->src_address.as_u64[0];
     403           1 :       e->key.s_addr.ip6.as_u64[1] = ulh->src_address.as_u64[1];
     404           1 :       e->key.d_addr.ip6.as_u64[0] = ulh->dst_address.as_u64[0];
     405           1 :       e->key.d_addr.ip6.as_u64[1] = ulh->dst_address.as_u64[1];
     406           1 :       e->key.s_port = src_port;
     407           1 :       e->key.d_port = dst_port;
     408           1 :       e->key.proto = ulh->protocol;
     409             : 
     410           1 :       kv.value = (u64) (e - ls_mem->cache);
     411             : 
     412           1 :       ctx.now = now;
     413           1 :       ctx.ls = ls_mem;
     414           1 :       clib_bihash_add_or_overwrite_stale_40_8 (h, &kv,
     415             :                                                ad_flow_is_idle_entry_cb, &ctx);
     416             :     }
     417           3 :   e->last_heard = now;
     418             : 
     419             :   /* Cache encapsulation headers */
     420           3 :   if (PREDICT_FALSE (encap_length > e->rw_len))
     421             :     {
     422           1 :       vec_validate (e->rw_data, encap_length - 1);
     423             :     }
     424           3 :   clib_memcpy_fast (e->rw_data, ip, encap_length);
     425           3 :   e->rw_len = encap_length;
     426             : 
     427             :   /* Update LRU */
     428           3 :   ad_flow_entry_update_lru (ls_mem, e);
     429             : 
     430             :   /* Decapsulate the packet */
     431           3 :   vlib_buffer_advance (b, encap_length);
     432             : 
     433             :   /* Set next node */
     434           3 :   *next = SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE6;
     435             : 
     436             :   /* Set Xconnect adjacency to VNF */
     437           3 :   vnet_buffer (b)->ip.adj_index[VLIB_TX] = ls_mem->nh_adj;
     438             : }
     439             : 
     440             : static_always_inline void
     441           3 : end_ad_flow_processing_v4 (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip,
     442             :                            srv6_ad_flow_localsid_t *ls_mem, u32 *next,
     443             :                            vlib_combined_counter_main_t **cnt, u32 *cnt_idx,
     444             :                            f64 now)
     445             : {
     446           3 :   ip6_sr_main_t *srm = &sr_main;
     447           3 :   srv6_ad_flow_main_t *sm = &srv6_ad_flow_main;
     448             :   ip6_address_t *new_dst;
     449           3 :   u32 encap_length = sizeof (ip6_header_t);
     450             :   ip6_sr_header_t *srh;
     451           3 :   clib_bihash_40_8_t *h = &ls_mem->ftable;
     452           3 :   ip4_header_t *ulh = NULL;
     453           3 :   u16 src_port = 0, dst_port = 0;
     454           3 :   srv6_ad_flow_entry_t *e = NULL;
     455             :   clib_bihash_kv_40_8_t kv, value;
     456             :   srv6_ad_is_idle_entry_ctx_t ctx;
     457             : 
     458             :   /* Find SRH in the extension header chain */
     459           3 :   end_ad_flow_walk_expect_first_hdr (vm, b, (void *) (ip + 1), ip->protocol,
     460             :                                      IP_PROTOCOL_IPV6_ROUTE, &encap_length,
     461             :                                      (u8 **) &srh);
     462             : 
     463             :   /* Punt the packet if no SRH or SRH with SL = 0 */
     464           3 :   if (PREDICT_FALSE (srh == NULL || srh->type != ROUTING_HEADER_TYPE_SR ||
     465             :                      srh->segments_left == 0))
     466             :     {
     467           0 :       *next = SRV6_AD_FLOW_LOCALSID_NEXT_PUNT;
     468           0 :       *cnt = &(sm->sid_punt_counters);
     469           0 :       *cnt_idx = ls_mem->index;
     470           0 :       return;
     471             :     }
     472             : 
     473             :   /* Decrement Segments Left and update Destination Address */
     474           3 :   srh->segments_left -= 1;
     475           3 :   new_dst = (ip6_address_t *) (srh->segments) + srh->segments_left;
     476           3 :   ip->dst_address.as_u64[0] = new_dst->as_u64[0];
     477           3 :   ip->dst_address.as_u64[1] = new_dst->as_u64[1];
     478             : 
     479             :   /* Add SRH length to the total encapsulation size */
     480           3 :   encap_length += ip6_ext_header_len ((ip6_ext_header_t *) srh);
     481             : 
     482             :   /* Find the inner IPv6 header (ULH) */
     483           3 :   int ret = end_ad_flow_walk_expect_first_hdr (
     484           3 :     vm, b, ip6_ext_next_header ((ip6_ext_header_t *) srh), srh->protocol,
     485             :     IP_PROTOCOL_IP_IN_IP, &encap_length, (u8 **) &ulh);
     486             : 
     487           3 :   if (PREDICT_FALSE (ulh == NULL))
     488             :     {
     489           0 :       if (ret == -1) /* Bypass the NF if ULH is not of expected type */
     490             :         {
     491           0 :           *next = SRV6_AD_FLOW_LOCALSID_NEXT_BYPASS;
     492           0 :           *cnt = &(sm->sid_bypass_counters);
     493           0 :           *cnt_idx = ls_mem->index;
     494             :         }
     495             :       else
     496             :         {
     497           0 :           *next = SRV6_AD_FLOW_LOCALSID_NEXT_ERROR;
     498           0 :           *cnt = &(srm->sr_ls_invalid_counters);
     499             :         }
     500           0 :       return;
     501             :     }
     502             : 
     503             :   /* Compute flow hash on ULH */
     504           3 :   if (PREDICT_TRUE (ulh->protocol == IP_PROTOCOL_UDP ||
     505             :                     ulh->protocol == IP_PROTOCOL_TCP))
     506             :     {
     507           3 :       udp_header_t *ulh_l4_hdr = (udp_header_t *) (ulh + 1);
     508           3 :       src_port = ulh_l4_hdr->src_port;
     509           3 :       dst_port = ulh_l4_hdr->dst_port;
     510             :     }
     511             : 
     512           3 :   kv.key[0] = *((u64 *) &ulh->address_pair);
     513           3 :   kv.key[1] = ((u64) src_port << 16) | ((u64) dst_port);
     514           3 :   kv.key[2] = 0;
     515           3 :   kv.key[3] = 0;
     516           3 :   kv.key[4] = 0;
     517             : 
     518             :   /* Lookup flow in hashtable */
     519           3 :   if (!clib_bihash_search_40_8 (h, &kv, &value))
     520             :     {
     521           2 :       e = pool_elt_at_index (ls_mem->cache,
     522             :                              ad_flow_value_get_session_index (&value));
     523             :     }
     524             : 
     525           3 :   if (!e)
     526             :     {
     527           1 :       if (pool_elts (ls_mem->cache) >= ls_mem->cache_size)
     528             :         {
     529           0 :           if (!ad_flow_lru_free_one (ls_mem, now))
     530             :             {
     531           0 :               *next = SRV6_AD_FLOW_LOCALSID_NEXT_ERROR;
     532           0 :               *cnt = &(sm->sid_cache_full_counters);
     533           0 :               *cnt_idx = ls_mem->index;
     534           0 :               return;
     535             :             }
     536             :         }
     537             : 
     538           1 :       e = ad_flow_entry_alloc (ls_mem, now);
     539           1 :       ASSERT (e);
     540           1 :       e->key.s_addr.ip4 = ulh->src_address;
     541           1 :       e->key.d_addr.ip4 = ulh->dst_address;
     542           1 :       e->key.s_port = src_port;
     543           1 :       e->key.d_port = dst_port;
     544           1 :       e->key.proto = ulh->protocol;
     545             : 
     546           1 :       kv.value = (u64) (e - ls_mem->cache);
     547             : 
     548           1 :       ctx.now = now;
     549           1 :       ctx.ls = ls_mem;
     550           1 :       clib_bihash_add_or_overwrite_stale_40_8 (h, &kv,
     551             :                                                ad_flow_is_idle_entry_cb, &ctx);
     552             :     }
     553           3 :   e->last_heard = now;
     554             : 
     555             :   /* Cache encapsulation headers */
     556           3 :   if (PREDICT_FALSE (encap_length > e->rw_len))
     557             :     {
     558           1 :       vec_validate (e->rw_data, encap_length - 1);
     559             :     }
     560           3 :   clib_memcpy_fast (e->rw_data, ip, encap_length);
     561           3 :   e->rw_len = encap_length;
     562             : 
     563             :   /* Update LRU */
     564           3 :   ad_flow_entry_update_lru (ls_mem, e);
     565             : 
     566             :   /* Decapsulate the packet */
     567           3 :   vlib_buffer_advance (b, encap_length);
     568             : 
     569             :   /* Set next node */
     570           3 :   *next = SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE4;
     571             : 
     572             :   /* Set Xconnect adjacency to VNF */
     573           3 :   vnet_buffer (b)->ip.adj_index[VLIB_TX] = ls_mem->nh_adj;
     574             : }
     575             : 
     576             : /**
     577             :  * @brief SRv6 AD Localsid graph node
     578             :  */
     579             : static uword
     580           2 : srv6_ad_flow_localsid_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
     581             :                           vlib_frame_t *frame)
     582             : {
     583           2 :   ip6_sr_main_t *srm = &sr_main;
     584           2 :   f64 now = vlib_time_now (vm);
     585             :   u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
     586           2 :   u32 thread_index = vm->thread_index;
     587             : 
     588           2 :   from = vlib_frame_vector_args (frame);
     589           2 :   n_left_from = frame->n_vectors;
     590           2 :   next_index = node->cached_next_index;
     591             : 
     592           4 :   while (n_left_from > 0)
     593             :     {
     594           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     595             : 
     596             :       /* TODO: Dual/quad loop */
     597             : 
     598           8 :       while (n_left_from > 0 && n_left_to_next > 0)
     599             :         {
     600             :           u32 bi0;
     601             :           vlib_buffer_t *b0;
     602           6 :           ip6_header_t *ip0 = 0;
     603             :           ip6_sr_localsid_t *ls0;
     604             :           srv6_ad_flow_localsid_t *ls_mem0;
     605             :           u32 next0;
     606           6 :           vlib_combined_counter_main_t *cnt0 = &(srm->sr_ls_valid_counters);
     607             :           u32 cnt_idx0;
     608             : 
     609           6 :           bi0 = from[0];
     610           6 :           to_next[0] = bi0;
     611           6 :           from += 1;
     612           6 :           to_next += 1;
     613           6 :           n_left_from -= 1;
     614           6 :           n_left_to_next -= 1;
     615             : 
     616           6 :           b0 = vlib_get_buffer (vm, bi0);
     617           6 :           ip0 = vlib_buffer_get_current (b0);
     618             : 
     619             :           /* Retrieve local SID context based on IP DA (adj) */
     620           6 :           ls0 = pool_elt_at_index (srm->localsids,
     621             :                                    vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
     622             : 
     623           6 :           cnt_idx0 = ls0 - srm->localsids;
     624             : 
     625             :           /* Retrieve local SID's plugin memory */
     626           6 :           ls_mem0 = ls0->plugin_mem;
     627             : 
     628             :           /* SRH processing */
     629           6 :           if (ls_mem0->inner_type == AD_TYPE_IP6)
     630           3 :             end_ad_flow_processing_v6 (vm, b0, ip0, ls_mem0, &next0, &cnt0,
     631             :                                        &cnt_idx0, now);
     632             :           else
     633           3 :             end_ad_flow_processing_v4 (vm, b0, ip0, ls_mem0, &next0, &cnt0,
     634             :                                        &cnt_idx0, now);
     635             : 
     636             :           /* Trace packet (if enabled) */
     637           6 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     638             :             {
     639             :               srv6_ad_flow_localsid_trace_t *tr =
     640           6 :                 vlib_add_trace (vm, node, b0, sizeof *tr);
     641           6 :               tr->localsid_index = ls_mem0->index;
     642             :             }
     643             : 
     644             :           /* Increment the appropriate per-SID counter */
     645           6 :           vlib_increment_combined_counter (
     646             :             cnt0, thread_index, cnt_idx0, 1,
     647             :             vlib_buffer_length_in_chain (vm, b0));
     648             : 
     649           6 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     650             :                                            n_left_to_next, bi0, next0);
     651             :         }
     652           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     653             :     }
     654             : 
     655           2 :   return frame->n_vectors;
     656             : }
     657             : 
     658       39743 : VLIB_REGISTER_NODE (srv6_ad_flow_localsid_node) = {
     659             :   .function = srv6_ad_flow_localsid_fn,
     660             :   .name = "srv6-ad-flow-localsid",
     661             :   .vector_size = sizeof (u32),
     662             :   .format_trace = format_srv6_ad_flow_localsid_trace,
     663             :   .type = VLIB_NODE_TYPE_INTERNAL,
     664             :   .n_next_nodes = SRV6_AD_FLOW_LOCALSID_N_NEXT,
     665             :   .next_nodes = {
     666             :                 [SRV6_AD_FLOW_LOCALSID_NEXT_PUNT] = "ip6-local",
     667             :                 [SRV6_AD_FLOW_LOCALSID_NEXT_BYPASS] = "ip6-lookup",
     668             :     [SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE4] = "ip4-rewrite",
     669             :     [SRV6_AD_FLOW_LOCALSID_NEXT_REWRITE6] = "ip6-rewrite",
     670             :     [SRV6_AD_FLOW_LOCALSID_NEXT_ERROR] = "error-drop",
     671             :   },
     672             : };
     673             : 
     674             : /****************************** Rewriting node *******************************/
     675             : 
     676             : /**
     677             :  * @brief Graph node for applying a SR policy into an IPv6 packet.
     678             :  * Encapsulation
     679             :  */
     680             : static uword
     681           1 : srv6_ad4_flow_rewrite_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
     682             :                           vlib_frame_t *frame)
     683             : {
     684           1 :   ip6_sr_main_t *srm = &sr_main;
     685           1 :   srv6_ad_flow_main_t *sm = &srv6_ad_flow_main;
     686             :   u32 n_left_from, next_index, *from, *to_next;
     687           1 :   u32 cnt_packets = 0;
     688             : 
     689           1 :   from = vlib_frame_vector_args (frame);
     690           1 :   n_left_from = frame->n_vectors;
     691           1 :   next_index = node->cached_next_index;
     692             : 
     693           2 :   while (n_left_from > 0)
     694             :     {
     695             :       u32 n_left_to_next;
     696             : 
     697           1 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     698             : 
     699             :       /* TODO: Dual/quad loop */
     700             : 
     701           4 :       while (n_left_from > 0 && n_left_to_next > 0)
     702             :         {
     703             :           u32 bi0;
     704             :           vlib_buffer_t *b0;
     705           3 :           ip4_header_t *ip0_encap = 0;
     706           3 :           ip6_header_t *ip0 = 0;
     707             :           ip6_sr_localsid_t *ls0;
     708             :           srv6_ad_flow_localsid_t *ls0_mem;
     709             :           srv6_ad_flow_entry_t *s0;
     710           3 :           u32 next0 = SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP;
     711           3 :           u16 new_l0 = 0;
     712             : 
     713           3 :           bi0 = from[0];
     714           3 :           to_next[0] = bi0;
     715           3 :           from += 1;
     716           3 :           to_next += 1;
     717           3 :           n_left_from -= 1;
     718           3 :           n_left_to_next -= 1;
     719             : 
     720           3 :           b0 = vlib_get_buffer (vm, bi0);
     721           3 :           ip0_encap = vlib_buffer_get_current (b0);
     722           3 :           ls0 = pool_elt_at_index (
     723             :             srm->localsids,
     724             :             sm->sw_iface_localsid4[vnet_buffer (b0)->sw_if_index[VLIB_RX]]);
     725           3 :           ls0_mem = ls0->plugin_mem;
     726             : 
     727           3 :           if (PREDICT_FALSE (ls0_mem == NULL))
     728             :             {
     729           0 :               next0 = SRV6_AD_FLOW_REWRITE_NEXT_ERROR;
     730           0 :               b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
     731             :             }
     732             :           else
     733             :             {
     734             :               clib_bihash_kv_40_8_t kv0, value0;
     735             : 
     736             :               /* Compute flow hash */
     737           3 :               u64 ports = 0;
     738           3 :               if (PREDICT_TRUE (ip0_encap->protocol == IP_PROTOCOL_UDP ||
     739             :                                 ip0_encap->protocol == IP_PROTOCOL_TCP))
     740             :                 {
     741           3 :                   udp_header_t *udp0 = (udp_header_t *) (ip0_encap + 1);
     742           3 :                   ports =
     743           3 :                     ((u64) udp0->src_port << 16) | ((u64) udp0->dst_port);
     744             :                 }
     745             : 
     746           3 :               kv0.key[0] = *((u64 *) &ip0_encap->address_pair);
     747           3 :               kv0.key[1] = ports;
     748           3 :               kv0.key[2] = 0;
     749           3 :               kv0.key[3] = 0;
     750           3 :               kv0.key[4] = 0;
     751             : 
     752             :               /* Lookup flow in hashtable */
     753           3 :               if (clib_bihash_search_40_8 (&ls0_mem->ftable, &kv0, &value0) <
     754             :                   0)
     755             :                 {
     756             :                   /* not found */
     757           0 :                   next0 = SRV6_AD_FLOW_REWRITE_NEXT_ERROR;
     758           0 :                   b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
     759             :                 }
     760             :               else
     761             :                 {
     762             :                   /* found */
     763           3 :                   s0 = pool_elt_at_index (
     764             :                     ls0_mem->cache, ad_flow_value_get_session_index (&value0));
     765           3 :                   ASSERT (s0);
     766           3 :                   ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
     767             :                           (s0->rw_len + b0->current_data));
     768             : 
     769           3 :                   clib_memcpy_fast (((u8 *) ip0_encap) - s0->rw_len,
     770           3 :                                     s0->rw_data, s0->rw_len);
     771           3 :                   vlib_buffer_advance (b0, -(word) s0->rw_len);
     772             : 
     773           3 :                   ip0 = vlib_buffer_get_current (b0);
     774             : 
     775             :                   /* Update inner IPv4 TTL and checksum */
     776             :                   u32 checksum0;
     777           3 :                   ip0_encap->ttl -= 1;
     778           3 :                   checksum0 =
     779           3 :                     ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
     780           3 :                   checksum0 += checksum0 >= 0xffff;
     781           3 :                   ip0_encap->checksum = checksum0;
     782             : 
     783             :                   /* Update outer IPv6 length (in case it has changed) */
     784           6 :                   new_l0 = s0->rw_len - sizeof (ip6_header_t) +
     785           3 :                            clib_net_to_host_u16 (ip0_encap->length);
     786           3 :                   ip0->payload_length = clib_host_to_net_u16 (new_l0);
     787             :                 }
     788             :             }
     789             : 
     790           3 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
     791           3 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     792             :             {
     793             :               srv6_ad_flow_rewrite_trace_t *tr =
     794           3 :                 vlib_add_trace (vm, node, b0, sizeof *tr);
     795           3 :               tr->error = 0;
     796             : 
     797           3 :               if (next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR)
     798             :                 {
     799           0 :                   tr->error = 1;
     800             :                 }
     801             :               else
     802             :                 {
     803           3 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
     804             :                                     sizeof tr->src.as_u8);
     805           3 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
     806             :                                     sizeof tr->dst.as_u8);
     807             :                 }
     808             :             }
     809             : 
     810             :           /* Increment per-SID AD rewrite counters */
     811           3 :           vlib_increment_combined_counter (
     812             :             ((next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR) ?
     813             :                &(sm->rw_invalid_counters) :
     814             :                &(sm->rw_valid_counters)),
     815             :             vm->thread_index, ls0_mem->index, 1,
     816             :             vlib_buffer_length_in_chain (vm, b0));
     817             : 
     818           3 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     819             :                                            n_left_to_next, bi0, next0);
     820             : 
     821           3 :           cnt_packets++;
     822             :         }
     823             : 
     824           1 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     825             :     }
     826             : 
     827             :   /* Update counters */
     828           1 :   vlib_node_increment_counter (vm, srv6_ad4_flow_rewrite_node.index,
     829             :                                SRV6_AD_FLOW_REWRITE_COUNTER_PROCESSED,
     830             :                                cnt_packets);
     831             : 
     832           1 :   return frame->n_vectors;
     833             : }
     834             : 
     835       39743 : VLIB_REGISTER_NODE (srv6_ad4_flow_rewrite_node) = {
     836             :   .function = srv6_ad4_flow_rewrite_fn,
     837             :   .name = "srv6-ad4-flow-rewrite",
     838             :   .vector_size = sizeof (u32),
     839             :   .format_trace = format_srv6_ad_flow_rewrite_trace,
     840             :   .type = VLIB_NODE_TYPE_INTERNAL,
     841             :   .n_errors = SRV6_AD_FLOW_REWRITE_N_COUNTERS,
     842             :   .error_strings = srv6_ad_flow_rewrite_counter_strings,
     843             :   .n_next_nodes = SRV6_AD_FLOW_REWRITE_N_NEXT,
     844             :   .next_nodes = {
     845             :       [SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
     846             :       [SRV6_AD_FLOW_REWRITE_NEXT_ERROR] = "error-drop",
     847             :   },
     848             : };
     849             : 
     850             : /**
     851             :  * @brief Graph node for applying a SR policy into an IPv6 packet.
     852             :  * Encapsulation
     853             :  */
     854             : static uword
     855           1 : srv6_ad6_flow_rewrite_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
     856             :                           vlib_frame_t *frame)
     857             : {
     858           1 :   ip6_sr_main_t *srm = &sr_main;
     859           1 :   srv6_ad_flow_main_t *sm = &srv6_ad_flow_main;
     860             :   u32 n_left_from, next_index, *from, *to_next;
     861           1 :   u32 cnt_packets = 0;
     862             : 
     863           1 :   from = vlib_frame_vector_args (frame);
     864           1 :   n_left_from = frame->n_vectors;
     865           1 :   next_index = node->cached_next_index;
     866             : 
     867           2 :   while (n_left_from > 0)
     868             :     {
     869             :       u32 n_left_to_next;
     870             : 
     871           1 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     872             : 
     873             :       /* TODO: Dual/quad loop */
     874             : 
     875           4 :       while (n_left_from > 0 && n_left_to_next > 0)
     876             :         {
     877             :           u32 bi0;
     878             :           vlib_buffer_t *b0;
     879           3 :           ip6_header_t *ip0 = 0, *ip0_encap = 0;
     880             :           ip6_sr_localsid_t *ls0;
     881             :           srv6_ad_flow_localsid_t *ls0_mem;
     882             :           srv6_ad_flow_entry_t *s0;
     883           3 :           u32 next0 = SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP;
     884           3 :           u16 new_l0 = 0;
     885             : 
     886           3 :           bi0 = from[0];
     887           3 :           to_next[0] = bi0;
     888           3 :           from += 1;
     889           3 :           to_next += 1;
     890           3 :           n_left_from -= 1;
     891           3 :           n_left_to_next -= 1;
     892             : 
     893           3 :           b0 = vlib_get_buffer (vm, bi0);
     894           3 :           ip0_encap = vlib_buffer_get_current (b0);
     895           3 :           ls0 = pool_elt_at_index (
     896             :             srm->localsids,
     897             :             sm->sw_iface_localsid6[vnet_buffer (b0)->sw_if_index[VLIB_RX]]);
     898           3 :           ls0_mem = ls0->plugin_mem;
     899             : 
     900           3 :           if (PREDICT_FALSE (ls0_mem == NULL))
     901             :             {
     902           0 :               next0 = SRV6_AD_FLOW_REWRITE_NEXT_ERROR;
     903           0 :               b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
     904             :             }
     905             :           else
     906             :             {
     907             :               /* ############################################# */
     908             :               clib_bihash_kv_40_8_t kv0, value0;
     909             : 
     910             :               /* Compute flow hash */
     911           3 :               u64 ports = 0;
     912           3 :               if (PREDICT_TRUE (ip0_encap->protocol == IP_PROTOCOL_UDP ||
     913             :                                 ip0_encap->protocol == IP_PROTOCOL_TCP))
     914             :                 {
     915           3 :                   udp_header_t *udp0 = (udp_header_t *) (ip0_encap + 1);
     916           3 :                   ports =
     917           3 :                     ((u64) udp0->src_port << 16) | ((u64) udp0->dst_port);
     918             :                 }
     919             : 
     920           3 :               kv0.key[0] = ip0_encap->src_address.as_u64[0];
     921           3 :               kv0.key[1] = ip0_encap->src_address.as_u64[1];
     922           3 :               kv0.key[2] = ip0_encap->dst_address.as_u64[0];
     923           3 :               kv0.key[3] = ip0_encap->dst_address.as_u64[1];
     924           3 :               kv0.key[4] = ports;
     925             : 
     926             :               /* Lookup flow in hashtable */
     927           3 :               if (clib_bihash_search_40_8 (&ls0_mem->ftable, &kv0, &value0))
     928             :                 {
     929             :                   /* not found */
     930           0 :                   next0 = SRV6_AD_FLOW_REWRITE_NEXT_ERROR;
     931           0 :                   b0->error = node->errors[SRV6_AD_FLOW_REWRITE_COUNTER_NO_RW];
     932             :                 }
     933             :               else
     934             :                 {
     935             :                   /* found */
     936           3 :                   s0 = pool_elt_at_index (
     937             :                     ls0_mem->cache, ad_flow_value_get_session_index (&value0));
     938           3 :                   ASSERT (s0);
     939             : 
     940           3 :                   ASSERT (VLIB_BUFFER_PRE_DATA_SIZE >=
     941             :                           (s0->rw_len + b0->current_data));
     942             : 
     943           3 :                   clib_memcpy_fast (((u8 *) ip0_encap) - s0->rw_len,
     944           3 :                                     s0->rw_data, s0->rw_len);
     945           3 :                   vlib_buffer_advance (b0, -(word) s0->rw_len);
     946             : 
     947           3 :                   ip0 = vlib_buffer_get_current (b0);
     948             : 
     949             :                   /* Update inner IPv6 hop limit */
     950           3 :                   ip0_encap->hop_limit -= 1;
     951             : 
     952             :                   /* Update outer IPv6 length (in case it has changed) */
     953           6 :                   new_l0 = s0->rw_len +
     954           3 :                            clib_net_to_host_u16 (ip0_encap->payload_length);
     955           3 :                   ip0->payload_length = clib_host_to_net_u16 (new_l0);
     956             :                 }
     957             :             }
     958             : 
     959           3 :           if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
     960           3 :               PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     961             :             {
     962             :               srv6_ad_flow_rewrite_trace_t *tr =
     963           3 :                 vlib_add_trace (vm, node, b0, sizeof *tr);
     964           3 :               tr->error = 0;
     965             : 
     966           3 :               if (next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR)
     967             :                 {
     968           0 :                   tr->error = 1;
     969             :                 }
     970             :               else
     971             :                 {
     972           3 :                   clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
     973             :                                     sizeof tr->src.as_u8);
     974           3 :                   clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
     975             :                                     sizeof tr->dst.as_u8);
     976             :                 }
     977             :             }
     978             : 
     979             :           /* Increment per-SID AD rewrite counters */
     980           3 :           vlib_increment_combined_counter (
     981             :             ((next0 == SRV6_AD_FLOW_REWRITE_NEXT_ERROR) ?
     982             :                &(sm->rw_invalid_counters) :
     983             :                &(sm->rw_valid_counters)),
     984             :             vm->thread_index, ls0_mem->index, 1,
     985             :             vlib_buffer_length_in_chain (vm, b0));
     986             : 
     987           3 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     988             :                                            n_left_to_next, bi0, next0);
     989             : 
     990           3 :           cnt_packets++;
     991             :         }
     992             : 
     993           1 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     994             :     }
     995             : 
     996             :   /* Update counters */
     997           1 :   vlib_node_increment_counter (vm, srv6_ad6_flow_rewrite_node.index,
     998             :                                SRV6_AD_FLOW_REWRITE_COUNTER_PROCESSED,
     999             :                                cnt_packets);
    1000             : 
    1001           1 :   return frame->n_vectors;
    1002             : }
    1003             : 
    1004       39743 : VLIB_REGISTER_NODE (srv6_ad6_flow_rewrite_node) = {
    1005             :   .function = srv6_ad6_flow_rewrite_fn,
    1006             :   .name = "srv6-ad6-flow-rewrite",
    1007             :   .vector_size = sizeof (u32),
    1008             :   .format_trace = format_srv6_ad_flow_rewrite_trace,
    1009             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1010             :   .n_errors = SRV6_AD_FLOW_REWRITE_N_COUNTERS,
    1011             :   .error_strings = srv6_ad_flow_rewrite_counter_strings,
    1012             :   .n_next_nodes = SRV6_AD_FLOW_REWRITE_N_NEXT,
    1013             :   .next_nodes = {
    1014             :       [SRV6_AD_FLOW_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
    1015             :       [SRV6_AD_FLOW_REWRITE_NEXT_ERROR] = "error-drop",
    1016             :   },
    1017             : };
    1018             : 
    1019             : /*
    1020             :  * fd.io coding-style-patch-verification: ON
    1021             :  *
    1022             :  * Local Variables:
    1023             :  * eval: (c-set-style "gnu")
    1024             :  * End:
    1025             :  */

Generated by: LCOV version 1.14