LCOV - code coverage report
Current view: top level - plugins/lb - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 247 478 51.7 %
Date: 2023-10-26 01:39:38 Functions: 52 64 81.2 %

          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        1400 : format_lb_trace (u8 * s, va_list * args)
      64             : {
      65        1400 :   lb_main_t *lbm = &lb_main;
      66        1400 :   CLIB_UNUSED(vlib_main_t * vm)
      67             : = va_arg (*args, vlib_main_t *);
      68        1400 :     CLIB_UNUSED(vlib_node_t * node)
      69             :   = va_arg (*args, vlib_node_t *);
      70        1400 :   lb_trace_t *t = va_arg (*args, lb_trace_t *);
      71        1400 :   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        1400 :       s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
      78        1400 :                   &lbm->vips[t->vip_index]);
      79             :     }
      80        1400 :   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        1400 :       s = format (s, "lb as[%d]: %U\n", t->as_index, format_lb_as,
      87        1400 :                   &lbm->ass[t->as_index]);
      88             :     }
      89        1400 :   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          14 : lb_get_sticky_table (u32 thread_index)
     128             : {
     129          14 :   lb_main_t *lbm = &lb_main;
     130          14 :   lb_hash_t *sticky_ht = lbm->per_cpu[thread_index].sticky_ht;
     131             :   //Check if size changed
     132          14 :   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          14 :   if (PREDICT_FALSE(sticky_ht == NULL))
     150             :     {
     151          14 :       lbm->per_cpu[thread_index].sticky_ht = lb_hash_alloc (
     152             :           lbm->per_cpu_sticky_buckets, lbm->flow_timeout);
     153          14 :       sticky_ht = lbm->per_cpu[thread_index].sticky_ht;
     154          14 :       clib_warning("Regenerated sticky table %p", sticky_ht);
     155             :     }
     156             : 
     157          14 :   ASSERT(sticky_ht);
     158             : 
     159             :   //Update timeout
     160          14 :   sticky_ht->timeout = lbm->flow_timeout;
     161          14 :   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        1400 : 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)
     179             : {
     180             :   vip_port_key_t key;
     181             :   clib_bihash_kv_8_8_t kv, value;
     182             :   ip4_header_t *ip40;
     183             :   ip6_header_t *ip60;
     184             :   lb_vip_t *vip0;
     185             :   u64 ports;
     186             : 
     187             :   /* For vip case, retrieve vip index for ip lookup */
     188        1400 :   *vip_idx = vnet_buffer (p)->ip.adj_index[VLIB_TX];
     189             : 
     190             :   /* Extract the L4 port number from the packet */
     191        1400 :   if (is_input_v4)
     192             :     {
     193         900 :       ip40 = vlib_buffer_get_current (p);
     194         900 :       if (PREDICT_TRUE(
     195             :           ip40->protocol == IP_PROTOCOL_TCP
     196             :               || ip40->protocol == IP_PROTOCOL_UDP))
     197         900 :         ports = ((u64) ((udp_header_t *) (ip40 + 1))->src_port << 16)
     198         900 :             | ((u64) ((udp_header_t *) (ip40 + 1))->dst_port);
     199             :       else
     200           0 :         ports = lb_node_get_other_ports4 (ip40);
     201             :     }
     202             :   else
     203             :     {
     204         500 :       ip60 = vlib_buffer_get_current (p);
     205             : 
     206         500 :       if (PREDICT_TRUE(
     207             :           ip60->protocol == IP_PROTOCOL_TCP
     208             :               || ip60->protocol == IP_PROTOCOL_UDP))
     209         500 :         ports = ((u64) ((udp_header_t *) (ip60 + 1))->src_port << 16)
     210         500 :             | ((u64) ((udp_header_t *) (ip60 + 1))->dst_port);
     211             :       else
     212           0 :         ports = lb_node_get_other_ports6 (ip60);
     213             :     }
     214             : 
     215        1400 :   if (per_port_vip)
     216             :     {
     217             :       /* For per-port-vip case, ip lookup stores placeholder index */
     218         800 :       key.vip_prefix_index = *vip_idx;
     219         800 :       key.port = (u16) (ports & 0xFFFF);
     220         800 :       key.rsv = 0;
     221         800 :       if (is_input_v4)
     222             :         {
     223         500 :           key.protocol = ip40->protocol;
     224             :         }
     225             :       else
     226             :         {
     227         300 :           key.protocol = ip60->protocol;
     228             :         }
     229             : 
     230             :       /* For per-port-vip case, retrieve vip index for vip_port_filter table */
     231         800 :       kv.key = key.as_u64;
     232         800 :       if (clib_bihash_search_8_8 (&lbm->vip_index_per_port, &kv, &value) < 0)
     233             :         {
     234             :           /* Set default vip */
     235           0 :           *vip_idx = 0;
     236             :         }
     237             :       else
     238             :         {
     239         800 :           *vip_idx = value.value;
     240             :         }
     241             :     }
     242             : 
     243        1400 :   vip0 = pool_elt_at_index (lbm->vips, *vip_idx);
     244             : 
     245        1400 :   if (is_input_v4)
     246             :     {
     247         900 :       if (lb_vip_is_src_ip_sticky (vip0))
     248             :         {
     249         200 :           *hash = lb_hash_hash (*((u64 *) &ip40->address_pair), 0, 0, 0, 0);
     250             :         }
     251             :       else
     252             :         {
     253         700 :           *hash =
     254         700 :             lb_hash_hash (*((u64 *) &ip40->address_pair), ports, 0, 0, 0);
     255             :         }
     256             :     }
     257             :   else
     258             :     {
     259         500 :       if (lb_vip_is_src_ip_sticky (vip0))
     260             :         {
     261           0 :           *hash = lb_hash_hash (
     262             :             ip60->src_address.as_u64[0], ip60->src_address.as_u64[1],
     263             :             ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], 0);
     264             :         }
     265             :       else
     266             :         {
     267         500 :           *hash = lb_hash_hash (
     268             :             ip60->src_address.as_u64[0], ip60->src_address.as_u64[1],
     269             :             ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], ports);
     270             :         }
     271             :     }
     272        1400 : }
     273             : 
     274             : /* clang-format off */
     275             : static_always_inline uword
     276          14 : lb_node_fn (vlib_main_t * vm,
     277             :             vlib_node_runtime_t * node,
     278             :             vlib_frame_t * frame,
     279             :             u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6)
     280             :             lb_encap_type_t encap_type, //Compile-time parameter is GRE4/GRE6/L3DSR/NAT4/NAT6
     281             :             u8 per_port_vip) //Compile-time parameter stating that is per_port_vip or not
     282             : {
     283          14 :   lb_main_t *lbm = &lb_main;
     284             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     285          14 :   u32 thread_index = vm->thread_index;
     286          14 :   u32 lb_time = lb_hash_time_now (vm);
     287             : 
     288          14 :   lb_hash_t *sticky_ht = lb_get_sticky_table (thread_index);
     289          14 :   from = vlib_frame_vector_args (frame);
     290          14 :   n_left_from = frame->n_vectors;
     291          14 :   next_index = node->cached_next_index;
     292             : 
     293          14 :   u32 nexthash0 = 0;
     294          14 :   u32 next_vip_idx0 = ~0;
     295          14 :   if (PREDICT_TRUE(n_left_from > 0))
     296             :     {
     297          14 :       vlib_buffer_t *p0 = vlib_get_buffer (vm, from[0]);
     298          14 :       lb_node_get_hash (lbm, p0, is_input_v4, &nexthash0,
     299             :                         &next_vip_idx0, per_port_vip);
     300             :     }
     301             : 
     302          28 :   while (n_left_from > 0)
     303             :     {
     304          14 :       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     305        1414 :       while (n_left_from > 0 && n_left_to_next > 0)
     306             :         {
     307             :           u32 pi0;
     308             :           vlib_buffer_t *p0;
     309             :           lb_vip_t *vip0;
     310        1400 :           u32 asindex0 = 0;
     311             :           u16 len0;
     312             :           u32 available_index0;
     313        1400 :           u8 counter = 0;
     314        1400 :           u32 hash0 = nexthash0;
     315        1400 :           u32 vip_index0 = next_vip_idx0;
     316             :           u32 next0;
     317             : 
     318        1400 :           if (PREDICT_TRUE(n_left_from > 1))
     319             :             {
     320        1386 :               vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]);
     321             :               //Compute next hash and prefetch bucket
     322        1386 :               lb_node_get_hash (lbm, p1, is_input_v4,
     323             :                                 &nexthash0, &next_vip_idx0,
     324             :                                 per_port_vip);
     325        1386 :               lb_hash_prefetch_bucket (sticky_ht, nexthash0);
     326             :               //Prefetch for encap, next
     327        1386 :               CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE);
     328             :             }
     329             : 
     330        1400 :           if (PREDICT_TRUE(n_left_from > 2))
     331             :             {
     332             :               vlib_buffer_t *p2;
     333        1372 :               p2 = vlib_get_buffer (vm, from[2]);
     334             :               /* prefetch packet header and data */
     335        1372 :               vlib_prefetch_buffer_header(p2, STORE);
     336        1372 :               CLIB_PREFETCH(vlib_buffer_get_current (p2), 64, STORE);
     337             :             }
     338             : 
     339        1400 :           pi0 = to_next[0] = from[0];
     340        1400 :           from += 1;
     341        1400 :           n_left_from -= 1;
     342        1400 :           to_next += 1;
     343        1400 :           n_left_to_next -= 1;
     344             : 
     345        1400 :           p0 = vlib_get_buffer (vm, pi0);
     346             : 
     347        1400 :           vip0 = pool_elt_at_index(lbm->vips, vip_index0);
     348             : 
     349        1400 :           if (is_input_v4)
     350             :             {
     351             :               ip4_header_t *ip40;
     352         900 :               ip40 = vlib_buffer_get_current (p0);
     353         900 :               len0 = clib_net_to_host_u16 (ip40->length);
     354             :             }
     355             :           else
     356             :             {
     357             :               ip6_header_t *ip60;
     358         500 :               ip60 = vlib_buffer_get_current (p0);
     359         500 :               len0 = clib_net_to_host_u16 (ip60->payload_length)
     360             :                   + sizeof(ip6_header_t);
     361             :             }
     362             : 
     363        1400 :           lb_hash_get (sticky_ht, hash0,
     364             :                        vip_index0, lb_time,
     365             :                        &available_index0, &asindex0);
     366             : 
     367        1400 :           if (PREDICT_TRUE(asindex0 != 0))
     368             :             {
     369             :               //Found an existing entry
     370         100 :               counter = LB_VIP_COUNTER_NEXT_PACKET;
     371             :             }
     372        1300 :           else if (PREDICT_TRUE(available_index0 != ~0))
     373             :             {
     374             :               //There is an available slot for a new flow
     375        1300 :               asindex0 =
     376        1300 :                   vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index;
     377        1300 :               counter = LB_VIP_COUNTER_FIRST_PACKET;
     378        1300 :               counter = (asindex0 == 0) ? LB_VIP_COUNTER_NO_SERVER : counter;
     379             : 
     380             :               //TODO: There are race conditions with as0 and vip0 manipulation.
     381             :               //Configuration may be changed, vectors resized, etc...
     382             : 
     383             :               //Dereference previously used
     384        1300 :               vlib_refcount_add (
     385             :                   &lbm->as_refcount, thread_index,
     386             :                   lb_hash_available_value (sticky_ht, hash0, available_index0),
     387             :                   -1);
     388        1300 :               vlib_refcount_add (&lbm->as_refcount, thread_index, asindex0, 1);
     389             : 
     390             :               //Add sticky entry
     391             :               //Note that when there is no AS configured, an entry is configured anyway.
     392             :               //But no configured AS is not something that should happen
     393        1300 :               lb_hash_put (sticky_ht, hash0, asindex0,
     394             :                            vip_index0,
     395             :                            available_index0, lb_time);
     396             :             }
     397             :           else
     398             :             {
     399             :               //Could not store new entry in the table
     400           0 :               asindex0 =
     401           0 :                   vip0->new_flow_table[hash0 & vip0->new_flow_table_mask].as_index;
     402           0 :               counter = LB_VIP_COUNTER_UNTRACKED_PACKET;
     403             :             }
     404             : 
     405        1400 :           vlib_increment_simple_counter (
     406        1400 :               &lbm->vip_counters[counter], thread_index,
     407             :               vip_index0,
     408             :               1);
     409             : 
     410             :           //Now let's encap
     411        1400 :           if ((encap_type == LB_ENCAP_TYPE_GRE4)
     412        1000 :               || (encap_type == LB_ENCAP_TYPE_GRE6))
     413         800 :             {
     414             :               gre_header_t *gre0;
     415         800 :               if (encap_type == LB_ENCAP_TYPE_GRE4) /* encap GRE4*/
     416             :                 {
     417             :                   ip4_header_t *ip40;
     418         400 :                   vlib_buffer_advance (
     419             :                       p0, -sizeof(ip4_header_t) - sizeof(gre_header_t));
     420         400 :                   ip40 = vlib_buffer_get_current (p0);
     421         400 :                   gre0 = (gre_header_t *) (ip40 + 1);
     422         400 :                   ip40->src_address = lbm->ip4_src_address;
     423         400 :                   ip40->dst_address = lbm->ass[asindex0].address.ip4;
     424         400 :                   ip40->ip_version_and_header_length = 0x45;
     425         400 :                   ip40->ttl = 128;
     426         400 :                   ip40->fragment_id = 0;
     427         400 :                   ip40->flags_and_fragment_offset = 0;
     428         800 :                   ip40->length = clib_host_to_net_u16 (
     429         400 :                       len0 + sizeof(gre_header_t) + sizeof(ip4_header_t));
     430         400 :                   ip40->protocol = IP_PROTOCOL_GRE;
     431         400 :                   ip40->checksum = ip4_header_checksum (ip40);
     432             :                 }
     433             :               else /* encap GRE6*/
     434             :                 {
     435             :                   ip6_header_t *ip60;
     436         400 :                   vlib_buffer_advance (
     437             :                       p0, -sizeof(ip6_header_t) - sizeof(gre_header_t));
     438         400 :                   ip60 = vlib_buffer_get_current (p0);
     439         400 :                   gre0 = (gre_header_t *) (ip60 + 1);
     440         400 :                   ip60->dst_address = lbm->ass[asindex0].address.ip6;
     441         400 :                   ip60->src_address = lbm->ip6_src_address;
     442         400 :                   ip60->hop_limit = 128;
     443         400 :                   ip60->ip_version_traffic_class_and_flow_label =
     444         400 :                       clib_host_to_net_u32 (0x6 << 28);
     445         800 :                   ip60->payload_length = clib_host_to_net_u16 (
     446         400 :                       len0 + sizeof(gre_header_t));
     447         400 :                   ip60->protocol = IP_PROTOCOL_GRE;
     448             :                 }
     449             : 
     450         800 :               gre0->flags_and_version = 0;
     451        1600 :               gre0->protocol =
     452             :                   (is_input_v4) ?
     453         400 :                       clib_host_to_net_u16 (0x0800) :
     454         400 :                       clib_host_to_net_u16 (0x86DD);
     455             :             }
     456         600 :           else if (encap_type == LB_ENCAP_TYPE_L3DSR) /* encap L3DSR*/
     457             :             {
     458             :               ip4_header_t *ip40;
     459             :               ip_csum_t csum;
     460             :               u32 old_dst, new_dst;
     461             :               u8 old_tos, new_tos;
     462             : 
     463         400 :               ip40 = vlib_buffer_get_current (p0);
     464         400 :               old_dst = ip40->dst_address.as_u32;
     465         400 :               new_dst = lbm->ass[asindex0].address.ip4.as_u32;
     466         400 :               ip40->dst_address.as_u32 = lbm->ass[asindex0].address.ip4.as_u32;
     467             :               /* Get and rewrite DSCP bit */
     468         400 :               old_tos = ip40->tos;
     469         400 :               new_tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2);
     470         400 :               ip40->tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2);
     471             : 
     472         400 :               csum = ip40->checksum;
     473         400 :               csum = ip_csum_update (csum, old_tos, new_tos,
     474             :                                      ip4_header_t,
     475             :                                      tos /* changed member */);
     476         400 :               csum = ip_csum_update (csum, old_dst, new_dst,
     477             :                                      ip4_header_t,
     478             :                                      dst_address /* changed member */);
     479         400 :               ip40->checksum = ip_csum_fold (csum);
     480             : 
     481             :               /* Recomputing L4 checksum after dst-IP modifying */
     482         400 :               if (ip40->protocol == IP_PROTOCOL_TCP)
     483             :                 {
     484             :                   tcp_header_t *th0;
     485           0 :                   th0 = ip4_next_header (ip40);
     486           0 :                   th0->checksum = 0;
     487           0 :                   th0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40);
     488             :                 }
     489         400 :               else if (ip40->protocol == IP_PROTOCOL_UDP)
     490             :                 {
     491             :                   udp_header_t *uh0;
     492         400 :                   uh0 = ip4_next_header (ip40);
     493         400 :                   uh0->checksum = 0;
     494         400 :                   uh0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40);
     495             :                 }
     496             :             }
     497         200 :           else if ((encap_type == LB_ENCAP_TYPE_NAT4)
     498         100 :               || (encap_type == LB_ENCAP_TYPE_NAT6))
     499             :             {
     500             :               ip_csum_t csum;
     501             :               udp_header_t *uh;
     502             : 
     503             :               /* do NAT */
     504         200 :               if ((is_input_v4 == 1) && (encap_type == LB_ENCAP_TYPE_NAT4))
     505         100 :                 {
     506             :                   /* NAT44 */
     507             :                   ip4_header_t *ip40;
     508             :                   u32 old_dst;
     509         100 :                   ip40 = vlib_buffer_get_current (p0);
     510         100 :                   uh = (udp_header_t *) (ip40 + 1);
     511         100 :                   old_dst = ip40->dst_address.as_u32;
     512         100 :                   ip40->dst_address = lbm->ass[asindex0].address.ip4;
     513             : 
     514         100 :                   csum = ip40->checksum;
     515         100 :                   csum = ip_csum_sub_even (csum, old_dst);
     516         100 :                   csum = ip_csum_add_even (
     517         100 :                       csum, lbm->ass[asindex0].address.ip4.as_u32);
     518         100 :                   ip40->checksum = ip_csum_fold (csum);
     519             : 
     520         100 :                   if (ip40->protocol == IP_PROTOCOL_UDP)
     521             :                     {
     522         100 :                       uh->dst_port = vip0->encap_args.target_port;
     523         100 :                       csum = uh->checksum;
     524         100 :                       csum = ip_csum_sub_even (csum, old_dst);
     525         100 :                       csum = ip_csum_add_even (
     526         100 :                           csum, lbm->ass[asindex0].address.ip4.as_u32);
     527         100 :                       uh->checksum = ip_csum_fold (csum);
     528             :                     }
     529             :                   else
     530             :                     {
     531           0 :                       asindex0 = 0;
     532             :                     }
     533             :                 }
     534         100 :               else if ((is_input_v4 == 0) && (encap_type == LB_ENCAP_TYPE_NAT6))
     535             :                 {
     536             :                   /* NAT66 */
     537             :                   ip6_header_t *ip60;
     538             :                   ip6_address_t old_dst;
     539             : 
     540         100 :                   ip60 = vlib_buffer_get_current (p0);
     541         100 :                   uh = (udp_header_t *) (ip60 + 1);
     542             : 
     543         100 :                   old_dst.as_u64[0] = ip60->dst_address.as_u64[0];
     544         100 :                   old_dst.as_u64[1] = ip60->dst_address.as_u64[1];
     545         100 :                   ip60->dst_address.as_u64[0] =
     546         100 :                       lbm->ass[asindex0].address.ip6.as_u64[0];
     547         100 :                   ip60->dst_address.as_u64[1] =
     548         100 :                       lbm->ass[asindex0].address.ip6.as_u64[1];
     549             : 
     550         100 :                   if (PREDICT_TRUE(ip60->protocol == IP_PROTOCOL_UDP))
     551             :                     {
     552         100 :                       uh->dst_port = vip0->encap_args.target_port;
     553         100 :                       csum = uh->checksum;
     554         100 :                       csum = ip_csum_sub_even (csum, old_dst.as_u64[0]);
     555         100 :                       csum = ip_csum_sub_even (csum, old_dst.as_u64[1]);
     556         100 :                       csum = ip_csum_add_even (
     557         100 :                           csum, lbm->ass[asindex0].address.ip6.as_u64[0]);
     558         100 :                       csum = ip_csum_add_even (
     559         100 :                           csum, lbm->ass[asindex0].address.ip6.as_u64[1]);
     560         100 :                       uh->checksum = ip_csum_fold (csum);
     561             :                     }
     562             :                   else
     563             :                     {
     564           0 :                       asindex0 = 0;
     565             :                     }
     566             :                 }
     567             :             }
     568        1400 :           next0 = lbm->ass[asindex0].dpo.dpoi_next_node;
     569             :           //Note that this is going to error if asindex0 == 0
     570        1400 :           vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
     571        1400 :               lbm->ass[asindex0].dpo.dpoi_index;
     572             : 
     573        1400 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     574             :             {
     575        1400 :               lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof(*tr));
     576        1400 :               tr->as_index = asindex0;
     577        1400 :               tr->vip_index = vip_index0;
     578             :             }
     579             : 
     580             :           //Enqueue to next
     581        1400 :           vlib_validate_buffer_enqueue_x1(
     582             :               vm, node, next_index, to_next, n_left_to_next, pi0, next0);
     583             :         }
     584          14 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     585             :     }
     586             : 
     587          14 :   return frame->n_vectors;
     588             : }
     589             : /* clang-format on */
     590             : 
     591             : u8 *
     592           0 : format_nodeport_lb_trace (u8 * s, va_list * args)
     593             : {
     594           0 :   lb_main_t *lbm = &lb_main;
     595           0 :   CLIB_UNUSED(vlib_main_t * vm)
     596             : = va_arg (*args, vlib_main_t *);
     597           0 :     CLIB_UNUSED(vlib_node_t * node)
     598             :   = va_arg (*args, vlib_node_t *);
     599           0 :   lb_nodeport_trace_t *t = va_arg (*args, lb_nodeport_trace_t *);
     600           0 :   if (pool_is_free_index(lbm->vips, t->vip_index))
     601             :     {
     602           0 :       s = format (s, "lb vip[%d]: This VIP was freed since capture\n");
     603             :     }
     604             :   else
     605             :     {
     606           0 :       s = format (s, "lb vip[%d]: %U\n", t->vip_index, format_lb_vip,
     607           0 :                   &lbm->vips[t->vip_index]);
     608             :     }
     609             : 
     610           0 :   s = format (s, "  lb node_port: %d", t->node_port);
     611             : 
     612           0 :   return s;
     613             : }
     614             : 
     615             : static uword
     616           0 : lb_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     617             :                      vlib_frame_t * frame, u8 is_input_v4)
     618             : {
     619           0 :   lb_main_t *lbm = &lb_main;
     620             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     621             : 
     622           0 :   from = vlib_frame_vector_args (frame);
     623           0 :   n_left_from = frame->n_vectors;
     624           0 :   next_index = node->cached_next_index;
     625             : 
     626           0 :   while (n_left_from > 0)
     627             :     {
     628           0 :       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     629             : 
     630           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     631             :         {
     632             :           u32 pi0;
     633             :           vlib_buffer_t *p0;
     634             :           udp_header_t * udp_0;
     635             :           uword * entry0;
     636             : 
     637           0 :           if (PREDICT_TRUE(n_left_from > 1))
     638             :             {
     639           0 :               vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]);
     640             :               //Prefetch for encap, next
     641           0 :               CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE);
     642             :             }
     643             : 
     644           0 :           if (PREDICT_TRUE(n_left_from > 2))
     645             :             {
     646             :               vlib_buffer_t *p2;
     647           0 :               p2 = vlib_get_buffer (vm, from[2]);
     648             :               /* prefetch packet header and data */
     649           0 :               vlib_prefetch_buffer_header(p2, STORE);
     650           0 :               CLIB_PREFETCH(vlib_buffer_get_current (p2), 64, STORE);
     651             :             }
     652             : 
     653           0 :           pi0 = to_next[0] = from[0];
     654           0 :           from += 1;
     655           0 :           n_left_from -= 1;
     656           0 :           to_next += 1;
     657           0 :           n_left_to_next -= 1;
     658             : 
     659           0 :           p0 = vlib_get_buffer (vm, pi0);
     660             : 
     661           0 :           if (is_input_v4)
     662             :             {
     663             :               ip4_header_t *ip40;
     664           0 :               vlib_buffer_advance (
     665             :                   p0, -(word) (sizeof(udp_header_t) + sizeof(ip4_header_t)));
     666           0 :               ip40 = vlib_buffer_get_current (p0);
     667           0 :               udp_0 = (udp_header_t *) (ip40 + 1);
     668             :             }
     669             :           else
     670             :             {
     671             :               ip6_header_t *ip60;
     672           0 :               vlib_buffer_advance (
     673             :                   p0, -(word) (sizeof(udp_header_t) + sizeof(ip6_header_t)));
     674           0 :               ip60 = vlib_buffer_get_current (p0);
     675           0 :               udp_0 = (udp_header_t *) (ip60 + 1);
     676             :             }
     677             : 
     678           0 :           entry0 = hash_get_mem(lbm->vip_index_by_nodeport, &(udp_0->dst_port));
     679             : 
     680             :           //Enqueue to next
     681           0 :           vnet_buffer(p0)->ip.adj_index[VLIB_TX] = entry0 ? entry0[0]
     682             :               : ADJ_INDEX_INVALID;
     683             : 
     684           0 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     685             :             {
     686           0 :               lb_nodeport_trace_t *tr = vlib_add_trace (vm, node, p0,
     687             :                                                         sizeof(*tr));
     688           0 :               tr->vip_index = entry0 ? entry0[0] : ADJ_INDEX_INVALID;
     689           0 :               tr->node_port = (u32) clib_net_to_host_u16 (udp_0->dst_port);
     690             :             }
     691             : 
     692           0 :           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     693             :               n_left_to_next, pi0,
     694             :               is_input_v4 ?
     695             :                   LB4_NODEPORT_NEXT_IP4_NAT4 : LB6_NODEPORT_NEXT_IP6_NAT6);
     696             :         }
     697           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     698             :     }
     699             : 
     700           0 :   return frame->n_vectors;
     701             : 
     702             : }
     703             : 
     704             : /**
     705             :  * @brief Match NAT44 static mapping.
     706             :  *
     707             :  * @param sm          NAT main.
     708             :  * @param match       Address and port to match.
     709             :  * @param index       index to the pool.
     710             :  *
     711             :  * @returns 0 if match found, otherwise -1.
     712             :  */
     713             : int
     714           0 : lb_nat44_mapping_match (lb_main_t *lbm, lb_snat4_key_t * match, u32 *index)
     715             : {
     716             :   clib_bihash_kv_8_8_t kv4, value;
     717           0 :   clib_bihash_8_8_t *mapping_hash = &lbm->mapping_by_as4;
     718             : 
     719           0 :   kv4.key = match->as_u64;
     720           0 :   kv4.value = 0;
     721           0 :   if (clib_bihash_search_8_8 (mapping_hash, &kv4, &value))
     722             :     {
     723           0 :       return 1;
     724             :     }
     725             : 
     726           0 :   *index = value.value;
     727           0 :   return 0;
     728             : }
     729             : 
     730             : /**
     731             :  * @brief Match NAT66 static mapping.
     732             :  *
     733             :  * @param sm          NAT main.
     734             :  * @param match       Address and port to match.
     735             :  * @param mapping     External or local address and port of the matched mapping.
     736             :  *
     737             :  * @returns 0 if match found otherwise 1.
     738             :  */
     739             : int
     740           0 : lb_nat66_mapping_match (lb_main_t *lbm, lb_snat6_key_t * match, u32 *index)
     741             : {
     742             :   clib_bihash_kv_24_8_t kv6, value;
     743             :   lb_snat6_key_t m_key6;
     744           0 :   clib_bihash_24_8_t *mapping_hash = &lbm->mapping_by_as6;
     745             : 
     746           0 :   m_key6.addr.as_u64[0] = match->addr.as_u64[0];
     747           0 :   m_key6.addr.as_u64[1] = match->addr.as_u64[1];
     748           0 :   m_key6.port = match->port;
     749           0 :   m_key6.protocol = 0;
     750           0 :   m_key6.fib_index = 0;
     751             : 
     752           0 :   kv6.key[0] = m_key6.as_u64[0];
     753           0 :   kv6.key[1] = m_key6.as_u64[1];
     754           0 :   kv6.key[2] = m_key6.as_u64[2];
     755           0 :   kv6.value = 0;
     756           0 :   if (clib_bihash_search_24_8 (mapping_hash, &kv6, &value))
     757             :     {
     758           0 :       return 1;
     759             :     }
     760             : 
     761           0 :   *index = value.value;
     762           0 :   return 0;
     763             : }
     764             : 
     765             : static uword
     766           0 : lb_nat_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     767             :                        vlib_frame_t * frame, u32 is_nat4)
     768             : {
     769             :   u32 n_left_from, *from, *to_next;
     770             :   u32 next_index;
     771           0 :   u32 pkts_processed = 0;
     772           0 :   lb_main_t *lbm = &lb_main;
     773             :   u32 stats_node_index;
     774             : 
     775           0 :   stats_node_index =
     776           0 :       is_nat4 ? lb_nat4_in2out_node.index : lb_nat6_in2out_node.index;
     777             : 
     778           0 :   from = vlib_frame_vector_args (frame);
     779           0 :   n_left_from = frame->n_vectors;
     780           0 :   next_index = node->cached_next_index;
     781             : 
     782           0 :   while (n_left_from > 0)
     783             :     {
     784             :       u32 n_left_to_next;
     785             : 
     786           0 :       vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     787             : 
     788           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     789             :         {
     790             :           u32 bi0;
     791             :           vlib_buffer_t * b0;
     792             :           u32 next0;
     793             :           u32 sw_if_index0;
     794             :           ip_csum_t csum;
     795             :           u16 old_port0, new_port0;
     796             :           udp_header_t * udp0;
     797             :           tcp_header_t * tcp0;
     798             : 
     799             :           u32 proto0;
     800             :           u32 rx_fib_index0;
     801             : 
     802             :           /* speculatively enqueue b0 to the current next frame */
     803           0 :           bi0 = from[0];
     804           0 :           to_next[0] = bi0;
     805           0 :           from += 1;
     806           0 :           to_next += 1;
     807           0 :           n_left_from -= 1;
     808           0 :           n_left_to_next -= 1;
     809             : 
     810           0 :           b0 = vlib_get_buffer (vm, bi0);
     811           0 :           next0 = LB_NAT4_IN2OUT_NEXT_LOOKUP;
     812           0 :           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
     813           0 :           rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (
     814             :               sw_if_index0);
     815             : 
     816           0 :           if (is_nat4)
     817             :             {
     818             :               ip4_header_t * ip40;
     819             :               u32 old_addr0, new_addr0;
     820             :               lb_snat4_key_t key40;
     821             :               lb_snat_mapping_t *sm40;
     822             :               u32 index40;
     823             : 
     824           0 :               ip40 = vlib_buffer_get_current (b0);
     825           0 :               udp0 = ip4_next_header (ip40);
     826           0 :               tcp0 = (tcp_header_t *) udp0;
     827           0 :               proto0 = lb_ip_proto_to_nat_proto (ip40->protocol);
     828             : 
     829           0 :               key40.addr = ip40->src_address;
     830           0 :               key40.protocol = proto0;
     831           0 :               key40.port = udp0->src_port;
     832           0 :               key40.fib_index = rx_fib_index0;
     833             : 
     834           0 :               if (lb_nat44_mapping_match (lbm, &key40, &index40))
     835             :                 {
     836           0 :                   next0 = LB_NAT4_IN2OUT_NEXT_DROP;
     837           0 :                   goto trace0;
     838             :                 }
     839             : 
     840           0 :               sm40 = pool_elt_at_index(lbm->snat_mappings, index40);
     841           0 :               new_addr0 = sm40->src_ip.ip4.as_u32;
     842           0 :               new_port0 = sm40->src_port;
     843           0 :               vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm40->fib_index;
     844           0 :               old_addr0 = ip40->src_address.as_u32;
     845           0 :               ip40->src_address.as_u32 = new_addr0;
     846             : 
     847           0 :               csum = ip40->checksum;
     848           0 :               csum = ip_csum_sub_even (csum, old_addr0);
     849           0 :               csum = ip_csum_add_even (csum, new_addr0);
     850           0 :               ip40->checksum = ip_csum_fold (csum);
     851             : 
     852           0 :               if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_TCP))
     853             :                 {
     854           0 :                   old_port0 = tcp0->src_port;
     855           0 :                   tcp0->src_port = new_port0;
     856             : 
     857           0 :                   csum = tcp0->checksum;
     858           0 :                   csum = ip_csum_sub_even (csum, old_addr0);
     859           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     860           0 :                   csum = ip_csum_add_even (csum, new_addr0);
     861           0 :                   csum = ip_csum_add_even (csum, new_port0);
     862           0 :                   tcp0->checksum = ip_csum_fold (csum);
     863             :                 }
     864           0 :               else if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_UDP))
     865             :                 {
     866           0 :                   old_port0 = udp0->src_port;
     867           0 :                   udp0->src_port = new_port0;
     868             : 
     869           0 :                   csum = udp0->checksum;
     870           0 :                   csum = ip_csum_sub_even (csum, old_addr0);
     871           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     872           0 :                   csum = ip_csum_add_even (csum, new_addr0);
     873           0 :                   csum = ip_csum_add_even (csum, new_port0);
     874           0 :                   udp0->checksum = ip_csum_fold (csum);
     875             :                 }
     876             : 
     877           0 :               pkts_processed += next0 != LB_NAT4_IN2OUT_NEXT_DROP;
     878             :             }
     879             :           else
     880             :             {
     881             :               ip6_header_t * ip60;
     882             :               ip6_address_t old_addr0, new_addr0;
     883             :               lb_snat6_key_t key60;
     884             :               lb_snat_mapping_t *sm60;
     885             :               u32 index60;
     886             : 
     887           0 :               ip60 = vlib_buffer_get_current (b0);
     888           0 :               udp0 = ip6_next_header (ip60);
     889           0 :               tcp0 = (tcp_header_t *) udp0;
     890           0 :               proto0 = lb_ip_proto_to_nat_proto (ip60->protocol);
     891             : 
     892           0 :               key60.addr.as_u64[0] = ip60->src_address.as_u64[0];
     893           0 :               key60.addr.as_u64[1] = ip60->src_address.as_u64[1];
     894           0 :               key60.protocol = proto0;
     895           0 :               key60.port = udp0->src_port;
     896           0 :               key60.fib_index = rx_fib_index0;
     897             : 
     898           0 :               if (lb_nat66_mapping_match (lbm, &key60, &index60))
     899             :                 {
     900           0 :                   next0 = LB_NAT6_IN2OUT_NEXT_DROP;
     901           0 :                   goto trace0;
     902             :                 }
     903             : 
     904           0 :               sm60 = pool_elt_at_index(lbm->snat_mappings, index60);
     905           0 :               new_addr0.as_u64[0] = sm60->src_ip.as_u64[0];
     906           0 :               new_addr0.as_u64[1] = sm60->src_ip.as_u64[1];
     907           0 :               new_port0 = sm60->src_port;
     908           0 :               vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm60->fib_index;
     909           0 :               old_addr0.as_u64[0] = ip60->src_address.as_u64[0];
     910           0 :               old_addr0.as_u64[1] = ip60->src_address.as_u64[1];
     911           0 :               ip60->src_address.as_u64[0] = new_addr0.as_u64[0];
     912           0 :               ip60->src_address.as_u64[1] = new_addr0.as_u64[1];
     913             : 
     914           0 :               if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_TCP))
     915             :                 {
     916           0 :                   old_port0 = tcp0->src_port;
     917           0 :                   tcp0->src_port = new_port0;
     918             : 
     919           0 :                   csum = tcp0->checksum;
     920           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[0]);
     921           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[1]);
     922           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[0]);
     923           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[1]);
     924           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     925           0 :                   csum = ip_csum_add_even (csum, new_port0);
     926           0 :                   tcp0->checksum = ip_csum_fold (csum);
     927             :                 }
     928           0 :               else if (PREDICT_TRUE(proto0 == LB_NAT_PROTOCOL_UDP))
     929             :                 {
     930           0 :                   old_port0 = udp0->src_port;
     931           0 :                   udp0->src_port = new_port0;
     932             : 
     933           0 :                   csum = udp0->checksum;
     934           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[0]);
     935           0 :                   csum = ip_csum_sub_even (csum, old_addr0.as_u64[1]);
     936           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[0]);
     937           0 :                   csum = ip_csum_add_even (csum, new_addr0.as_u64[1]);
     938           0 :                   csum = ip_csum_sub_even (csum, old_port0);
     939           0 :                   csum = ip_csum_add_even (csum, new_port0);
     940           0 :                   udp0->checksum = ip_csum_fold (csum);
     941             :                 }
     942             : 
     943           0 :               pkts_processed += next0 != LB_NAT4_IN2OUT_NEXT_DROP;
     944             :             }
     945             : 
     946           0 :           trace0: if (PREDICT_FALSE(
     947             :               (node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     948             :             {
     949           0 :               lb_nat_trace_t *t = vlib_add_trace (vm, node, b0, sizeof(*t));
     950           0 :               t->rx_sw_if_index = sw_if_index0;
     951           0 :               t->next_index = next0;
     952             :             }
     953             : 
     954             :           /* verify speculative enqueue, maybe switch current next frame */
     955           0 :           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     956             :                                           n_left_to_next, bi0, next0);
     957             :         }
     958             : 
     959           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     960             :     }
     961             : 
     962           0 :   vlib_node_increment_counter (vm, stats_node_index,
     963             :                                LB_NAT_IN2OUT_ERROR_IN2OUT_PACKETS,
     964             :                                pkts_processed);
     965           0 :   return frame->n_vectors;
     966             : }
     967             : 
     968             : static uword
     969           1 : lb6_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     970             :                   vlib_frame_t * frame)
     971             : {
     972           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 0);
     973             : }
     974             : 
     975             : static uword
     976           1 : lb6_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     977             :                   vlib_frame_t * frame)
     978             : {
     979           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 0);
     980             : }
     981             : 
     982             : static uword
     983           1 : lb4_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     984             :                   vlib_frame_t * frame)
     985             : {
     986           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 0);
     987             : }
     988             : 
     989             : static uword
     990           1 : lb4_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     991             :                   vlib_frame_t * frame)
     992             : {
     993           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 0);
     994             : }
     995             : 
     996             : static uword
     997           1 : lb6_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     998             :                        vlib_frame_t * frame)
     999             : {
    1000           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 1);
    1001             : }
    1002             : 
    1003             : static uword
    1004           1 : lb6_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1005             :                        vlib_frame_t * frame)
    1006             : {
    1007           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 1);
    1008             : }
    1009             : 
    1010             : static uword
    1011           1 : lb4_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1012             :                        vlib_frame_t * frame)
    1013             : {
    1014           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 1);
    1015             : }
    1016             : 
    1017             : static uword
    1018           1 : lb4_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1019             :                        vlib_frame_t * frame)
    1020             : {
    1021           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 1);
    1022             : }
    1023             : 
    1024             : static uword
    1025           2 : lb4_l3dsr_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1026             :                         vlib_frame_t * frame)
    1027             : {
    1028           2 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 0);
    1029             : }
    1030             : 
    1031             : static uword
    1032           2 : lb4_l3dsr_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1033             :                         vlib_frame_t * frame)
    1034             : {
    1035           2 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 1);
    1036             : }
    1037             : 
    1038             : static uword
    1039           1 : lb6_nat6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1040             :                        vlib_frame_t * frame)
    1041             : {
    1042           1 :   return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_NAT6, 1);
    1043             : }
    1044             : 
    1045             : static uword
    1046           1 : lb4_nat4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1047             :                        vlib_frame_t * frame)
    1048             : {
    1049           1 :   return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_NAT4, 1);
    1050             : }
    1051             : 
    1052             : static uword
    1053           0 : lb_nat4_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1054             :                         vlib_frame_t * frame)
    1055             : {
    1056           0 :   return lb_nat_in2out_node_fn (vm, node, frame, 1);
    1057             : }
    1058             : 
    1059             : static uword
    1060           0 : lb_nat6_in2out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1061             :                         vlib_frame_t * frame)
    1062             : {
    1063           0 :   return lb_nat_in2out_node_fn (vm, node, frame, 0);
    1064             : }
    1065             : 
    1066      101996 : VLIB_REGISTER_NODE (lb6_gre6_node) =
    1067             :   {
    1068             :     .function = lb6_gre6_node_fn,
    1069             :     .name = "lb6-gre6",
    1070             :     .vector_size = sizeof(u32),
    1071             :     .format_trace = format_lb_trace,
    1072             :     .n_errors = LB_N_ERROR,
    1073             :     .error_strings = lb_error_strings,
    1074             :     .n_next_nodes = LB_N_NEXT,
    1075             :     .next_nodes =
    1076             :         { [LB_NEXT_DROP] = "error-drop" },
    1077             :   };
    1078             : 
    1079      101996 : VLIB_REGISTER_NODE (lb6_gre4_node) =
    1080             :   {
    1081             :     .function = lb6_gre4_node_fn,
    1082             :     .name = "lb6-gre4",
    1083             :     .vector_size = sizeof(u32),
    1084             :     .format_trace = format_lb_trace,
    1085             :     .n_errors = LB_N_ERROR,
    1086             :     .error_strings = lb_error_strings,
    1087             :     .n_next_nodes = LB_N_NEXT,
    1088             :     .next_nodes =
    1089             :         { [LB_NEXT_DROP] = "error-drop" },
    1090             :   };
    1091             : 
    1092      101996 : VLIB_REGISTER_NODE (lb4_gre6_node) =
    1093             :   {
    1094             :     .function = lb4_gre6_node_fn,
    1095             :     .name = "lb4-gre6",
    1096             :     .vector_size = sizeof(u32),
    1097             :     .format_trace = format_lb_trace,
    1098             :     .n_errors = LB_N_ERROR,
    1099             :     .error_strings = lb_error_strings,
    1100             :     .n_next_nodes = LB_N_NEXT,
    1101             :     .next_nodes =
    1102             :         { [LB_NEXT_DROP] = "error-drop" },
    1103             :   };
    1104             : 
    1105      101996 : VLIB_REGISTER_NODE (lb4_gre4_node) =
    1106             :   {
    1107             :     .function = lb4_gre4_node_fn,
    1108             :     .name = "lb4-gre4",
    1109             :     .vector_size = sizeof(u32),
    1110             :     .format_trace = format_lb_trace,
    1111             :     .n_errors = LB_N_ERROR,
    1112             :     .error_strings = lb_error_strings,
    1113             :     .n_next_nodes = LB_N_NEXT,
    1114             :     .next_nodes =
    1115             :         { [LB_NEXT_DROP] = "error-drop" },
    1116             :   };
    1117             : 
    1118      101996 : VLIB_REGISTER_NODE (lb6_gre6_port_node) =
    1119             :   {
    1120             :     .function = lb6_gre6_port_node_fn,
    1121             :     .name = "lb6-gre6-port",
    1122             :     .vector_size = sizeof(u32),
    1123             :     .format_trace = format_lb_trace,
    1124             :     .n_errors = LB_N_ERROR,
    1125             :     .error_strings = lb_error_strings,
    1126             :     .n_next_nodes = LB_N_NEXT,
    1127             :     .next_nodes =
    1128             :         { [LB_NEXT_DROP] = "error-drop" },
    1129             :   };
    1130             : 
    1131      101996 : VLIB_REGISTER_NODE (lb6_gre4_port_node) =
    1132             :   {
    1133             :     .function = lb6_gre4_port_node_fn,
    1134             :     .name = "lb6-gre4-port",
    1135             :     .vector_size = sizeof(u32),
    1136             :     .format_trace = format_lb_trace,
    1137             :     .n_errors = LB_N_ERROR,
    1138             :     .error_strings = lb_error_strings,
    1139             :     .n_next_nodes = LB_N_NEXT,
    1140             :     .next_nodes =
    1141             :         { [LB_NEXT_DROP] = "error-drop" },
    1142             :   };
    1143             : 
    1144      101996 : VLIB_REGISTER_NODE (lb4_gre6_port_node) =
    1145             :   {
    1146             :     .function = lb4_gre6_port_node_fn,
    1147             :     .name = "lb4-gre6-port",
    1148             :     .vector_size = sizeof(u32),
    1149             :     .format_trace = format_lb_trace,
    1150             :     .n_errors = LB_N_ERROR,
    1151             :     .error_strings = lb_error_strings,
    1152             :     .n_next_nodes = LB_N_NEXT,
    1153             :     .next_nodes =
    1154             :         { [LB_NEXT_DROP] = "error-drop" },
    1155             :   };
    1156             : 
    1157      101996 : VLIB_REGISTER_NODE (lb4_gre4_port_node) =
    1158             :   {
    1159             :     .function = lb4_gre4_port_node_fn,
    1160             :     .name = "lb4-gre4-port",
    1161             :     .vector_size = sizeof(u32),
    1162             :     .format_trace = format_lb_trace,
    1163             :     .n_errors = LB_N_ERROR,
    1164             :     .error_strings = lb_error_strings,
    1165             :     .n_next_nodes = LB_N_NEXT,
    1166             :     .next_nodes =
    1167             :         { [LB_NEXT_DROP] = "error-drop" },
    1168             :   };
    1169             : 
    1170      101996 : VLIB_REGISTER_NODE (lb4_l3dsr_port_node) =
    1171             :   {
    1172             :     .function = lb4_l3dsr_port_node_fn,
    1173             :     .name = "lb4-l3dsr-port",
    1174             :     .vector_size = sizeof(u32),
    1175             :     .format_trace = format_lb_trace,
    1176             :     .n_errors = LB_N_ERROR,
    1177             :     .error_strings = lb_error_strings,
    1178             :     .n_next_nodes = LB_N_NEXT,
    1179             :     .next_nodes =
    1180             :         { [LB_NEXT_DROP] = "error-drop" },
    1181             :   };
    1182             : 
    1183      101996 : VLIB_REGISTER_NODE (lb4_l3dsr_node) =
    1184             :   {
    1185             :     .function = lb4_l3dsr_node_fn,
    1186             :     .name = "lb4-l3dsr",
    1187             :     .vector_size = sizeof(u32),
    1188             :     .format_trace = format_lb_trace,
    1189             :     .n_errors = LB_N_ERROR,
    1190             :     .error_strings = lb_error_strings,
    1191             :     .n_next_nodes = LB_N_NEXT,
    1192             :     .next_nodes =
    1193             :         { [LB_NEXT_DROP] = "error-drop" },
    1194             :   };
    1195             : 
    1196      101996 : VLIB_REGISTER_NODE (lb6_nat6_port_node) =
    1197             :   {
    1198             :     .function = lb6_nat6_port_node_fn,
    1199             :     .name = "lb6-nat6-port",
    1200             :     .vector_size = sizeof(u32),
    1201             :     .format_trace = format_lb_trace,
    1202             :     .n_errors = LB_N_ERROR,
    1203             :     .error_strings = lb_error_strings,
    1204             :     .n_next_nodes = LB_N_NEXT,
    1205             :     .next_nodes =
    1206             :         { [LB_NEXT_DROP] = "error-drop" },
    1207             :   };
    1208             : 
    1209      101996 : VLIB_REGISTER_NODE (lb4_nat4_port_node) =
    1210             :   {
    1211             :     .function = lb4_nat4_port_node_fn,
    1212             :     .name = "lb4-nat4-port",
    1213             :     .vector_size = sizeof(u32),
    1214             :     .format_trace = format_lb_trace,
    1215             :     .n_errors = LB_N_ERROR,
    1216             :     .error_strings = lb_error_strings,
    1217             :     .n_next_nodes = LB_N_NEXT,
    1218             :     .next_nodes =
    1219             :         { [LB_NEXT_DROP] = "error-drop" },
    1220             :   };
    1221             : 
    1222             : static uword
    1223           0 : lb4_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1224             :                       vlib_frame_t * frame)
    1225             : {
    1226           0 :   return lb_nodeport_node_fn (vm, node, frame, 1);
    1227             : }
    1228             : 
    1229             : static uword
    1230           0 : lb6_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
    1231             :                       vlib_frame_t * frame)
    1232             : {
    1233           0 :   return lb_nodeport_node_fn (vm, node, frame, 0);
    1234             : }
    1235             : 
    1236      101996 : VLIB_REGISTER_NODE (lb4_nodeport_node) =
    1237             :   {
    1238             :     .function = lb4_nodeport_node_fn,
    1239             :     .name = "lb4-nodeport",
    1240             :     .vector_size = sizeof(u32),
    1241             :     .format_trace = format_nodeport_lb_trace,
    1242             :     .n_errors = LB_N_ERROR,
    1243             :     .error_strings = lb_error_strings,
    1244             :     .n_next_nodes = LB4_NODEPORT_N_NEXT,
    1245             :     .next_nodes =
    1246             :         {
    1247             :             [LB4_NODEPORT_NEXT_IP4_NAT4] = "lb4-nat4-port",
    1248             :             [LB4_NODEPORT_NEXT_DROP] = "error-drop",
    1249             :         },
    1250             :   };
    1251             : 
    1252      101996 : VLIB_REGISTER_NODE (lb6_nodeport_node) =
    1253             :   {
    1254             :     .function = lb6_nodeport_node_fn,
    1255             :     .name = "lb6-nodeport",
    1256             :     .vector_size = sizeof(u32),
    1257             :     .format_trace = format_nodeport_lb_trace,
    1258             :     .n_errors = LB_N_ERROR,
    1259             :     .error_strings = lb_error_strings,
    1260             :     .n_next_nodes = LB6_NODEPORT_N_NEXT,
    1261             :     .next_nodes =
    1262             :       {
    1263             :           [LB6_NODEPORT_NEXT_IP6_NAT6] = "lb6-nat6-port",
    1264             :           [LB6_NODEPORT_NEXT_DROP] = "error-drop",
    1265             :       },
    1266             :   };
    1267             : 
    1268       50139 : VNET_FEATURE_INIT (lb_nat4_in2out_node_fn, static) =
    1269             :   {
    1270             :     .arc_name = "ip4-unicast",
    1271             :     .node_name = "lb-nat4-in2out",
    1272             :     .runs_before =  VNET_FEATURES("ip4-lookup"),
    1273             :   };
    1274             : 
    1275      101996 : VLIB_REGISTER_NODE (lb_nat4_in2out_node) =
    1276             :   {
    1277             :     .function = lb_nat4_in2out_node_fn,
    1278             :     .name = "lb-nat4-in2out",
    1279             :     .vector_size = sizeof(u32),
    1280             :     .format_trace = format_lb_nat_trace,
    1281             :     .n_errors = LB_N_ERROR,
    1282             :     .error_strings = lb_error_strings,
    1283             :     .n_next_nodes = LB_NAT4_IN2OUT_N_NEXT,
    1284             :     .next_nodes =
    1285             :       {
    1286             :           [LB_NAT4_IN2OUT_NEXT_DROP] = "error-drop",
    1287             :           [LB_NAT4_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
    1288             :       },
    1289             :   };
    1290             : 
    1291       50139 : VNET_FEATURE_INIT (lb_nat6_in2out_node_fn, static) =
    1292             :   {
    1293             :     .arc_name = "ip6-unicast",
    1294             :     .node_name = "lb-nat6-in2out",
    1295             :     .runs_before = VNET_FEATURES("ip6-lookup"),
    1296             :   };
    1297             : 
    1298      101996 : VLIB_REGISTER_NODE (lb_nat6_in2out_node) =
    1299             :   {
    1300             :     .function = lb_nat6_in2out_node_fn,
    1301             :     .name = "lb-nat6-in2out",
    1302             :     .vector_size = sizeof(u32),
    1303             :     .format_trace = format_lb_nat_trace,
    1304             :     .n_errors = LB_N_ERROR,
    1305             :     .error_strings = lb_error_strings,
    1306             :     .n_next_nodes = LB_NAT6_IN2OUT_N_NEXT,
    1307             :     .next_nodes =
    1308             :       {
    1309             :           [LB_NAT6_IN2OUT_NEXT_DROP] = "error-drop",
    1310             :           [LB_NAT6_IN2OUT_NEXT_LOOKUP] = "ip6-lookup",
    1311             :       },
    1312             :   };

Generated by: LCOV version 1.14