LCOV - code coverage report
Current view: top level - plugins/lb - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 260 514 50.6 %
Date: 2023-07-05 22:20:52 Functions: 77 100 77.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <lb/lb.h>
      17             : #include <vnet/fib/ip4_fib.h>
      18             : 
      19             : #include <vnet/gre/packet.h>
      20             : #include <lb/lbhash.h>
      21             : 
      22             : #define foreach_lb_error \
      23             :  _(NONE, "no error") \
      24             :  _(PROTO_NOT_SUPPORTED, "protocol not supported")
      25             : 
      26             : typedef enum
      27             : {
      28             : #define _(sym,str) LB_ERROR_##sym,
      29             :   foreach_lb_error
      30             : #undef _
      31             :   LB_N_ERROR,
      32             : } lb_error_t;
      33             : 
      34             : static char *lb_error_strings[] =
      35             :   {
      36             : #define _(sym,string) string,
      37             :       foreach_lb_error
      38             : #undef _
      39             :     };
      40             : 
      41             : typedef struct
      42             : {
      43             :   u32 vip_index;
      44             :   u32 as_index;
      45             : } lb_trace_t;
      46             : 
      47             : typedef struct
      48             : {
      49             :   u32 vip_index;
      50             : 
      51             :   u32 node_port;
      52             : } lb_nodeport_trace_t;
      53             : 
      54             : typedef struct
      55             : {
      56             :   u32 vip_index;
      57             :   u32 as_index;
      58             :   u32 rx_sw_if_index;
      59             :   u32 next_index;
      60             : } lb_nat_trace_t;
      61             : 
      62             : u8 *
      63        1300 : format_lb_trace (u8 * s, va_list * args)
      64             : {
      65        1300 :   lb_main_t *lbm = &lb_main;
      66        1300 :   CLIB_UNUSED(vlib_main_t * vm)
      67             : = va_arg (*args, vlib_main_t *);
      68        1300 :     CLIB_UNUSED(vlib_node_t * node)
      69             :   = va_arg (*args, vlib_node_t *);
      70        1300 :   lb_trace_t *t = va_arg (*args, lb_trace_t *);
      71        1300 :   if (pool_is_free_index(lbm->vips, t->vip_index))
      72             :     {
      73           0 :       s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
      74             :     }
      75             :   else
      76             :     {
      77        1300 :       s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
      78        1300 :                   &lbm->vips[t->vip_index]);
      79             :     }
      80        1300 :   if (pool_is_free_index(lbm->ass, t->as_index))
      81             :     {
      82           0 :       s = format (s, "lb as[%d]: This AS was freed since capture\n");
      83             :     }
      84             :   else
      85             :     {
      86        1300 :       s = format (s, "lb as[%d]: %U\n", t->as_index, format_lb_as,
      87        1300 :                   &lbm->ass[t->as_index]);
      88             :     }
      89        1300 :   return s;
      90             : }
      91             : 
      92             : u8 *
      93           0 : format_lb_nat_trace (u8 * s, va_list * args)
      94             : {
      95           0 :   lb_main_t *lbm = &lb_main;
      96           0 :   CLIB_UNUSED(vlib_main_t * vm)
      97             : = va_arg (*args, vlib_main_t *);
      98           0 :     CLIB_UNUSED(vlib_node_t * node)
      99             :   = va_arg (*args, vlib_node_t *);
     100           0 :   lb_nat_trace_t *t = va_arg (*args, lb_nat_trace_t *);
     101             : 
     102           0 :   if (pool_is_free_index(lbm->vips, t->vip_index))
     103             :     {
     104           0 :       s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
     105             :     }
     106             :   else
     107             :     {
     108           0 :       s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
     109           0 :                   &lbm->vips[t->vip_index]);
     110             :     }
     111           0 :   if (pool_is_free_index(lbm->ass, t->as_index))
     112             :     {
     113           0 :       s = format (s, "lb as[%d]: This AS was freed since capture\n");
     114             :     }
     115             :   else
     116             :     {
     117           0 :       s = format (s, "lb as[%d]: %U\n", t->as_index, format_lb_as,
     118           0 :                   &lbm->ass[t->as_index]);
     119             :     }
     120           0 :   s = format (s, "lb nat: rx_sw_if_index = %d, next_index = %d",
     121             :               t->rx_sw_if_index, t->next_index);
     122             : 
     123           0 :   return s;
     124             : }
     125             : 
     126             : lb_hash_t *
     127          13 : lb_get_sticky_table (u32 thread_index)
     128             : {
     129          13 :   lb_main_t *lbm = &lb_main;
     130          13 :   lb_hash_t *sticky_ht = lbm->per_cpu[thread_index].sticky_ht;
     131             :   //Check if size changed
     132          13 :   if (PREDICT_FALSE(
     133             :       sticky_ht && (lbm->per_cpu_sticky_buckets != lb_hash_nbuckets(sticky_ht))))
     134             :     {
     135             :       //Dereference everything in there
     136             :       lb_hash_bucket_t *b;
     137             :       u32 i;
     138           0 :       lb_hash_foreach_entry(sticky_ht, b, i)
     139             :         {
     140           0 :           vlib_refcount_add (&lbm->as_refcount, thread_index, b->value[i], -1);
     141           0 :           vlib_refcount_add (&lbm->as_refcount, thread_index, 0, 1);
     142             :         }
     143             : 
     144           0 :       lb_hash_free (sticky_ht);
     145           0 :       sticky_ht = NULL;
     146             :     }
     147             : 
     148             :   //Create if necessary
     149          13 :   if (PREDICT_FALSE(sticky_ht == NULL))
     150             :     {
     151          13 :       lbm->per_cpu[thread_index].sticky_ht = lb_hash_alloc (
     152             :           lbm->per_cpu_sticky_buckets, lbm->flow_timeout);
     153          13 :       sticky_ht = lbm->per_cpu[thread_index].sticky_ht;
     154          13 :       clib_warning("Regenerated sticky table %p", sticky_ht);
     155             :     }
     156             : 
     157          13 :   ASSERT(sticky_ht);
     158             : 
     159             :   //Update timeout
     160          13 :   sticky_ht->timeout = lbm->flow_timeout;
     161          13 :   return sticky_ht;
     162             : }
     163             : 
     164             : u64
     165           0 : lb_node_get_other_ports4 (ip4_header_t *ip40)
     166             : {
     167           0 :   return 0;
     168             : }
     169             : 
     170             : u64
     171           0 : lb_node_get_other_ports6 (ip6_header_t *ip60)
     172             : {
     173           0 :   return 0;
     174             : }
     175             : 
     176             : static_always_inline void
     177        1300 : lb_node_get_hash (lb_main_t *lbm, vlib_buffer_t *p, u8 is_input_v4, u32 *hash,
     178             :                   u32 *vip_idx, u8 per_port_vip, u8 src_ip_sticky)
     179             : {
     180             :   vip_port_key_t key;
     181             :   clib_bihash_kv_8_8_t kv, value;
     182             : 
     183             :   /* For vip case, retrieve vip index for ip lookup */
     184        1300 :   *vip_idx = vnet_buffer (p)->ip.adj_index[VLIB_TX];
     185             : 
     186        1300 :   if (per_port_vip)
     187             :     {
     188             :       /* For per-port-vip case, ip lookup stores placeholder index */
     189         800 :       key.vip_prefix_index = *vip_idx;
     190             :     }
     191             : 
     192        1300 :   if (is_input_v4)
     193             :     {
     194             :       ip4_header_t *ip40;
     195             :       u64 ports;
     196             : 
     197         800 :       ip40 = vlib_buffer_get_current (p);
     198         800 :       if (PREDICT_TRUE(
     199             :           ip40->protocol == IP_PROTOCOL_TCP
     200             :               || ip40->protocol == IP_PROTOCOL_UDP))
     201         800 :         ports = ((u64) ((udp_header_t *) (ip40 + 1))->src_port << 16)
     202         800 :             | ((u64) ((udp_header_t *) (ip40 + 1))->dst_port);
     203             :       else
     204           0 :         ports = lb_node_get_other_ports4 (ip40);
     205             : 
     206         800 :       if (src_ip_sticky)
     207             :         {
     208         100 :           *hash = lb_hash_hash (*((u64 *) &ip40->address_pair), 0, 0, 0, 0);
     209             :         }
     210             :       else
     211             :         {
     212         700 :           *hash =
     213         700 :             lb_hash_hash (*((u64 *) &ip40->address_pair), ports, 0, 0, 0);
     214             :         }
     215             : 
     216         800 :       if (per_port_vip)
     217             :         {
     218         500 :           key.protocol = ip40->protocol;
     219         500 :           key.port = (u16)(ports & 0xFFFF);
     220             :         }
     221             :     }
     222             :   else
     223             :     {
     224             :       ip6_header_t *ip60;
     225         500 :       ip60 = vlib_buffer_get_current (p);
     226             :       u64 ports;
     227             : 
     228         500 :       if (PREDICT_TRUE(
     229             :           ip60->protocol == IP_PROTOCOL_TCP
     230             :               || ip60->protocol == IP_PROTOCOL_UDP))
     231         500 :         ports = ((u64) ((udp_header_t *) (ip60 + 1))->src_port << 16)
     232         500 :             | ((u64) ((udp_header_t *) (ip60 + 1))->dst_port);
     233             :       else
     234           0 :         ports = lb_node_get_other_ports6 (ip60);
     235             : 
     236         500 :       if (src_ip_sticky)
     237             :         {
     238           0 :           *hash = lb_hash_hash (
     239             :             ip60->src_address.as_u64[0], ip60->src_address.as_u64[1],
     240             :             ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], 0);
     241             :         }
     242             :       else
     243             :         {
     244         500 :           *hash = lb_hash_hash (
     245             :             ip60->src_address.as_u64[0], ip60->src_address.as_u64[1],
     246             :             ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], ports);
     247             :         }
     248             : 
     249         500 :       if (per_port_vip)
     250             :         {
     251         300 :           key.protocol = ip60->protocol;
     252         300 :           key.port = (u16)(ports & 0xFFFF);
     253             :         }
     254             :     }
     255             : 
     256             :   /* For per-port-vip case, retrieve vip index for vip_port_filter table */
     257        1300 :   if (per_port_vip)
     258             :     {
     259         800 :       kv.key = key.as_u64;
     260         800 :       if (clib_bihash_search_8_8(&lbm->vip_index_per_port, &kv, &value) < 0)
     261             :         {
     262             :           /* return default vip */
     263           0 :           *vip_idx = 0;
     264           0 :           return;
     265             :         }
     266         800 :       *vip_idx = value.value;
     267             :     }
     268             : }
     269             : 
     270             : /* clang-format off */
     271             : static_always_inline uword
     272          13 : lb_node_fn (vlib_main_t * vm,
     273             :             vlib_node_runtime_t * node,
     274             :             vlib_frame_t * frame,
     275             :             u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6)
     276             :             lb_encap_type_t encap_type, //Compile-time parameter is GRE4/GRE6/L3DSR/NAT4/NAT6
     277             :             u8 per_port_vip, //Compile-time parameter stating that is per_port_vip or not
     278             :             u8 src_ip_sticky) //Compile-time parameter stating that is source ip based sticky or not
     279             : {
     280          13 :   lb_main_t *lbm = &lb_main;
     281             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     282          13 :   u32 thread_index = vm->thread_index;
     283          13 :   u32 lb_time = lb_hash_time_now (vm);
     284             : 
     285          13 :   lb_hash_t *sticky_ht = lb_get_sticky_table (thread_index);
     286          13 :   from = vlib_frame_vector_args (frame);
     287          13 :   n_left_from = frame->n_vectors;
     288          13 :   next_index = node->cached_next_index;
     289             : 
     290          13 :   u32 nexthash0 = 0;
     291          13 :   u32 next_vip_idx0 = ~0;
     292          13 :   if (PREDICT_TRUE(n_left_from > 0))
     293             :     {
     294          13 :       vlib_buffer_t *p0 = vlib_get_buffer (vm, from[0]);
     295          13 :       lb_node_get_hash (lbm, p0, is_input_v4, &nexthash0,
     296             :                         &next_vip_idx0, per_port_vip, src_ip_sticky);
     297             :     }
     298             : 
     299          26 :   while (n_left_from > 0)
     300             :     {
     301          13 :       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     302        1313 :       while (n_left_from > 0 && n_left_to_next > 0)
     303             :         {
     304             :           u32 pi0;
     305             :           vlib_buffer_t *p0;
     306             :           lb_vip_t *vip0;
     307        1300 :           u32 asindex0 = 0;
     308             :           u16 len0;
     309             :           u32 available_index0;
     310        1300 :           u8 counter = 0;
     311        1300 :           u32 hash0 = nexthash0;
     312        1300 :           u32 vip_index0 = next_vip_idx0;
     313             :           u32 next0;
     314             : 
     315        1300 :           if (PREDICT_TRUE(n_left_from > 1))
     316             :             {
     317        1287 :               vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]);
     318             :               //Compute next hash and prefetch bucket
     319        1287 :               lb_node_get_hash (lbm, p1, is_input_v4,
     320             :                                 &nexthash0, &next_vip_idx0,
     321             :                                 per_port_vip, src_ip_sticky);
     322        1287 :               lb_hash_prefetch_bucket (sticky_ht, nexthash0);
     323             :               //Prefetch for encap, next
     324        1287 :               CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE);
     325             :             }
     326             : 
     327        1300 :           if (PREDICT_TRUE(n_left_from > 2))
     328             :             {
     329             :               vlib_buffer_t *p2;
     330        1274 :               p2 = vlib_get_buffer (vm, from[2]);
     331             :               /* prefetch packet header and data */
     332        1274 :               vlib_prefetch_buffer_header(p2, STORE);
     333        1274 :               CLIB_PREFETCH(vlib_buffer_get_current (p2), 64, STORE);
     334             :             }
     335             : 
     336        1300 :           pi0 = to_next[0] = from[0];
     337        1300 :           from += 1;
     338        1300 :           n_left_from -= 1;
     339        1300 :           to_next += 1;
     340        1300 :           n_left_to_next -= 1;
     341             : 
     342        1300 :           p0 = vlib_get_buffer (vm, pi0);
     343             : 
     344        1300 :           vip0 = pool_elt_at_index(lbm->vips, vip_index0);
     345             : 
     346        1300 :           if (is_input_v4)
     347             :             {
     348             :               ip4_header_t *ip40;
     349         800 :               ip40 = vlib_buffer_get_current (p0);
     350         800 :               len0 = clib_net_to_host_u16 (ip40->length);
     351             :             }
     352             :           else
     353             :             {
     354             :               ip6_header_t *ip60;
     355         500 :               ip60 = vlib_buffer_get_current (p0);
     356         500 :               len0 = clib_net_to_host_u16 (ip60->payload_length)
     357             :                   + sizeof(ip6_header_t);
     358             :             }
     359             : 
     360        1300 :           lb_hash_get (sticky_ht, hash0,
     361             :                        vip_index0, lb_time,
     362             :                        &available_index0, &asindex0);
     363             : 
     364        1300 :           if (PREDICT_TRUE(asindex0 != 0))
     365             :             {
     366             :               //Found an existing entry
     367          50 :               counter = LB_VIP_COUNTER_NEXT_PACKET;
     368             :             }
     369        1250 :           else if (PREDICT_TRUE(available_index0 != ~0))
     370             :             {
     371             :               //There is an available slot for a new flow
     372        1250 :               asindex0 =
     373        1250 :                   vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index;
     374        1250 :               counter = LB_VIP_COUNTER_FIRST_PACKET;
     375        1250 :               counter = (asindex0 == 0) ? LB_VIP_COUNTER_NO_SERVER : counter;
     376             : 
     377             :               //TODO: There are race conditions with as0 and vip0 manipulation.
     378             :               //Configuration may be changed, vectors resized, etc...
     379             : 
     380             :               //Dereference previously used
     381        1250 :               vlib_refcount_add (
     382             :                   &lbm->as_refcount, thread_index,
     383             :                   lb_hash_available_value (sticky_ht, hash0, available_index0),
     384             :                   -1);
     385        1250 :               vlib_refcount_add (&lbm->as_refcount, thread_index, asindex0, 1);
     386             : 
     387             :               //Add sticky entry
     388             :               //Note that when there is no AS configured, an entry is configured anyway.
     389             :               //But no configured AS is not something that should happen
     390        1250 :               lb_hash_put (sticky_ht, hash0, asindex0,
     391             :                            vip_index0,
     392             :                            available_index0, lb_time);
     393             :             }
     394             :           else
     395             :             {
     396             :               //Could not store new entry in the table
     397           0 :               asindex0 =
     398           0 :                   vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index;
     399           0 :               counter = LB_VIP_COUNTER_UNTRACKED_PACKET;
     400             :             }
     401             : 
     402        1300 :           vlib_increment_simple_counter (
     403        1300 :               &lbm->vip_counters[counter], thread_index,
     404             :               vip_index0,
     405             :               1);
     406             : 
     407             :           //Now let's encap
     408        1300 :           if ((encap_type == LB_ENCAP_TYPE_GRE4)
     409         900 :               || (encap_type == LB_ENCAP_TYPE_GRE6))
     410         800 :             {
     411             :               gre_header_t *gre0;
     412         800 :               if (encap_type == LB_ENCAP_TYPE_GRE4) /* encap GRE4*/
     413             :                 {
     414             :                   ip4_header_t *ip40;
     415         400 :                   vlib_buffer_advance (
     416             :                       p0, -sizeof(ip4_header_t) - sizeof(gre_header_t));
     417         400 :                   ip40 = vlib_buffer_get_current (p0);
     418         400 :                   gre0 = (gre_header_t *) (ip40 + 1);
     419         400 :                   ip40->src_address = lbm->ip4_src_address;
     420         400 :                   ip40->dst_address = lbm->ass[asindex0].address.ip4;
     421         400 :                   ip40->ip_version_and_header_length = 0x45;
     422         400 :                   ip40->ttl = 128;
     423         400 :                   ip40->fragment_id = 0;
     424         400 :                   ip40->flags_and_fragment_offset = 0;
     425         800 :                   ip40->length = clib_host_to_net_u16 (
     426         400 :                       len0 + sizeof(gre_header_t) + sizeof(ip4_header_t));
     427         400 :                   ip40->protocol = IP_PROTOCOL_GRE;
     428         400 :                   ip40->checksum = ip4_header_checksum (ip40);
     429             :                 }
     430             :               else /* encap GRE6*/
     431             :                 {
     432             :                   ip6_header_t *ip60;
     433         400 :                   vlib_buffer_advance (
     434             :                       p0, -sizeof(ip6_header_t) - sizeof(gre_header_t));
     435         400 :                   ip60 = vlib_buffer_get_current (p0);
     436         400 :                   gre0 = (gre_header_t *) (ip60 + 1);
     437         400 :                   ip60->dst_address = lbm->ass[asindex0].address.ip6;
     438         400 :                   ip60->src_address = lbm->ip6_src_address;
     439         400 :                   ip60->hop_limit = 128;
     440         400 :                   ip60->ip_version_traffic_class_and_flow_label =
     441         400 :                       clib_host_to_net_u32 (0x6 << 28);
     442         800 :                   ip60->payload_length = clib_host_to_net_u16 (
     443         400 :                       len0 + sizeof(gre_header_t));
     444         400 :                   ip60->protocol = IP_PROTOCOL_GRE;
     445             :                 }
     446             : 
     447         800 :               gre0->flags_and_version = 0;
     448        1600 :               gre0->protocol =
     449             :                   (is_input_v4) ?
     450         400 :                       clib_host_to_net_u16 (0x0800) :
     451         400 :                       clib_host_to_net_u16 (0x86DD);
     452             :             }
     453         500 :           else if (encap_type == LB_ENCAP_TYPE_L3DSR) /* encap L3DSR*/
     454             :             {
     455             :               ip4_header_t *ip40;
     456             :               ip_csum_t csum;
     457             :               u32 old_dst, new_dst;
     458             :               u8 old_tos, new_tos;
     459             : 
     460         300 :               ip40 = vlib_buffer_get_current (p0);
     461         300 :               old_dst = ip40->dst_address.as_u32;
     462         300 :               new_dst = lbm->ass[asindex0].address.ip4.as_u32;
     463         300 :               ip40->dst_address.as_u32 = lbm->ass[asindex0].address.ip4.as_u32;
     464             :               /* Get and rewrite DSCP bit */
     465         300 :               old_tos = ip40->tos;
     466         300 :               new_tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2);
     467         300 :               ip40->tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2);
     468             : 
     469         300 :               csum = ip40->checksum;
     470         300 :               csum = ip_csum_update (csum, old_tos, new_tos,
     471             :                                      ip4_header_t,
     472             :                                      tos /* changed member */);
     473         300 :               csum = ip_csum_update (csum, old_dst, new_dst,
     474             :                                      ip4_header_t,
     475             :                                      dst_address /* changed member */);
     476         300 :               ip40->checksum = ip_csum_fold (csum);
     477             : 
     478             :               /* Recomputing L4 checksum after dst-IP modifying */
     479         300 :               if (ip40->protocol == IP_PROTOCOL_TCP)
     480             :                 {
     481             :                   tcp_header_t *th0;
     482           0 :                   th0 = ip4_next_header (ip40);
     483           0 :                   th0->checksum = 0;
     484           0 :                   th0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40);
     485             :                 }
     486         300 :               else if (ip40->protocol == IP_PROTOCOL_UDP)
     487             :                 {
     488             :                   udp_header_t *uh0;
     489         300 :                   uh0 = ip4_next_header (ip40);
     490         300 :                   uh0->checksum = 0;
     491         300 :                   uh0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40);
     492             :                 }
     493             :             }
     494         200 :           else if ((encap_type == LB_ENCAP_TYPE_NAT4)
     495         100 :               || (encap_type == LB_ENCAP_TYPE_NAT6))
     496             :             {
     497             :               ip_csum_t csum;
     498             :               udp_header_t *uh;
     499             : 
     500             :               /* do NAT */
     501         200 :               if ((is_input_v4 == 1) && (encap_type == LB_ENCAP_TYPE_NAT4))
     502         100 :                 {
     503             :                   /* NAT44 */
     504             :                   ip4_header_t *ip40;
     505             :                   u32 old_dst;
     506         100 :                   ip40 = vlib_buffer_get_current (p0);
     507         100 :                   uh = (udp_header_t *) (ip40 + 1);
     508         100 :                   old_dst = ip40->dst_address.as_u32;
     509         100 :                   ip40->dst_address = lbm->ass[asindex0].address.ip4;
     510             : 
     511         100 :                   csum = ip40->checksum;
     512         100 :                   csum = ip_csum_sub_even (csum, old_dst);
     513         100 :                   csum = ip_csum_add_even (
     514         100 :                       csum, lbm->ass[asindex0].address.ip4.as_u32);
     515         100 :                   ip40->checksum = ip_csum_fold (csum);
     516             : 
     517         100 :                   if (ip40->protocol == IP_PROTOCOL_UDP)
     518             :                     {
     519         100 :                       uh->dst_port = vip0->encap_args.target_port;
     520         100 :                       csum = uh->checksum;
     521         100 :                       csum = ip_csum_sub_even (csum, old_dst);
     522         100 :                       csum = ip_csum_add_even (
     523         100 :                           csum, lbm->ass[asindex0].address.ip4.as_u32);
     524         100 :                       uh->checksum = ip_csum_fold (csum);
     525             :                     }
     526             :                   else
     527             :                     {
     528           0 :                       asindex0 = 0;
     529             :                     }
     530             :                 }
     531         100 :               else if ((is_input_v4 == 0) && (encap_type == LB_ENCAP_TYPE_NAT6))
     532             :                 {
     533             :                   /* NAT66 */
     534             :                   ip6_header_t *ip60;
     535             :                   ip6_address_t old_dst;
     536             : 
     537         100 :                   ip60 = vlib_buffer_get_current (p0);
     538         100 :                   uh = (udp_header_t *) (ip60 + 1);
     539             : 
     540         100 :                   old_dst.as_u64[0] = ip60->dst_address.as_u64[0];
     541         100 :                   old_dst.as_u64[1] = ip60->dst_address.as_u64[1];
     542         100 :                   ip60->dst_address.as_u64[0] =
     543         100 :                       lbm->ass[asindex0].address.ip6.as_u64[0];
     544         100 :                   ip60->dst_address.as_u64[1] =
     545         100 :                       lbm->ass[asindex0].address.ip6.as_u64[1];
     546             : 
     547         100 :                   if (PREDICT_TRUE(ip60->protocol == IP_PROTOCOL_UDP))
     548             :                     {
     549         100 :                       uh->dst_port = vip0->encap_args.target_port;
     550         100 :                       csum = uh->checksum;
     551         100 :                       csum = ip_csum_sub_even (csum, old_dst.as_u64[0]);
     552         100 :                       csum = ip_csum_sub_even (csum, old_dst.as_u64[1]);
     553         100 :                       csum = ip_csum_add_even (
     554         100 :                           csum, lbm->ass[asindex0].address.ip6.as_u64[0]);
     555         100 :                       csum = ip_csum_add_even (
     556         100 :                           csum, lbm->ass[asindex0].address.ip6.as_u64[1]);
     557         100 :                       uh->checksum = ip_csum_fold (csum);
     558             :                     }
     559             :                   else
     560             :                     {
     561           0 :                       asindex0 = 0;
     562             :                     }
     563             :                 }
     564             :             }
     565        1300 :           next0 = lbm->ass[asindex0].dpo.dpoi_next_node;
     566             :           //Note that this is going to error if asindex0 == 0
     567        1300 :           vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
     568        1300 :               lbm->ass[asindex0].dpo.dpoi_index;
     569             : 
     570        1300 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     571             :             {
     572        1300 :               lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof(*tr));
     573        1300 :               tr->as_index = asindex0;
     574        1300 :               tr->vip_index = vip_index0;
     575             :             }
     576             : 
     577             :           //Enqueue to next
     578        1300 :           vlib_validate_buffer_enqueue_x1(
     579             :               vm, node, next_index, to_next, n_left_to_next, pi0, next0);
     580             :         }
     581          13 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     582             :     }
     583             : 
     584          13 :   return frame->n_vectors;
     585             : }
     586             : /* clang-format on */
     587             : 
     588             : u8 *
     589           0 : format_nodeport_lb_trace (u8 * s, va_list * args)
     590             : {
     591           0 :   lb_main_t *lbm = &lb_main;
     592           0 :   CLIB_UNUSED(vlib_main_t * vm)
     593             : = va_arg (*args, vlib_main_t *);
     594           0 :     CLIB_UNUSED(vlib_node_t * node)
     595             :   = va_arg (*args, vlib_node_t *);
     596           0 :   lb_nodeport_trace_t *t = va_arg (*args, lb_nodeport_trace_t *);
     597           0 :   if (pool_is_free_index(lbm->vips, t->vip_index))
     598             :     {
     599           0 :       s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
     600             :     }
     601             :   else
     602             :     {
     603           0 :       s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
     604           0 :                   &lbm->vips[t->vip_index]);
     605             :     }
     606             : 
     607           0 :   s = format (s, "  lb node_port: %d", t->node_port);
     608             : 
     609           0 :   return s;
     610             : }
     611             : 
     612             : static uword
     613           0 : lb_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     614             :                      vlib_frame_t * frame, u8 is_input_v4)
     615             : {
     616           0 :   lb_main_t *lbm = &lb_main;
     617             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     618             : 
     619           0 :   from = vlib_frame_vector_args (frame);
     620           0 :   n_left_from = frame->n_vectors;
     621           0 :   next_index = node->cached_next_index;
     622             : 
     623           0 :   while (n_left_from > 0)
     624             :     {
     625           0 :       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     626             : 
     627           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     628             :         {
     629             :           u32 pi0;
     630             :           vlib_buffer_t *p0;
     631             :           udp_header_t * udp_0;
     632             :           uword * entry0;
     633             : 
     634           0 :           if (PREDICT_TRUE(n_left_from > 1))
     635             :             {
     636           0 :               vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]);
     637             :               //Prefetch for encap, next
     638           0 :               CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE);
     639             :             }
     640             : 
     641           0 :           if (PREDICT_TRUE(n_left_from > 2))
     642             :             {
     643             :               vlib_buffer_t *p2;
     644           0 :               p2 = vlib_get_buffer (vm, from[2]);
     645             :               /* prefetch packet header and data */
     646           0 :               vlib_prefetch_buffer_header(p2, STORE);
     647           0 :               CLIB_PREFETCH(vlib_buffer_get_current (p2), 64, STORE);
     648             :             }
     649             : 
     650           0 :           pi0 = to_next[0] = from[0];
     651           0 :           from += 1;
     652           0 :           n_left_from -= 1;
     653           0 :           to_next += 1;
     654           0 :           n_left_to_next -= 1;
     655             : 
     656           0 :           p0 = vlib_get_buffer (vm, pi0);
     657             : 
     658           0 :           if (is_input_v4)
     659             :             {
     660             :               ip4_header_t *ip40;
     661           0 :               vlib_buffer_advance (
     662             :                   p0, -(word) (sizeof(udp_header_t) + sizeof(ip4_header_t)));
     663           0 :               ip40 = vlib_buffer_get_current (p0);
     664           0 :               udp_0 = (udp_header_t *) (ip40 + 1);
     665             :             }
     666             :           else
     667             :             {
     668             :               ip6_header_t *ip60;
     669           0 :               vlib_buffer_advance (
     670             :                   p0, -(word) (sizeof(udp_header_t) + sizeof(ip6_header_t)));
     671           0 :               ip60 = vlib_buffer_get_current (p0);
     672           0 :               udp_0 = (udp_header_t *) (ip60 + 1);
     673             :             }
     674             : 
     675           0 :           entry0 = hash_get_mem(lbm->vip_index_by_nodeport, &(udp_0->dst_port));
     676             : 
     677             :           //Enqueue to next
     678           0 :           vnet_buffer(p0)->ip.adj_index[VLIB_TX] = entry0 ? entry0[0]
     679             :               : ADJ_INDEX_INVALID;
     680             : 
     681           0 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     682             :             {
     683           0 :               lb_nodeport_trace_t *tr = vlib_add_trace (vm, node, p0,
     684             :                                                         sizeof(*tr));
     685           0 :               tr->vip_index = entry0 ? entry0[0] : ADJ_INDEX_INVALID;
     686           0 :               tr->node_port = (u32) clib_net_to_host_u16 (udp_0->dst_port);
     687             :             }
     688             : 
     689           0 :           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     690             :               n_left_to_next, pi0,
     691             :               is_input_v4 ?
     692             :                   LB4_NODEPORT_NEXT_IP4_NAT4 : LB6_NODEPORT_NEXT_IP6_NAT6);
     693             :         }
     694           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     695             :     }
     696             : 
     697           0 :   return frame->n_vectors;
     698             : 
     699             : }
     700             : 
     701             : /**
     702             :  * @brief Match NAT44 static mapping.
     703             :  *
     704             :  * @param sm          NAT main.
     705             :  * @param match       Address and port to match.
     706             :  * @param index       index to the pool.
     707             :  *
     708             :  * @returns 0 if match found, otherwise -1.
     709             :  */
     710             : int
     711           0 : lb_nat44_mapping_match (lb_main_t *lbm, lb_snat4_key_t * match, u32 *index)
     712             : {
     713             :   clib_bihash_kv_8_8_t kv4, value;
     714           0 :   clib_bihash_8_8_t *mapping_hash = &lbm->mapping_by_as4;
     715             : 
     716           0 :   kv4.key = match->as_u64;
     717           0 :   kv4.value = 0;
     718           0 :   if (clib_bihash_search_8_8 (mapping_hash, &kv4, &value))
     719             :     {
     720           0 :       return 1;
     721             :     }
     722             : 
     723           0 :   *index = value.value;
     724           0 :   return 0;
     725             : }
     726             : 
     727             : /**
     728             :  * @brief Match NAT66 static mapping.
     729             :  *
     730             :  * @param sm          NAT main.
     731             :  * @param match       Address and port to match.
     732             :  * @param mapping     External or local address and port of the matched mapping.
     733             :  *
     734             :  * @returns 0 if match found otherwise 1.
     735             :  */
     736             : int
     737           0 : lb_nat66_mapping_match (lb_main_t *lbm, lb_snat6_key_t * match, u32 *index)
     738             : {
     739             :   clib_bihash_kv_24_8_t kv6, value;
     740             :   lb_snat6_key_t m_key6;
     741           0 :   clib_bihash_24_8_t *mapping_hash = &lbm->mapping_by_as6;
     742             : 
     743           0 :   m_key6.addr.as_u64[0] = match->addr.as_u64[0];
     744           0 :   m_key6.addr.as_u64[1] = match->addr.as_u64[1];
     745           0 :   m_key6.port = match->port;
     746           0 :   m_key6.protocol = 0;
     747           0 :   m_key6.fib_index = 0;
     748             : 
     749           0 :   kv6.key[0] = m_key6.as_u64[0];
     750           0 :   kv6.key[1] = m_key6.as_u64[1];
     751           0 :   kv6.key[2] = m_key6.as_u64[2];
     752           0 :   kv6.value = 0;
     753           0 :   if (clib_bihash_search_24_8 (mapping_hash, &kv6, &value))
     754             :     {
     755           0 :       return 1;
     756             :     }
     757             : 
     758           0 :   *index = value.value;
     759           0 :   return 0;
     760             : }
     761             : 
     762             : static uword
     763           0 : lb_nat_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     764             :                        vlib_frame_t * frame, u32 is_nat4)
     765             : {
     766             :   u32 n_left_from, *from, *to_next;
     767             :   u32 next_index;
     768           0 :   u32 pkts_processed = 0;
     769           0 :   lb_main_t *lbm = &lb_main;
     770             :   u32 stats_node_index;
     771             : 
     772           0 :   stats_node_index =
     773           0 :       is_nat4 ? lb_nat4_in2out_node.index : lb_nat6_in2out_node.index;
     774             : 
     775           0 :   from = vlib_frame_vector_args (frame);
     776           0 :   n_left_from = frame->n_vectors;
     777           0 :   next_index = node->cached_next_index;
     778             : 
     779           0 :   while (n_left_from > 0)
     780             :     {
     781             :       u32 n_left_to_next;
     782             : 
     783           0 :       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     784             : 
     785           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     786             :         {
     787             :           u32 bi0;
     788             :           vlib_buffer_t * b0;
     789             :           u32 next0;
     790             :           u32 sw_if_index0;
     791             :           ip_csum_t csum;
     792             :           u16 old_port0, new_port0;
     793             :           udp_header_t * udp0;
     794             :           tcp_header_t * tcp0;
     795             : 
     796             :           u32 proto0;
     797             :           u32 rx_fib_index0;
     798             : 
     799             :           /* speculatively enqueue b0 to the current next frame */
     800           0 :           bi0 = from[0];
     801           0 :           to_next[0] = bi0;
     802           0 :           from += 1;
     803           0 :           to_next += 1;
     804           0 :           n_left_from -= 1;
     805           0 :           n_left_to_next -= 1;
     806             : 
     807           0 :           b0 = vlib_get_buffer (vm, bi0);
     808           0 :           next0 = LB_NAT4_IN2OUT_NEXT_LOOKUP;
     809           0 :           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
     810           0 :           rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (
     811             :               sw_if_index0);
     812             : 
     813           0 :           if (is_nat4)
     814             :             {
     815             :               ip4_header_t * ip40;
     816             :               u32 old_addr0, new_addr0;
     817             :               lb_snat4_key_t key40;
     818             :               lb_snat_mapping_t *sm40;
     819             :               u32 index40;
     820             : 
     821           0 :               ip40 = vlib_buffer_get_current (b0);
     822           0 :               udp0 = ip4_next_header (ip40);
     823           0 :               tcp0 = (tcp_header_t *) udp0;
     824           0 :               proto0 = lb_ip_proto_to_nat_proto (ip40->protocol);
     825             : 
     826           0 :               key40.addr = ip40->src_address;
     827           0 :               key40.protocol = proto0;
     828           0 :               key40.port = udp0->src_port;
     829           0 :               key40.fib_index = rx_fib_index0;
     830             : 
     831           0 :               if (lb_nat44_mapping_match (lbm, &key40, &index40))
     832             :                 {
     833           0 :                   next0 = LB_NAT4_IN2OUT_NEXT_DROP;
     834           0 :                   goto trace0;
     835             :                 }
     836             : 
     837           0 :               sm40 = pool_elt_at_index(lbm->snat_mappings, index40);
     838           0 :               new_addr0 = sm40->src_ip.ip4.as_u32;
     839           0 :               new_port0 = sm40->src_port;
     840           0 :               vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm40->fib_index;
     841           0 :               old_addr0 = ip40->src_address.as_u32;
     842           0 :               ip40->src_address.as_u32 = new_addr0;
     843             : 
     844           0 :               csum = ip40->checksum;
     845           0 :               csum = ip_csum_sub_even (csum, old_addr0);
     846           0 :               csum = ip_csum_add_even (csum, new_addr0);
     847           0 :               ip40->checksum = ip_csum_fold (csum);
     848             : 
     849           0 :               if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_TCP))
     850             :                 {
     851           0 :                   old_port0 = tcp0->src_port;
     852           0 :                   tcp0->src_port = new_port0;
     853             : 
     854           0 :                   csum = tcp0->checksum;
     855           0 :                   csum = ip_csum_sub_even (csum, old_addr0);
     856           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     857           0 :                   csum = ip_csum_add_even (csum, new_addr0);
     858           0 :                   csum = ip_csum_add_even (csum, new_port0);
     859           0 :                   tcp0->checksum = ip_csum_fold (csum);
     860             :                 }
     861           0 :               else if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_UDP))
     862             :                 {
     863           0 :                   old_port0 = udp0->src_port;
     864           0 :                   udp0->src_port = new_port0;
     865             : 
     866           0 :                   csum = udp0->checksum;
     867           0 :                   csum = ip_csum_sub_even (csum, old_addr0);
     868           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     869           0 :                   csum = ip_csum_add_even (csum, new_addr0);
     870           0 :                   csum = ip_csum_add_even (csum, new_port0);
     871           0 :                   udp0->checksum = ip_csum_fold (csum);
     872             :                 }
     873             : 
     874           0 :               pkts_processed += next0 != LB_NAT4_IN2OUT_NEXT_DROP;
     875             :             }
     876             :           else
     877             :             {
     878             :               ip6_header_t * ip60;
     879             :               ip6_address_t old_addr0, new_addr0;
     880             :               lb_snat6_key_t key60;
     881             :               lb_snat_mapping_t *sm60;
     882             :               u32 index60;
     883             : 
     884           0 :               ip60 = vlib_buffer_get_current (b0);
     885           0 :               udp0 = ip6_next_header (ip60);
     886           0 :               tcp0 = (tcp_header_t *) udp0;
     887           0 :               proto0 = lb_ip_proto_to_nat_proto (ip60->protocol);
     888             : 
     889           0 :               key60.addr.as_u64[0] = ip60->src_address.as_u64[0];
     890           0 :               key60.addr.as_u64[1] = ip60->src_address.as_u64[1];
     891           0 :               key60.protocol = proto0;
     892           0 :               key60.port = udp0->src_port;
     893           0 :               key60.fib_index = rx_fib_index0;
     894             : 
     895           0 :               if (lb_nat66_mapping_match (lbm, &key60, &index60))
     896             :                 {
     897           0 :                   next0 = LB_NAT6_IN2OUT_NEXT_DROP;
     898           0 :                   goto trace0;
     899             :                 }
     900             : 
     901           0 :               sm60 = pool_elt_at_index(lbm->snat_mappings, index60);
     902           0 :               new_addr0.as_u64[0] = sm60->src_ip.as_u64[0];
     903           0 :               new_addr0.as_u64[1] = sm60->src_ip.as_u64[1];
     904           0 :               new_port0 = sm60->src_port;
     905           0 :               vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm60->fib_index;
     906           0 :               old_addr0.as_u64[0] = ip60->src_address.as_u64[0];
     907           0 :               old_addr0.as_u64[1] = ip60->src_address.as_u64[1];
     908           0 :               ip60->src_address.as_u64[0] = new_addr0.as_u64[0];
     909           0 :               ip60->src_address.as_u64[1] = new_addr0.as_u64[1];
     910             : 
     911           0 :               if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_TCP))
     912             :                 {
     913           0 :                   old_port0 = tcp0->src_port;
     914           0 :                   tcp0->src_port = new_port0;
     915             : 
     916           0 :                   csum = tcp0->checksum;
     917           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[0]);
     918           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[1]);
     919           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[0]);
     920           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[1]);
     921           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     922           0 :                   csum = ip_csum_add_even (csum, new_port0);
     923           0 :                   tcp0->checksum = ip_csum_fold (csum);
     924             :                 }
     925           0 :               else if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_UDP))
     926             :                 {
     927           0 :                   old_port0 = udp0->src_port;
     928           0 :                   udp0->src_port = new_port0;
     929             : 
     930           0 :                   csum = udp0->checksum;
     931           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[0]);
     932           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[1]);
     933           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[0]);
     934           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[1]);
     935           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     936           0 :                   csum = ip_csum_add_even (csum, new_port0);
     937           0 :                   udp0->checksum = ip_csum_fold (csum);
     938             :                 }
     939             : 
     940           0 :               pkts_processed += next0 != LB_NAT4_IN2OUT_NEXT_DROP;
     941             :             }
     942             : 
     943           0 :           trace0: if (PREDICT_FALSE(
     944             :               (node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     945             :             {
     946           0 :               lb_nat_trace_t *t = vlib_add_trace (vm, node, b0, sizeof(*t));
     947           0 :               t->rx_sw_if_index = sw_if_index0;
     948           0 :               t->next_index = next0;
     949             :             }
     950             : 
     951             :           /* verify speculative enqueue, maybe switch current next frame */
     952           0 :           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     953             :                                           n_left_to_next, bi0, next0);
     954             :         }
     955             : 
     956           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     957             :     }
     958             : 
     959           0 :   vlib_node_increment_counter (vm, stats_node_index,
     960             :                                LB_NAT_IN2OUT_ERROR_IN2OUT_PACKETS,
     961             :                                pkts_processed);
     962           0 :   return frame->n_vectors;
     963             : }
     964             : 
     965             : static uword
     966           1 : lb6_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     967             :                   vlib_frame_t * frame)
     968             : {
     969           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 0, 0);
     970             : }
     971             : 
     972             : static uword
     973           1 : lb6_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     974             :                   vlib_frame_t * frame)
     975             : {
     976           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 0, 0);
     977             : }
     978             : 
     979             : static uword
     980           1 : lb4_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     981             :                   vlib_frame_t * frame)
     982             : {
     983           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 0, 0);
     984             : }
     985             : 
     986             : static uword
     987           1 : lb4_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     988             :                   vlib_frame_t * frame)
     989             : {
     990           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 0, 0);
     991             : }
     992             : 
     993             : static uword
     994           1 : lb6_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     995             :                        vlib_frame_t * frame)
     996             : {
     997           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 1, 0);
     998             : }
     999             : 
    1000             : static uword
    1001           1 : lb6_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1002             :                        vlib_frame_t * frame)
    1003             : {
    1004           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 1, 0);
    1005             : }
    1006             : 
    1007             : static uword
    1008           1 : lb4_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1009             :                        vlib_frame_t * frame)
    1010             : {
    1011           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 1, 0);
    1012             : }
    1013             : 
    1014             : static uword
    1015           1 : lb4_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1016             :                        vlib_frame_t * frame)
    1017             : {
    1018           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 1, 0);
    1019             : }
    1020             : 
    1021             : static uword
    1022           1 : lb4_l3dsr_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1023             :                         vlib_frame_t * frame)
    1024             : {
    1025           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 0, 0);
    1026             : }
    1027             : 
    1028             : static uword
    1029           1 : lb4_l3dsr_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1030             :                         vlib_frame_t * frame)
    1031             : {
    1032           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 1, 0);
    1033             : }
    1034             : 
    1035             : static uword
    1036           1 : lb6_nat6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1037             :                        vlib_frame_t * frame)
    1038             : {
    1039           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_NAT6, 1, 0);
    1040             : }
    1041             : 
    1042             : static uword
    1043           1 : lb4_nat4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1044             :                        vlib_frame_t * frame)
    1045             : {
    1046           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_NAT4, 1, 0);
    1047             : }
    1048             : 
    1049             : static uword
    1050           0 : lb6_gre6_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1051             :                          vlib_frame_t *frame)
    1052             : {
    1053           0 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 0, 1);
    1054             : }
    1055             : 
    1056             : static uword
    1057           0 : lb6_gre4_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1058             :                          vlib_frame_t *frame)
    1059             : {
    1060           0 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 0, 1);
    1061             : }
    1062             : 
    1063             : static uword
    1064           0 : lb4_gre6_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1065             :                          vlib_frame_t *frame)
    1066             : {
    1067           0 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 0, 1);
    1068             : }
    1069             : 
    1070             : static uword
    1071           0 : lb4_gre4_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1072             :                          vlib_frame_t *frame)
    1073             : {
    1074           0 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 0, 1);
    1075             : }
    1076             : 
    1077             : static uword
    1078           0 : lb6_gre6_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1079             :                               vlib_frame_t *frame)
    1080             : {
    1081           0 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 1, 1);
    1082             : }
    1083             : 
    1084             : static uword
    1085           0 : lb6_gre4_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1086             :                               vlib_frame_t *frame)
    1087             : {
    1088           0 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 1, 1);
    1089             : }
    1090             : 
    1091             : static uword
    1092           0 : lb4_gre6_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1093             :                               vlib_frame_t *frame)
    1094             : {
    1095           0 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 1, 1);
    1096             : }
    1097             : 
    1098             : static uword
    1099           0 : lb4_gre4_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1100             :                               vlib_frame_t *frame)
    1101             : {
    1102           0 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 1, 1);
    1103             : }
    1104             : 
    1105             : static uword
    1106           0 : lb4_l3dsr_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1107             :                           vlib_frame_t *frame)
    1108             : {
    1109           0 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 0, 1);
    1110             : }
    1111             : 
    1112             : static uword
    1113           1 : lb4_l3dsr_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1114             :                                vlib_frame_t *frame)
    1115             : {
    1116           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 1, 1);
    1117             : }
    1118             : 
    1119             : static uword
    1120           0 : lb6_nat6_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1121             :                               vlib_frame_t *frame)
    1122             : {
    1123           0 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_NAT6, 1, 1);
    1124             : }
    1125             : 
    1126             : static uword
    1127           0 : lb4_nat4_port_sticky_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    1128             :                               vlib_frame_t *frame)
    1129             : {
    1130           0 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_NAT4, 1, 1);
    1131             : }
    1132             : 
    1133             : static uword
    1134           0 : lb_nat4_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1135             :                         vlib_frame_t * frame)
    1136             : {
    1137           0 :   return lb_nat_in2out_node_fn (vm, node, frame, 1);
    1138             : }
    1139             : 
    1140             : static uword
    1141           0 : lb_nat6_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1142             :                         vlib_frame_t * frame)
    1143             : {
    1144           0 :   return lb_nat_in2out_node_fn (vm, node, frame, 0);
    1145             : }
    1146             : 
    1147       91880 : VLIB_REGISTER_NODE (lb6_gre6_node) =
    1148             :   {
    1149             :     .function = lb6_gre6_node_fn,
    1150             :     .name = "lb6-gre6",
    1151             :     .vector_size = sizeof(u32),
    1152             :     .format_trace = format_lb_trace,
    1153             :     .n_errors = LB_N_ERROR,
    1154             :     .error_strings = lb_error_strings,
    1155             :     .n_next_nodes = LB_N_NEXT,
    1156             :     .next_nodes =
    1157             :         { [LB_NEXT_DROP] = "error-drop" },
    1158             :   };
    1159             : 
    1160       91880 : VLIB_REGISTER_NODE (lb6_gre4_node) =
    1161             :   {
    1162             :     .function = lb6_gre4_node_fn,
    1163             :     .name = "lb6-gre4",
    1164             :     .vector_size = sizeof(u32),
    1165             :     .format_trace = format_lb_trace,
    1166             :     .n_errors = LB_N_ERROR,
    1167             :     .error_strings = lb_error_strings,
    1168             :     .n_next_nodes = LB_N_NEXT,
    1169             :     .next_nodes =
    1170             :         { [LB_NEXT_DROP] = "error-drop" },
    1171             :   };
    1172             : 
    1173       91880 : VLIB_REGISTER_NODE (lb4_gre6_node) =
    1174             :   {
    1175             :     .function = lb4_gre6_node_fn,
    1176             :     .name = "lb4-gre6",
    1177             :     .vector_size = sizeof(u32),
    1178             :     .format_trace = format_lb_trace,
    1179             :     .n_errors = LB_N_ERROR,
    1180             :     .error_strings = lb_error_strings,
    1181             :     .n_next_nodes = LB_N_NEXT,
    1182             :     .next_nodes =
    1183             :         { [LB_NEXT_DROP] = "error-drop" },
    1184             :   };
    1185             : 
    1186       91880 : VLIB_REGISTER_NODE (lb4_gre4_node) =
    1187             :   {
    1188             :     .function = lb4_gre4_node_fn,
    1189             :     .name = "lb4-gre4",
    1190             :     .vector_size = sizeof(u32),
    1191             :     .format_trace = format_lb_trace,
    1192             :     .n_errors = LB_N_ERROR,
    1193             :     .error_strings = lb_error_strings,
    1194             :     .n_next_nodes = LB_N_NEXT,
    1195             :     .next_nodes =
    1196             :         { [LB_NEXT_DROP] = "error-drop" },
    1197             :   };
    1198             : 
    1199       91880 : VLIB_REGISTER_NODE (lb6_gre6_port_node) =
    1200             :   {
    1201             :     .function = lb6_gre6_port_node_fn,
    1202             :     .name = "lb6-gre6-port",
    1203             :     .vector_size = sizeof(u32),
    1204             :     .format_trace = format_lb_trace,
    1205             :     .n_errors = LB_N_ERROR,
    1206             :     .error_strings = lb_error_strings,
    1207             :     .n_next_nodes = LB_N_NEXT,
    1208             :     .next_nodes =
    1209             :         { [LB_NEXT_DROP] = "error-drop" },
    1210             :   };
    1211             : 
    1212       91880 : VLIB_REGISTER_NODE (lb6_gre4_port_node) =
    1213             :   {
    1214             :     .function = lb6_gre4_port_node_fn,
    1215             :     .name = "lb6-gre4-port",
    1216             :     .vector_size = sizeof(u32),
    1217             :     .format_trace = format_lb_trace,
    1218             :     .n_errors = LB_N_ERROR,
    1219             :     .error_strings = lb_error_strings,
    1220             :     .n_next_nodes = LB_N_NEXT,
    1221             :     .next_nodes =
    1222             :         { [LB_NEXT_DROP] = "error-drop" },
    1223             :   };
    1224             : 
    1225       91880 : VLIB_REGISTER_NODE (lb4_gre6_port_node) =
    1226             :   {
    1227             :     .function = lb4_gre6_port_node_fn,
    1228             :     .name = "lb4-gre6-port",
    1229             :     .vector_size = sizeof(u32),
    1230             :     .format_trace = format_lb_trace,
    1231             :     .n_errors = LB_N_ERROR,
    1232             :     .error_strings = lb_error_strings,
    1233             :     .n_next_nodes = LB_N_NEXT,
    1234             :     .next_nodes =
    1235             :         { [LB_NEXT_DROP] = "error-drop" },
    1236             :   };
    1237             : 
    1238       91880 : VLIB_REGISTER_NODE (lb4_gre4_port_node) =
    1239             :   {
    1240             :     .function = lb4_gre4_port_node_fn,
    1241             :     .name = "lb4-gre4-port",
    1242             :     .vector_size = sizeof(u32),
    1243             :     .format_trace = format_lb_trace,
    1244             :     .n_errors = LB_N_ERROR,
    1245             :     .error_strings = lb_error_strings,
    1246             :     .n_next_nodes = LB_N_NEXT,
    1247             :     .next_nodes =
    1248             :         { [LB_NEXT_DROP] = "error-drop" },
    1249             :   };
    1250             : 
    1251       91880 : VLIB_REGISTER_NODE (lb4_l3dsr_port_node) =
    1252             :   {
    1253             :     .function = lb4_l3dsr_port_node_fn,
    1254             :     .name = "lb4-l3dsr-port",
    1255             :     .vector_size = sizeof(u32),
    1256             :     .format_trace = format_lb_trace,
    1257             :     .n_errors = LB_N_ERROR,
    1258             :     .error_strings = lb_error_strings,
    1259             :     .n_next_nodes = LB_N_NEXT,
    1260             :     .next_nodes =
    1261             :         { [LB_NEXT_DROP] = "error-drop" },
    1262             :   };
    1263             : 
    1264       91880 : VLIB_REGISTER_NODE (lb4_l3dsr_node) =
    1265             :   {
    1266             :     .function = lb4_l3dsr_node_fn,
    1267             :     .name = "lb4-l3dsr",
    1268             :     .vector_size = sizeof(u32),
    1269             :     .format_trace = format_lb_trace,
    1270             :     .n_errors = LB_N_ERROR,
    1271             :     .error_strings = lb_error_strings,
    1272             :     .n_next_nodes = LB_N_NEXT,
    1273             :     .next_nodes =
    1274             :         { [LB_NEXT_DROP] = "error-drop" },
    1275             :   };
    1276             : 
    1277       91880 : VLIB_REGISTER_NODE (lb6_nat6_port_node) =
    1278             :   {
    1279             :     .function = lb6_nat6_port_node_fn,
    1280             :     .name = "lb6-nat6-port",
    1281             :     .vector_size = sizeof(u32),
    1282             :     .format_trace = format_lb_trace,
    1283             :     .n_errors = LB_N_ERROR,
    1284             :     .error_strings = lb_error_strings,
    1285             :     .n_next_nodes = LB_N_NEXT,
    1286             :     .next_nodes =
    1287             :         { [LB_NEXT_DROP] = "error-drop" },
    1288             :   };
    1289             : 
    1290       91880 : VLIB_REGISTER_NODE (lb4_nat4_port_node) =
    1291             :   {
    1292             :     .function = lb4_nat4_port_node_fn,
    1293             :     .name = "lb4-nat4-port",
    1294             :     .vector_size = sizeof(u32),
    1295             :     .format_trace = format_lb_trace,
    1296             :     .n_errors = LB_N_ERROR,
    1297             :     .error_strings = lb_error_strings,
    1298             :     .n_next_nodes = LB_N_NEXT,
    1299             :     .next_nodes =
    1300             :         { [LB_NEXT_DROP] = "error-drop" },
    1301             :   };
    1302             : 
    1303       91880 : VLIB_REGISTER_NODE (lb6_gre6_sticky_node) = {
    1304             :   .function = lb6_gre6_sticky_node_fn,
    1305             :   .name = "lb6-gre6-sticky",
    1306             :   .vector_size = sizeof (u32),
    1307             :   .format_trace = format_lb_trace,
    1308             :   .n_errors = LB_N_ERROR,
    1309             :   .error_strings = lb_error_strings,
    1310             :   .n_next_nodes = LB_N_NEXT,
    1311             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1312             : };
    1313             : 
    1314       91880 : VLIB_REGISTER_NODE (lb6_gre4_sticky_node) = {
    1315             :   .function = lb6_gre4_sticky_node_fn,
    1316             :   .name = "lb6-gre4-sticky",
    1317             :   .vector_size = sizeof (u32),
    1318             :   .format_trace = format_lb_trace,
    1319             :   .n_errors = LB_N_ERROR,
    1320             :   .error_strings = lb_error_strings,
    1321             :   .n_next_nodes = LB_N_NEXT,
    1322             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1323             : };
    1324             : 
    1325       91880 : VLIB_REGISTER_NODE (lb4_gre6_sticky_node) = {
    1326             :   .function = lb4_gre6_sticky_node_fn,
    1327             :   .name = "lb4-gre6-sticky",
    1328             :   .vector_size = sizeof (u32),
    1329             :   .format_trace = format_lb_trace,
    1330             :   .n_errors = LB_N_ERROR,
    1331             :   .error_strings = lb_error_strings,
    1332             :   .n_next_nodes = LB_N_NEXT,
    1333             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1334             : };
    1335             : 
    1336       91880 : VLIB_REGISTER_NODE (lb4_gre4_sticky_node) = {
    1337             :   .function = lb4_gre4_sticky_node_fn,
    1338             :   .name = "lb4-gre4-sticky",
    1339             :   .vector_size = sizeof (u32),
    1340             :   .format_trace = format_lb_trace,
    1341             :   .n_errors = LB_N_ERROR,
    1342             :   .error_strings = lb_error_strings,
    1343             :   .n_next_nodes = LB_N_NEXT,
    1344             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1345             : };
    1346             : 
    1347       91880 : VLIB_REGISTER_NODE (lb6_gre6_port_sticky_node) = {
    1348             :   .function = lb6_gre6_port_sticky_node_fn,
    1349             :   .name = "lb6-gre6-port-sticky",
    1350             :   .vector_size = sizeof (u32),
    1351             :   .format_trace = format_lb_trace,
    1352             :   .n_errors = LB_N_ERROR,
    1353             :   .error_strings = lb_error_strings,
    1354             :   .n_next_nodes = LB_N_NEXT,
    1355             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1356             : };
    1357             : 
    1358       91880 : VLIB_REGISTER_NODE (lb6_gre4_port_sticky_node) = {
    1359             :   .function = lb6_gre4_port_sticky_node_fn,
    1360             :   .name = "lb6-gre4-port-sticky",
    1361             :   .vector_size = sizeof (u32),
    1362             :   .format_trace = format_lb_trace,
    1363             :   .n_errors = LB_N_ERROR,
    1364             :   .error_strings = lb_error_strings,
    1365             :   .n_next_nodes = LB_N_NEXT,
    1366             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1367             : };
    1368             : 
    1369       91880 : VLIB_REGISTER_NODE (lb4_gre6_port_sticky_node) = {
    1370             :   .function = lb4_gre6_port_sticky_node_fn,
    1371             :   .name = "lb4-gre6-port-sticky",
    1372             :   .vector_size = sizeof (u32),
    1373             :   .format_trace = format_lb_trace,
    1374             :   .n_errors = LB_N_ERROR,
    1375             :   .error_strings = lb_error_strings,
    1376             :   .n_next_nodes = LB_N_NEXT,
    1377             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1378             : };
    1379             : 
    1380       91880 : VLIB_REGISTER_NODE (lb4_gre4_port_sticky_node) = {
    1381             :   .function = lb4_gre4_port_sticky_node_fn,
    1382             :   .name = "lb4-gre4-port-sticky",
    1383             :   .vector_size = sizeof (u32),
    1384             :   .format_trace = format_lb_trace,
    1385             :   .n_errors = LB_N_ERROR,
    1386             :   .error_strings = lb_error_strings,
    1387             :   .n_next_nodes = LB_N_NEXT,
    1388             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1389             : };
    1390             : 
    1391       91880 : VLIB_REGISTER_NODE (lb4_l3dsr_port_sticky_node) = {
    1392             :   .function = lb4_l3dsr_port_sticky_node_fn,
    1393             :   .name = "lb4-l3dsr-port-sticky",
    1394             :   .vector_size = sizeof (u32),
    1395             :   .format_trace = format_lb_trace,
    1396             :   .n_errors = LB_N_ERROR,
    1397             :   .error_strings = lb_error_strings,
    1398             :   .n_next_nodes = LB_N_NEXT,
    1399             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1400             : };
    1401             : 
    1402       91880 : VLIB_REGISTER_NODE (lb4_l3dsr_sticky_node) = {
    1403             :   .function = lb4_l3dsr_sticky_node_fn,
    1404             :   .name = "lb4-l3dsr-sticky",
    1405             :   .vector_size = sizeof (u32),
    1406             :   .format_trace = format_lb_trace,
    1407             :   .n_errors = LB_N_ERROR,
    1408             :   .error_strings = lb_error_strings,
    1409             :   .n_next_nodes = LB_N_NEXT,
    1410             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1411             : };
    1412             : 
    1413       91880 : VLIB_REGISTER_NODE (lb6_nat6_port_sticky_node) = {
    1414             :   .function = lb6_nat6_port_sticky_node_fn,
    1415             :   .name = "lb6-nat6-port-sticky",
    1416             :   .vector_size = sizeof (u32),
    1417             :   .format_trace = format_lb_trace,
    1418             :   .n_errors = LB_N_ERROR,
    1419             :   .error_strings = lb_error_strings,
    1420             :   .n_next_nodes = LB_N_NEXT,
    1421             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1422             : };
    1423             : 
    1424       91880 : VLIB_REGISTER_NODE (lb4_nat4_port_sticky_node) = {
    1425             :   .function = lb4_nat4_port_sticky_node_fn,
    1426             :   .name = "lb4-nat4-port-sticky",
    1427             :   .vector_size = sizeof (u32),
    1428             :   .format_trace = format_lb_trace,
    1429             :   .n_errors = LB_N_ERROR,
    1430             :   .error_strings = lb_error_strings,
    1431             :   .n_next_nodes = LB_N_NEXT,
    1432             :   .next_nodes = { [LB_NEXT_DROP] = "error-drop" },
    1433             : };
    1434             : 
    1435             : static uword
    1436           0 : lb4_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1437             :                       vlib_frame_t * frame)
    1438             : {
    1439           0 :   return lb_nodeport_node_fn (vm, node, frame, 1);
    1440             : }
    1441             : 
    1442             : static uword
    1443           0 : lb6_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1444             :                       vlib_frame_t * frame)
    1445             : {
    1446           0 :   return lb_nodeport_node_fn (vm, node, frame, 0);
    1447             : }
    1448             : 
    1449       91880 : VLIB_REGISTER_NODE (lb4_nodeport_node) =
    1450             :   {
    1451             :     .function = lb4_nodeport_node_fn,
    1452             :     .name = "lb4-nodeport",
    1453             :     .vector_size = sizeof(u32),
    1454             :     .format_trace = format_nodeport_lb_trace,
    1455             :     .n_errors = LB_N_ERROR,
    1456             :     .error_strings = lb_error_strings,
    1457             :     .n_next_nodes = LB4_NODEPORT_N_NEXT,
    1458             :     .next_nodes =
    1459             :         {
    1460             :             [LB4_NODEPORT_NEXT_IP4_NAT4] = "lb4-nat4-port",
    1461             :             [LB4_NODEPORT_NEXT_DROP] = "error-drop",
    1462             :         },
    1463             :   };
    1464             : 
    1465       91880 : VLIB_REGISTER_NODE (lb6_nodeport_node) =
    1466             :   {
    1467             :     .function = lb6_nodeport_node_fn,
    1468             :     .name = "lb6-nodeport",
    1469             :     .vector_size = sizeof(u32),
    1470             :     .format_trace = format_nodeport_lb_trace,
    1471             :     .n_errors = LB_N_ERROR,
    1472             :     .error_strings = lb_error_strings,
    1473             :     .n_next_nodes = LB6_NODEPORT_N_NEXT,
    1474             :     .next_nodes =
    1475             :       {
    1476             :           [LB6_NODEPORT_NEXT_IP6_NAT6] = "lb6-nat6-port",
    1477             :           [LB6_NODEPORT_NEXT_DROP] = "error-drop",
    1478             :       },
    1479             :   };
    1480             : 
    1481       44823 : VNET_FEATURE_INIT (lb_nat4_in2out_node_fn, static) =
    1482             :   {
    1483             :     .arc_name = "ip4-unicast",
    1484             :     .node_name = "lb-nat4-in2out",
    1485             :     .runs_before =  VNET_FEATURES("ip4-lookup"),
    1486             :   };
    1487             : 
    1488       91880 : VLIB_REGISTER_NODE (lb_nat4_in2out_node) =
    1489             :   {
    1490             :     .function = lb_nat4_in2out_node_fn,
    1491             :     .name = "lb-nat4-in2out",
    1492             :     .vector_size = sizeof(u32),
    1493             :     .format_trace = format_lb_nat_trace,
    1494             :     .n_errors = LB_N_ERROR,
    1495             :     .error_strings = lb_error_strings,
    1496             :     .n_next_nodes = LB_NAT4_IN2OUT_N_NEXT,
    1497             :     .next_nodes =
    1498             :       {
    1499             :           [LB_NAT4_IN2OUT_NEXT_DROP] = "error-drop",
    1500             :           [LB_NAT4_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
    1501             :       },
    1502             :   };
    1503             : 
    1504       44823 : VNET_FEATURE_INIT (lb_nat6_in2out_node_fn, static) =
    1505             :   {
    1506             :     .arc_name = "ip6-unicast",
    1507             :     .node_name = "lb-nat6-in2out",
    1508             :     .runs_before = VNET_FEATURES("ip6-lookup"),
    1509             :   };
    1510             : 
    1511       91880 : VLIB_REGISTER_NODE (lb_nat6_in2out_node) =
    1512             :   {
    1513             :     .function = lb_nat6_in2out_node_fn,
    1514             :     .name = "lb-nat6-in2out",
    1515             :     .vector_size = sizeof(u32),
    1516             :     .format_trace = format_lb_nat_trace,
    1517             :     .n_errors = LB_N_ERROR,
    1518             :     .error_strings = lb_error_strings,
    1519             :     .n_next_nodes = LB_NAT6_IN2OUT_N_NEXT,
    1520             :     .next_nodes =
    1521             :       {
    1522             :           [LB_NAT6_IN2OUT_NEXT_DROP] = "error-drop",
    1523             :           [LB_NAT6_IN2OUT_NEXT_LOOKUP] = "ip6-lookup",
    1524             :       },
    1525             :   };

Generated by: LCOV version 1.14