LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ed - nat44_ed_in2out.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 622 772 80.6 %
Date: 2023-10-26 01:39:38 Functions: 58 76 76.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 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             :  * @file
      17             :  * @brief NAT44 endpoint-dependent inside to outside network translation
      18             :  */
      19             : 
      20             : #include <vlib/vlib.h>
      21             : #include <vnet/vnet.h>
      22             : #include <vnet/ip/ip.h>
      23             : #include <vnet/ethernet/ethernet.h>
      24             : #include <vnet/fib/ip4_fib.h>
      25             : #include <vnet/udp/udp_local.h>
      26             : #include <vppinfra/error.h>
      27             : 
      28             : #include <nat/lib/nat_inlines.h>
      29             : #include <nat/lib/ipfix_logging.h>
      30             : 
      31             : #include <nat/nat44-ed/nat44_ed.h>
      32             : #include <nat/nat44-ed/nat44_ed_inlines.h>
      33             : 
      34             : static char *nat_in2out_ed_error_strings[] = {
      35             : #define _(sym,string) string,
      36             :   foreach_nat_in2out_ed_error
      37             : #undef _
      38             : };
      39             : 
      40             : typedef struct
      41             : {
      42             :   u32 sw_if_index;
      43             :   u32 next_index;
      44             :   u32 session_index;
      45             :   nat_translation_error_e translation_error;
      46             :   nat_6t_flow_t i2of;
      47             :   nat_6t_flow_t o2if;
      48             :   clib_bihash_kv_16_8_t search_key;
      49             :   u8 is_slow_path;
      50             :   u8 translation_via_i2of;
      51             :   u8 lookup_skipped;
      52             :   u8 tcp_state;
      53             : } nat_in2out_ed_trace_t;
      54             : 
      55             : static u8 *
      56        2756 : format_nat_in2out_ed_trace (u8 * s, va_list * args)
      57             : {
      58        2756 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      59        2756 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      60        2756 :   nat_in2out_ed_trace_t *t = va_arg (*args, nat_in2out_ed_trace_t *);
      61             :   char *tag;
      62             : 
      63        2756 :   tag =
      64        2756 :     t->is_slow_path ? "NAT44_IN2OUT_ED_SLOW_PATH" :
      65             :     "NAT44_IN2OUT_ED_FAST_PATH";
      66             : 
      67        2756 :   s = format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index,
      68             :               t->next_index);
      69        2756 :   if (~0 != t->session_index)
      70             :     {
      71        1218 :       s = format (s, ", session %d, translation result '%U' via %s",
      72             :                   t->session_index, format_nat_ed_translation_error,
      73        1218 :                   t->translation_error,
      74        1218 :                   t->translation_via_i2of ? "i2of" : "o2if");
      75        1218 :       s = format (s, "\n  i2of %U", format_nat_6t_flow, &t->i2of);
      76        1218 :       s = format (s, "\n  o2if %U", format_nat_6t_flow, &t->o2if);
      77             :     }
      78        2756 :   if (!t->is_slow_path)
      79             :     {
      80        1587 :       if (t->lookup_skipped)
      81             :         {
      82          89 :           s = format (s, "\n  lookup skipped - cached session index used");
      83             :         }
      84             :       else
      85             :         {
      86        1498 :           s = format (s, "\n  search key %U", format_ed_session_kvp,
      87             :                       &t->search_key);
      88             :         }
      89             :     }
      90        2756 :   if (IP_PROTOCOL_TCP == t->i2of.match.proto)
      91             :     {
      92         110 :       s = format (s, "\n  TCP state: %U", format_nat44_ed_tcp_state,
      93         110 :                   t->tcp_state);
      94             :     }
      95             : 
      96        2756 :   return s;
      97             : }
      98             : 
      99             : static int
     100       28348 : nat_ed_alloc_addr_and_port_with_snat_address (
     101             :   snat_main_t *sm, u8 proto, u32 thread_index, snat_address_t *a,
     102             :   u16 port_per_thread, u32 snat_thread_index, snat_session_t *s,
     103             :   ip4_address_t *outside_addr, u16 *outside_port)
     104             : {
     105       28348 :   const u16 port_thread_offset =
     106       28348 :     (port_per_thread * snat_thread_index) + ED_USER_PORT_OFFSET;
     107             : 
     108             :   /* Backup original match in case of failure */
     109       28348 :   const nat_6t_t match = s->o2i.match;
     110             : 
     111       28348 :   s->o2i.match.daddr = a->addr;
     112             :   /* first try port suggested by caller */
     113       28348 :   u16 port = clib_net_to_host_u16 (*outside_port);
     114       28348 :   u16 port_offset = port - port_thread_offset;
     115       28348 :   if (port < port_thread_offset ||
     116         206 :       port >= port_thread_offset + port_per_thread)
     117             :     {
     118             :       /* need to pick a different port, suggested port doesn't fit in
     119             :        * this thread's port range */
     120       28178 :       port_offset = snat_random_port (0, port_per_thread - 1);
     121       28178 :       port = port_thread_offset + port_offset;
     122             :     }
     123       28348 :   u16 attempts = ED_PORT_ALLOC_ATTEMPTS;
     124             :   do
     125             :     {
     126       42732 :       if (IP_PROTOCOL_ICMP == proto)
     127             :         {
     128        7531 :           s->o2i.match.sport = clib_host_to_net_u16 (port);
     129             :         }
     130       42732 :       s->o2i.match.dport = clib_host_to_net_u16 (port);
     131       42732 :       if (0 == nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2))
     132             :         {
     133       28214 :           *outside_addr = a->addr;
     134       28214 :           *outside_port = clib_host_to_net_u16 (port);
     135       28214 :           return 0;
     136             :         }
     137       14519 :       port_offset = snat_random_port (0, port_per_thread - 1);
     138       14519 :       port = port_thread_offset + port_offset;
     139       14519 :       --attempts;
     140             :     }
     141       14519 :   while (attempts > 0);
     142             : 
     143             :   /* Revert match */
     144         135 :   s->o2i.match = match;
     145         135 :   return 1;
     146             : }
     147             : 
     148             : static int
     149       28352 : nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index,
     150             :                             u32 tx_sw_if_index, u32 nat_proto,
     151             :                             u32 thread_index, ip4_address_t s_addr,
     152             :                             ip4_address_t d_addr, u32 snat_thread_index,
     153             :                             snat_session_t *s, ip4_address_t *outside_addr,
     154             :                             u16 *outside_port)
     155             : {
     156       28352 :   if (vec_len (sm->addresses) > 0)
     157             :     {
     158       56696 :       u32 s_addr_offset = (s_addr.as_u32 + (s_addr.as_u32 >> 8) +
     159       28348 :                            (s_addr.as_u32 >> 16) + (s_addr.as_u32 >> 24)) %
     160       28348 :                           vec_len (sm->addresses);
     161       28348 :       snat_address_t *a, *ja = 0, *ra = 0, *ba = 0;
     162             :       int i;
     163             : 
     164             :       // output feature
     165       28348 :       if (tx_sw_if_index != ~0)
     166             :         {
     167          44 :           for (i = s_addr_offset; i < vec_len (sm->addresses); ++i)
     168             :             {
     169          22 :               a = sm->addresses + i;
     170          22 :               if (a->fib_index == rx_fib_index)
     171             :                 {
     172           0 :                   if (a->sw_if_index == tx_sw_if_index)
     173             :                     {
     174           0 :                       if ((a->addr_len != ~0) &&
     175           0 :                           (a->net.as_u32 ==
     176           0 :                            (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
     177             : 
     178             :                         {
     179           0 :                           return nat_ed_alloc_addr_and_port_with_snat_address (
     180             :                             sm, nat_proto, thread_index, a,
     181           0 :                             sm->port_per_thread, snat_thread_index, s,
     182             :                             outside_addr, outside_port);
     183             :                         }
     184           0 :                       ra = a;
     185             :                     }
     186           0 :                   ja = a;
     187             :                 }
     188          22 :               else if (a->fib_index == ~0)
     189             :                 {
     190          22 :                   ba = a;
     191             :                 }
     192             :             }
     193          22 :           for (i = 0; i < s_addr_offset; ++i)
     194             :             {
     195           0 :               a = sm->addresses + i;
     196           0 :               if (a->fib_index == rx_fib_index)
     197             :                 {
     198           0 :                   if (a->sw_if_index == tx_sw_if_index)
     199             :                     {
     200           0 :                       if ((a->addr_len != ~0) &&
     201           0 :                           (a->net.as_u32 ==
     202           0 :                            (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
     203             : 
     204             :                         {
     205           0 :                           return nat_ed_alloc_addr_and_port_with_snat_address (
     206             :                             sm, nat_proto, thread_index, a,
     207           0 :                             sm->port_per_thread, snat_thread_index, s,
     208             :                             outside_addr, outside_port);
     209             :                         }
     210           0 :                       ra = a;
     211             :                     }
     212           0 :                   ja = a;
     213             :                 }
     214           0 :               else if (a->fib_index == ~0)
     215             :                 {
     216           0 :                   ba = a;
     217             :                 }
     218             :             }
     219          22 :           if (ra)
     220             :             {
     221           0 :               return nat_ed_alloc_addr_and_port_with_snat_address (
     222           0 :                 sm, nat_proto, thread_index, ra, sm->port_per_thread,
     223             :                 snat_thread_index, s, outside_addr, outside_port);
     224             :             }
     225             :         }
     226             :       else
     227             :         {
     228             :           // first try nat pool addresses to sw interface addreses mappings
     229       63904 :           for (i = s_addr_offset; i < vec_len (sm->addresses); ++i)
     230             :             {
     231       35578 :               a = sm->addresses + i;
     232       35578 :               if (a->fib_index == rx_fib_index)
     233             :                 {
     234           3 :                   if ((a->addr_len != ~0) &&
     235           0 :                       (a->net.as_u32 ==
     236           0 :                        (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
     237             :                     {
     238           0 :                       return nat_ed_alloc_addr_and_port_with_snat_address (
     239           0 :                         sm, nat_proto, thread_index, a, sm->port_per_thread,
     240             :                         snat_thread_index, s, outside_addr, outside_port);
     241             :                     }
     242           3 :                   ja = a;
     243             :                 }
     244       35575 :               else if (a->fib_index == ~0)
     245             :                 {
     246       35575 :                   ba = a;
     247             :                 }
     248             :             }
     249       33674 :           for (i = 0; i < s_addr_offset; ++i)
     250             :             {
     251        5348 :               a = sm->addresses + i;
     252        5348 :               if (a->fib_index == rx_fib_index)
     253             :                 {
     254           0 :                   if ((a->addr_len != ~0) &&
     255           0 :                       (a->net.as_u32 ==
     256           0 :                        (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len])))
     257             :                     {
     258           0 :                       return nat_ed_alloc_addr_and_port_with_snat_address (
     259           0 :                         sm, nat_proto, thread_index, a, sm->port_per_thread,
     260             :                         snat_thread_index, s, outside_addr, outside_port);
     261             :                     }
     262           0 :                   ja = a;
     263             :                 }
     264        5348 :               else if (a->fib_index == ~0)
     265             :                 {
     266        5348 :                   ba = a;
     267             :                 }
     268             :             }
     269             :         }
     270             : 
     271       28348 :       if (ja || ba)
     272             :         {
     273       28348 :           a = ja ? ja : ba;
     274       28349 :           return nat_ed_alloc_addr_and_port_with_snat_address (
     275       28348 :             sm, nat_proto, thread_index, a, sm->port_per_thread,
     276             :             snat_thread_index, s, outside_addr, outside_port);
     277             :         }
     278             :     }
     279             :   /* Totally out of translations to use... */
     280           4 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
     281           4 :   return 1;
     282             : }
     283             : 
     284             : static_always_inline int
     285       28358 : nat44_ed_external_sm_lookup (snat_main_t *sm, ip4_address_t match_addr,
     286             :                              u16 match_port, ip_protocol_t match_protocol,
     287             :                              ip4_address_t *daddr, u16 *dport)
     288             : {
     289             :   snat_static_mapping_t *m =
     290       28358 :     nat44_ed_sm_o2i_lookup (sm, match_addr, match_port, 0, match_protocol);
     291       28360 :   if (!m)
     292             :     {
     293             :       /* Try address only mapping */
     294       28358 :       m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0);
     295       28358 :       if (!m)
     296       28350 :         return 0;
     297             :     }
     298          10 :   *daddr = m->local_addr;
     299          10 :   if (dport)
     300             :     {
     301             :       /* Address only mapping doesn't change port */
     302           9 :       *dport = is_sm_addr_only (m->flags) ? match_port : m->local_port;
     303             :     }
     304          10 :   return 1;
     305             : }
     306             : 
     307             : static_always_inline vrf_table_t *
     308       56698 : get_vrf_table_by_fib (u32 fib_index)
     309             : {
     310       56698 :   snat_main_t *sm = &snat_main;
     311             :   vrf_table_t *t;
     312             : 
     313       56698 :   pool_foreach (t, sm->vrf_tables)
     314             :     {
     315           0 :       if (fib_index == t->table_fib_index)
     316             :         {
     317           0 :           return t;
     318             :         }
     319             :     }
     320             : 
     321       56698 :   return 0;
     322             : }
     323             : 
     324             : static_always_inline u32
     325       28360 : get_tx_fib_index (u32 rx_fib_index, ip4_address_t addr)
     326             : {
     327       28360 :   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
     328       28360 :   fib_prefix_t pfx = {
     329             :     .fp_proto = FIB_PROTOCOL_IP4,
     330             :     .fp_len = 32,
     331       28360 :     .fp_addr = {.ip4.as_u32 = addr.as_u32,}
     332             :     ,
     333             :   };
     334             : 
     335       28360 :   snat_main_t *sm = &snat_main;
     336       28360 :   vrf_table_t *t = get_vrf_table_by_fib (rx_fib_index);
     337             :   // default to rx fib
     338       28360 :   u32 tx_fib_index = rx_fib_index;
     339             : 
     340       28360 :   if (0 != t)
     341             :     {
     342             :       // managed routes to other fibs
     343             :       vrf_route_t *r;
     344           0 :       pool_foreach (r, t->routes)
     345             :         {
     346           0 :           fei = fib_table_lookup (r->fib_index, &pfx);
     347           0 :           if ((FIB_NODE_INDEX_INVALID != fei) &&
     348           0 :               (~0 != fib_entry_get_resolving_interface (fei)))
     349             :             {
     350           0 :               tx_fib_index = r->fib_index;
     351           0 :               break;
     352             :             }
     353             :         }
     354             :     }
     355             :   else
     356             :     {
     357             :       // default to configured fib
     358       28360 :       tx_fib_index = sm->outside_fib_index;
     359             : 
     360             :       // default routes to other fibs
     361             :       nat_fib_t *f;
     362       28360 :       vec_foreach (f, sm->outside_fibs)
     363             :         {
     364       28360 :           fei = fib_table_lookup (f->fib_index, &pfx);
     365       56717 :           if ((FIB_NODE_INDEX_INVALID != fei) &&
     366       28359 :               (~0 != fib_entry_get_resolving_interface (fei)))
     367             :             {
     368       28358 :               tx_fib_index = f->fib_index;
     369       28358 :               break;
     370             :             }
     371             :         }
     372             :     }
     373             : 
     374       28358 :   return tx_fib_index;
     375             : }
     376             : 
     377             : static_always_inline int
     378       28340 : is_destination_resolvable (u32 rx_fib_index, ip4_address_t addr)
     379             : {
     380       28340 :   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
     381       28340 :   fib_prefix_t pfx = {
     382             :     .fp_proto = FIB_PROTOCOL_IP4,
     383             :     .fp_len = 32,
     384       28340 :     .fp_addr = {.ip4.as_u32 = addr.as_u32,}
     385             :     ,
     386             :   };
     387             : 
     388       28340 :   snat_main_t *sm = &snat_main;
     389       28340 :   vrf_table_t *t = get_vrf_table_by_fib (rx_fib_index);
     390             :   u32 ii;
     391             : 
     392       28338 :   if (0 != t)
     393             :     {
     394             :       // managed routes to other fibs
     395             :       vrf_route_t *r;
     396           0 :       pool_foreach (r, t->routes)
     397             :         {
     398           0 :           fei = fib_table_lookup (r->fib_index, &pfx);
     399           0 :           if ((FIB_NODE_INDEX_INVALID != fei) &&
     400           0 :               (~0 != (ii = fib_entry_get_resolving_interface (fei))))
     401             :             {
     402           0 :               return 1;
     403             :             }
     404             :         }
     405             :     }
     406             :   else
     407             :     {
     408             :       // default routes to other fibs
     409             :       nat_fib_t *f;
     410       28344 :       vec_foreach (f, sm->outside_fibs)
     411             :         {
     412       28340 :           fei = fib_table_lookup (f->fib_index, &pfx);
     413       56680 :           if ((FIB_NODE_INDEX_INVALID != fei) &&
     414       28343 :               (~0 != (ii = fib_entry_get_resolving_interface (fei))))
     415             :             {
     416             :               snat_interface_t *i;
     417       56695 :               pool_foreach (i, sm->interfaces)
     418             :                 {
     419       56694 :                   if ((nat44_ed_is_interface_outside (i)) &&
     420       28341 :                       (ii == i->sw_if_index))
     421             :                     {
     422       28337 :                       return 1;
     423             :                     }
     424             :                 }
     425             :             }
     426             :         }
     427             :     }
     428             : 
     429           4 :   return 0;
     430             : }
     431             : 
     432             : static u32
     433       28369 : slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
     434             :               ip4_address_t l_addr, ip4_address_t r_addr, u16 l_port,
     435             :               u16 r_port, u8 proto, u32 rx_fib_index, u32 tx_sw_if_index,
     436             :               snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next,
     437             :               u32 thread_index, f64 now)
     438             : {
     439       28369 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     440             :   ip4_address_t outside_addr;
     441             :   u16 outside_port;
     442             :   u32 tx_fib_index;
     443       28369 :   u8 is_identity_nat = 0;
     444             : 
     445       28369 :   snat_session_t *s = NULL;
     446       28369 :   lb_nat_type_t lb = 0;
     447       28369 :   ip4_address_t daddr = r_addr;
     448       28369 :   u16 dport = r_port;
     449             : 
     450       28369 :   if (PREDICT_FALSE
     451             :       (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
     452             :     {
     453           6 :       if (!nat_lru_free_one (sm, thread_index, now))
     454             :         {
     455           5 :           b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     456           5 :           nat_ipfix_logging_max_sessions (thread_index,
     457             :                                           sm->max_translations_per_thread);
     458           5 :           nat_elog_notice (sm, "maximum sessions exceeded");
     459           5 :           return NAT_NEXT_DROP;
     460             :         }
     461             :     }
     462             : 
     463             :   ip4_address_t sm_addr;
     464             :   u16 sm_port;
     465             :   u32 sm_fib_index;
     466       28364 :   int is_sm = 0;
     467             :   // First try to match static mapping by local address and port
     468       28364 :   if (!snat_static_mapping_match (vm, l_addr, l_port, rx_fib_index, proto,
     469             :                                   &sm_addr, &sm_port, &sm_fib_index, 0, 0, 0,
     470             :                                   &lb, 0, &is_identity_nat, 0))
     471             :     {
     472          12 :       if (PREDICT_FALSE (is_identity_nat))
     473             :         {
     474           0 :           *sessionp = NULL;
     475           0 :           return next;
     476             :         }
     477          12 :       is_sm = 1;
     478             :     }
     479             : 
     480       28365 :   if (PREDICT_TRUE (proto == IP_PROTOCOL_TCP))
     481             :     {
     482        1603 :       if (PREDICT_FALSE (!tcp_flags_is_init (
     483             :             vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
     484             :         {
     485           8 :           b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
     486           8 :           return NAT_NEXT_DROP;
     487             :         }
     488             :     }
     489             : 
     490       28357 :   s = nat_ed_session_alloc (sm, thread_index, now, proto);
     491       28358 :   ASSERT (s);
     492             : 
     493       28358 :   tx_fib_index = get_tx_fib_index (rx_fib_index, r_addr);
     494             : 
     495       28356 :   if (!is_sm)
     496             :     {
     497       28350 :       s->in2out.addr = l_addr;
     498       28350 :       s->in2out.port = l_port;
     499       28350 :       s->proto = proto;
     500       28350 :       s->in2out.fib_index = rx_fib_index;
     501       28350 :       s->out2in.fib_index = tx_fib_index;
     502             : 
     503             :       // suggest using local port to allocation function
     504       28350 :       outside_port = l_port;
     505             : 
     506       28350 :       if (PREDICT_FALSE (nat44_ed_external_sm_lookup (sm, r_addr, r_port,
     507             :                                                       proto, &daddr, &dport)))
     508             :         {
     509           9 :           s->flags |= SNAT_SESSION_FLAG_HAIRPINNING;
     510             :         }
     511             : 
     512             :       // destination addr/port updated with real values in
     513             :       // nat_ed_alloc_addr_and_port
     514       28353 :       nat_6t_o2i_flow_init (sm, thread_index, s, daddr, dport, daddr, 0,
     515             :                             s->out2in.fib_index, proto);
     516       28352 :       nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32);
     517       28353 :       if (IP_PROTOCOL_ICMP == proto)
     518             :         {
     519        6566 :           nat_6t_flow_icmp_id_rewrite_set (&s->o2i, l_port);
     520             :         }
     521             :       else
     522             :         {
     523       21787 :           nat_6t_flow_dport_rewrite_set (&s->o2i, l_port);
     524             :         }
     525       28353 :       nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
     526             : 
     527       28352 :       if (nat_ed_alloc_addr_and_port (
     528             :             sm, rx_fib_index, tx_sw_if_index, proto, thread_index, l_addr,
     529             :             r_addr, tsm->snat_thread_index, s, &outside_addr, &outside_port))
     530             :         {
     531         139 :           nat_elog_notice (sm, "addresses exhausted");
     532         139 :           b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
     533         139 :           nat_ed_session_delete (sm, s, thread_index, 1);
     534         139 :           return NAT_NEXT_DROP;
     535             :         }
     536       28214 :       s->out2in.addr = outside_addr;
     537       28214 :       s->out2in.port = outside_port;
     538             :     }
     539             :   else
     540             :     {
     541             :       // static mapping
     542           6 :       s->out2in.addr = outside_addr = sm_addr;
     543           6 :       s->out2in.port = outside_port = sm_port;
     544           6 :       s->in2out.addr = l_addr;
     545           6 :       s->in2out.port = l_port;
     546           6 :       s->proto = proto;
     547           6 :       s->in2out.fib_index = rx_fib_index;
     548           6 :       s->out2in.fib_index = tx_fib_index;
     549           6 :       s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
     550             : 
     551             :       // hairpinning?
     552           6 :       int is_hairpinning = nat44_ed_external_sm_lookup (sm, r_addr, r_port,
     553             :                                                         proto, &daddr, &dport);
     554           6 :       s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING;
     555             : 
     556           6 :       if (IP_PROTOCOL_ICMP == proto)
     557             :         {
     558           0 :           nat_6t_o2i_flow_init (sm, thread_index, s, daddr, sm_port, sm_addr,
     559             :                                 sm_port, s->out2in.fib_index, proto);
     560           0 :           nat_6t_flow_icmp_id_rewrite_set (&s->o2i, l_port);
     561             :         }
     562             :       else
     563             :         {
     564           6 :           nat_6t_o2i_flow_init (sm, thread_index, s, daddr, dport, sm_addr,
     565             :                                 sm_port, s->out2in.fib_index, proto);
     566           6 :           nat_6t_flow_dport_rewrite_set (&s->o2i, l_port);
     567             :         }
     568           6 :       nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32);
     569           6 :       nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
     570           6 :       if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2))
     571             :         {
     572           0 :           nat_elog_notice (sm, "out2in key add failed");
     573           0 :           goto error;
     574             :         }
     575             :     }
     576             : 
     577       28220 :   if (lb)
     578           0 :     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
     579       28220 :   s->ext_host_addr = r_addr;
     580       28220 :   s->ext_host_port = r_port;
     581             : 
     582       28220 :   nat_6t_i2o_flow_init (sm, thread_index, s, l_addr, l_port, r_addr, r_port,
     583             :                         rx_fib_index, proto);
     584       28220 :   nat_6t_flow_saddr_rewrite_set (&s->i2o, outside_addr.as_u32);
     585       28220 :   nat_6t_flow_daddr_rewrite_set (&s->i2o, daddr.as_u32);
     586             : 
     587       28220 :   if (IP_PROTOCOL_ICMP == proto)
     588             :     {
     589        6565 :       nat_6t_flow_icmp_id_rewrite_set (&s->i2o, outside_port);
     590             :     }
     591             :   else
     592             :     {
     593       21655 :       nat_6t_flow_sport_rewrite_set (&s->i2o, outside_port);
     594       21655 :       nat_6t_flow_dport_rewrite_set (&s->i2o, dport);
     595             :     }
     596       28220 :   nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index);
     597             : 
     598       28220 :   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     599             :     {
     600           0 :       nat_elog_notice (sm, "in2out key add failed");
     601           0 :       goto error;
     602             :     }
     603             : 
     604             :   /* log NAT event */
     605       28220 :   nat_ipfix_logging_nat44_ses_create (
     606       28220 :     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
     607       28220 :     s->in2out.port, s->out2in.port, s->in2out.fib_index);
     608             : 
     609       28220 :   nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
     610       28220 :                          s->in2out.port, &s->ext_host_nat_addr,
     611       28220 :                          s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
     612       28220 :                          &s->ext_host_addr, s->ext_host_port, s->proto, 0);
     613             : 
     614       28220 :   per_vrf_sessions_register_session (s, thread_index);
     615             : 
     616       28220 :   *sessionp = s;
     617       28220 :   return next;
     618           0 : error:
     619           0 :   if (s)
     620             :     {
     621           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
     622             :     }
     623           0 :   *sessionp = s = NULL;
     624           0 :   return NAT_NEXT_DROP;
     625             : }
     626             : 
     627             : static_always_inline int
     628       28369 : nat44_ed_not_translate (vlib_main_t *vm, vlib_node_runtime_t *node,
     629             :                         u32 sw_if_index, vlib_buffer_t *b, ip4_header_t *ip,
     630             :                         u32 proto, u32 rx_fib_index)
     631             : {
     632       28369 :   snat_main_t *sm = &snat_main;
     633             : 
     634             :   clib_bihash_kv_16_8_t kv, value;
     635             :   ip4_address_t placeholder_addr;
     636             :   u32 placeholder_fib_index;
     637             :   u16 placeholder_port;
     638             : 
     639       28369 :   init_ed_k (&kv, ip->dst_address.as_u32,
     640       28369 :              vnet_buffer (b)->ip.reass.l4_dst_port, ip->src_address.as_u32,
     641       28369 :              vnet_buffer (b)->ip.reass.l4_src_port, sm->outside_fib_index,
     642       28369 :              ip->protocol);
     643             : 
     644             :   // do nat if active session or is static mapping
     645       56740 :   if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value) ||
     646       28370 :       !snat_static_mapping_match (
     647       28370 :         vm, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
     648             :         sm->outside_fib_index, proto, &placeholder_addr, &placeholder_port,
     649             :         &placeholder_fib_index, 1, 0, 0, 0, 0, 0, 0))
     650             :     {
     651           9 :       return 0;
     652             :     }
     653             : 
     654             :   // do not nat if forwarding enabled
     655       28362 :   if (sm->forwarding_enabled)
     656             :     {
     657          17 :       return 1;
     658             :     }
     659             : 
     660             :   // do not nat packet aimed at the interface address
     661       28345 :   if (PREDICT_FALSE (
     662             :         is_interface_addr (sm, node, sw_if_index, ip->dst_address.as_u32)))
     663             :     {
     664           0 :       return 1;
     665             :     }
     666             : 
     667             :   // do nat packets with resolvable destination
     668             :   // destination can be resolved either by:
     669             :   // a) vrf routing table entry
     670             :   // b) (non output feature) outside interface fib
     671       28340 :   if (is_destination_resolvable (rx_fib_index, ip->dst_address))
     672             :     {
     673       28337 :       return 0;
     674             :     }
     675             : 
     676           4 :   return 1;
     677             : }
     678             : 
     679             : static_always_inline int
     680          66 : nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
     681             :                                       u32 thread_index, f64 now,
     682             :                                       vlib_main_t * vm, vlib_buffer_t * b)
     683             : {
     684             :   clib_bihash_kv_16_8_t kv, value;
     685          66 :   snat_session_t *s = 0;
     686          66 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     687             : 
     688          66 :   if (!sm->forwarding_enabled)
     689          21 :     return 0;
     690             : 
     691          45 :   if (ip->protocol == IP_PROTOCOL_ICMP)
     692             :     {
     693             :       ip4_address_t lookup_saddr, lookup_daddr;
     694             :       u16 lookup_sport, lookup_dport;
     695             :       u8 lookup_protocol;
     696          10 :       if (nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr,
     697             :                                               &lookup_sport, &lookup_daddr,
     698             :                                               &lookup_dport, &lookup_protocol))
     699           0 :         return 0;
     700          10 :       init_ed_k (&kv, lookup_saddr.as_u32, lookup_sport, lookup_daddr.as_u32,
     701             :                  lookup_dport, 0, lookup_protocol);
     702             :     }
     703          35 :   else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
     704             :     {
     705          35 :       init_ed_k (&kv, ip->src_address.as_u32,
     706          35 :                  vnet_buffer (b)->ip.reass.l4_src_port, ip->dst_address.as_u32,
     707          35 :                  vnet_buffer (b)->ip.reass.l4_dst_port, 0, ip->protocol);
     708             :     }
     709             :   else
     710             :     {
     711           0 :       init_ed_k (&kv, ip->src_address.as_u32, 0, ip->dst_address.as_u32, 0, 0,
     712           0 :                  ip->protocol);
     713             :     }
     714             : 
     715          45 :   if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
     716             :     {
     717          10 :       ASSERT (thread_index == ed_value_get_thread_index (&value));
     718          10 :       s =
     719          10 :         pool_elt_at_index (tsm->sessions,
     720             :                            ed_value_get_session_index (&value));
     721             : 
     722          10 :       if (na44_ed_is_fwd_bypass_session (s))
     723             :         {
     724           8 :           if (ip->protocol == IP_PROTOCOL_TCP)
     725             :             {
     726           4 :               nat44_set_tcp_session_state_i2o (
     727           4 :                 sm, now, s, vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags,
     728             :                 thread_index);
     729             :             }
     730             :           /* Accounting */
     731           8 :           nat44_session_update_counters (s, now,
     732             :                                          vlib_buffer_length_in_chain (vm, b),
     733             :                                          thread_index);
     734             :           /* Per-user LRU list maintenance */
     735           8 :           nat44_session_update_lru (sm, s, thread_index);
     736           8 :           return 1;
     737             :         }
     738             :       else
     739           2 :         return 0;
     740             :     }
     741             : 
     742          35 :   return 0;
     743             : }
     744             : 
     745             : static_always_inline int
     746          46 : nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b,
     747             :                                        ip4_header_t *ip, u16 src_port,
     748             :                                        u16 dst_port, u32 thread_index,
     749             :                                        u32 rx_sw_if_index, u32 tx_sw_if_index,
     750             :                                        int is_multi_worker)
     751             : {
     752             :   clib_bihash_kv_16_8_t kv, value;
     753          46 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     754             :   snat_interface_t *i;
     755             :   snat_session_t *s;
     756          46 :   u32 rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (rx_sw_if_index);
     757          46 :   u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index);
     758             : 
     759             :   /* src NAT check */
     760          46 :   init_ed_k (&kv, ip->src_address.as_u32, src_port, ip->dst_address.as_u32,
     761          46 :              dst_port, tx_fib_index, ip->protocol);
     762          46 :   if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
     763             :     {
     764           0 :       ASSERT (thread_index == ed_value_get_thread_index (&value));
     765           0 :       s =
     766           0 :         pool_elt_at_index (tsm->sessions,
     767             :                            ed_value_get_session_index (&value));
     768           0 :       return 1;
     769             :     }
     770             : 
     771             :   /* dst NAT check */
     772          46 :   if (is_multi_worker &&
     773          29 :       PREDICT_TRUE (!pool_is_free_index (
     774             :         tsm->sessions, vnet_buffer2 (b)->nat.cached_dst_nat_session_index)))
     775             :     {
     776             :       nat_6t_t lookup;
     777          24 :       lookup.fib_index = rx_fib_index;
     778          24 :       lookup.proto = ip->protocol;
     779          24 :       lookup.daddr.as_u32 = ip->src_address.as_u32;
     780          24 :       lookup.dport = src_port;
     781          24 :       lookup.saddr.as_u32 = ip->dst_address.as_u32;
     782          24 :       lookup.sport = dst_port;
     783          24 :       s = pool_elt_at_index (
     784             :         tsm->sessions, vnet_buffer2 (b)->nat.cached_dst_nat_session_index);
     785          24 :       if (PREDICT_TRUE (nat_6t_t_eq (&s->i2o.match, &lookup)))
     786             :         {
     787           4 :           goto skip_dst_nat_lookup;
     788             :         }
     789          20 :       s = NULL;
     790             :     }
     791             : 
     792          42 :   init_ed_k (&kv, ip->dst_address.as_u32, dst_port, ip->src_address.as_u32,
     793          42 :              src_port, rx_fib_index, ip->protocol);
     794          42 :   if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
     795             :     {
     796          26 :       ASSERT (thread_index == ed_value_get_thread_index (&value));
     797          26 :       s =
     798          26 :         pool_elt_at_index (tsm->sessions,
     799             :                            ed_value_get_session_index (&value));
     800             : 
     801          30 :     skip_dst_nat_lookup:
     802          30 :       if (na44_ed_is_fwd_bypass_session (s))
     803           6 :         return 0;
     804             : 
     805             :       /* hairpinning */
     806          48 :       pool_foreach (i, sm->output_feature_interfaces)
     807             :         {
     808          24 :           if ((nat44_ed_is_interface_inside (i)) &&
     809          24 :               (rx_sw_if_index == i->sw_if_index))
     810           0 :             return 0;
     811             :         }
     812          24 :       return 1;
     813             :     }
     814             : 
     815          16 :   return 0;
     816             : }
     817             : 
     818             : static inline u32
     819        6568 : icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip,
     820             :                           icmp46_header_t *icmp, u32 sw_if_index,
     821             :                           u32 tx_sw_if_index, u32 rx_fib_index,
     822             :                           vlib_node_runtime_t *node, u32 next, f64 now,
     823             :                           u32 thread_index, snat_session_t **s_p,
     824             :                           int is_multi_worker)
     825             : {
     826        6568 :   vlib_main_t *vm = vlib_get_main ();
     827             :   u16 checksum;
     828             :   int err;
     829        6568 :   snat_session_t *s = NULL;
     830        6568 :   u8 lookup_protocol = ip->protocol;
     831             :   u16 lookup_sport, lookup_dport;
     832             :   ip4_address_t lookup_saddr, lookup_daddr;
     833             : 
     834        6568 :   err = nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr,
     835             :                                             &lookup_sport, &lookup_daddr,
     836             :                                             &lookup_dport, &lookup_protocol);
     837        6568 :   if (err != 0)
     838             :     {
     839           0 :       b->error = node->errors[err];
     840           0 :       return NAT_NEXT_DROP;
     841             :     }
     842             : 
     843        6568 :   if (tx_sw_if_index != ~0)
     844             :     {
     845           8 :       if (PREDICT_FALSE (nat44_ed_not_translate_output_feature (
     846             :             sm, b, ip, lookup_sport, lookup_dport, thread_index, sw_if_index,
     847             :             tx_sw_if_index, is_multi_worker)))
     848             :         {
     849           2 :           return next;
     850             :         }
     851             :     }
     852             :   else
     853             :     {
     854        6560 :       if (PREDICT_FALSE (nat44_ed_not_translate (
     855             :             vm, node, sw_if_index, b, ip, IP_PROTOCOL_ICMP, rx_fib_index)))
     856             :         {
     857           0 :           return next;
     858             :         }
     859             :     }
     860             : 
     861        6566 :   if (PREDICT_FALSE (icmp_type_is_error_message (
     862             :         vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
     863             :     {
     864           0 :       b->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
     865           0 :       return NAT_NEXT_DROP;
     866             :     }
     867             : 
     868             :   next =
     869        6566 :     slow_path_ed (vm, sm, b, ip->src_address, ip->dst_address, lookup_sport,
     870        6566 :                   lookup_dport, ip->protocol, rx_fib_index, tx_sw_if_index, &s,
     871             :                   node, next, thread_index, vlib_time_now (vm));
     872             : 
     873        6566 :   if (NAT_NEXT_DROP == next)
     874           1 :     goto out;
     875             : 
     876        6565 :   if (PREDICT_TRUE (!ip4_is_fragment (ip)))
     877             :     {
     878       13112 :       ip_csum_t sum = ip_incremental_checksum_buffer (
     879        6556 :         vm, b, (u8 *) icmp - (u8 *) vlib_buffer_get_current (b),
     880        6556 :         ntohs (ip->length) - ip4_header_bytes (ip), 0);
     881        6556 :       checksum = ~ip_csum_fold (sum);
     882        6556 :       if (PREDICT_FALSE (checksum != 0 && checksum != 0xffff))
     883             :         {
     884           0 :           next = NAT_NEXT_DROP;
     885           0 :           goto out;
     886             :         }
     887             :     }
     888             : 
     889        6565 : out:
     890        6566 :   if (PREDICT_TRUE (next != NAT_NEXT_DROP && s))
     891             :     {
     892             :       /* Accounting */
     893        6565 :       nat44_session_update_counters (
     894             :         s, now, vlib_buffer_length_in_chain (vm, b), thread_index);
     895             :       /* Per-user LRU list maintenance */
     896        6565 :       nat44_session_update_lru (sm, s, thread_index);
     897             :     }
     898        6566 :   *s_p = s;
     899        6566 :   return next;
     900             : }
     901             : 
     902             : static snat_session_t *
     903           2 : nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
     904             :                                         ip4_header_t *ip, u32 rx_fib_index,
     905             :                                         u32 thread_index, f64 now,
     906             :                                         vlib_main_t *vm,
     907             :                                         vlib_node_runtime_t *node)
     908             : {
     909             :   clib_bihash_kv_16_8_t s_kv, s_value;
     910           2 :   snat_static_mapping_t *m = NULL;
     911           2 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     912           2 :   snat_session_t *s = NULL;
     913             :   u32 tx_fib_index;
     914             :   int i;
     915           2 :   ip4_address_t new_src_addr = { 0 };
     916           2 :   ip4_address_t new_dst_addr = ip->dst_address;
     917             : 
     918           2 :   if (PREDICT_FALSE (
     919             :         nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
     920             :     {
     921           0 :       b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     922           0 :       nat_ipfix_logging_max_sessions (thread_index,
     923             :                                       sm->max_translations_per_thread);
     924           0 :       nat_elog_notice (sm, "maximum sessions exceeded");
     925           0 :       return 0;
     926             :     }
     927             : 
     928           2 :   tx_fib_index = get_tx_fib_index (rx_fib_index, ip->dst_address);
     929             : 
     930             :   // Try to find static mapping first
     931           2 :   m = nat44_ed_sm_i2o_lookup (sm, ip->src_address, 0, rx_fib_index,
     932           2 :                               ip->protocol);
     933           2 :   if (m)
     934             :     {
     935           0 :       new_src_addr = m->external_addr;
     936             :     }
     937             :   else
     938             :     {
     939           2 :       pool_foreach (s, tsm->sessions)
     940             :         {
     941           2 :           if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
     942             :             {
     943           2 :               init_ed_k (&s_kv, s->out2in.addr.as_u32, 0,
     944             :                          ip->dst_address.as_u32, 0, tx_fib_index,
     945           2 :                          ip->protocol);
     946           2 :               if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value))
     947             :                 {
     948           2 :                   new_src_addr = s->out2in.addr;
     949             :                 }
     950           2 :               break;
     951             :             }
     952             :         }
     953             : 
     954           2 :       if (!new_src_addr.as_u32)
     955             :         {
     956           0 :           for (i = 0; i < vec_len (sm->addresses); i++)
     957             :             {
     958           0 :               init_ed_k (&s_kv, sm->addresses[i].addr.as_u32, 0,
     959             :                          ip->dst_address.as_u32, 0, tx_fib_index,
     960           0 :                          ip->protocol);
     961           0 :               if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value))
     962             :                 {
     963           0 :                   new_src_addr = sm->addresses[i].addr;
     964             :                 }
     965             :             }
     966             :         }
     967             :     }
     968             : 
     969           2 :   if (!new_src_addr.as_u32)
     970             :     {
     971             :       // could not allocate address for translation ...
     972           0 :       return 0;
     973             :     }
     974             : 
     975           2 :   s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
     976           2 :   if (!s)
     977             :     {
     978           0 :       b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     979           0 :       nat_elog_warn (sm, "create NAT session failed");
     980           0 :       return 0;
     981             :     }
     982             : 
     983           2 :   nat_6t_i2o_flow_init (sm, thread_index, s, ip->src_address, 0,
     984           2 :                         ip->dst_address, 0, rx_fib_index, ip->protocol);
     985           2 :   nat_6t_flow_saddr_rewrite_set (&s->i2o, new_src_addr.as_u32);
     986           2 :   nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index);
     987             : 
     988             :   // hairpinning?
     989           2 :   int is_hairpinning = nat44_ed_external_sm_lookup (
     990           2 :     sm, ip->dst_address, 0, ip->protocol, &new_dst_addr, NULL);
     991           2 :   s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING;
     992             : 
     993           2 :   nat_6t_flow_daddr_rewrite_set (&s->i2o, new_dst_addr.as_u32);
     994           2 :   nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index);
     995             : 
     996           2 :   nat_6t_o2i_flow_init (sm, thread_index, s, new_dst_addr, 0, new_src_addr, 0,
     997           2 :                         tx_fib_index, ip->protocol);
     998           2 :   nat_6t_flow_saddr_rewrite_set (&s->o2i, ip->dst_address.as_u32);
     999           2 :   nat_6t_flow_daddr_rewrite_set (&s->o2i, ip->src_address.as_u32);
    1000           2 :   nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
    1001             : 
    1002           2 :   s->ext_host_addr.as_u32 = ip->dst_address.as_u32;
    1003           2 :   s->out2in.addr.as_u32 = new_src_addr.as_u32;
    1004           2 :   s->out2in.fib_index = tx_fib_index;
    1005           2 :   s->in2out.addr.as_u32 = ip->src_address.as_u32;
    1006           2 :   s->in2out.fib_index = rx_fib_index;
    1007           2 :   s->in2out.port = s->out2in.port = ip->protocol;
    1008           2 :   if (m)
    1009           0 :     s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
    1010             : 
    1011           2 :   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
    1012             :     {
    1013           0 :       nat_elog_notice (sm, "in2out flow hash add failed");
    1014           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
    1015           0 :       return NULL;
    1016             :     }
    1017             : 
    1018           2 :   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
    1019             :     {
    1020           0 :       nat_elog_notice (sm, "out2in flow hash add failed");
    1021           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
    1022           0 :       return NULL;
    1023             :     }
    1024             : 
    1025           2 :   per_vrf_sessions_register_session (s, thread_index);
    1026             : 
    1027             :   /* Accounting */
    1028           2 :   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
    1029             :                                  thread_index);
    1030             :   /* Per-user LRU list maintenance */
    1031           2 :   nat44_session_update_lru (sm, s, thread_index);
    1032             : 
    1033           2 :   return s;
    1034             : }
    1035             : 
    1036             : static inline uword
    1037         365 : nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm,
    1038             :                                           vlib_node_runtime_t *node,
    1039             :                                           vlib_frame_t *frame,
    1040             :                                           int is_output_feature,
    1041             :                                           int is_multi_worker)
    1042             : {
    1043             :   u32 n_left_from, *from;
    1044         365 :   snat_main_t *sm = &snat_main;
    1045         365 :   f64 now = vlib_time_now (vm);
    1046         362 :   u32 thread_index = vm->thread_index;
    1047         362 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
    1048         362 :   u32 def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH
    1049         362 :     : NAT_NEXT_IN2OUT_ED_SLOW_PATH;
    1050             : 
    1051         362 :   from = vlib_frame_vector_args (frame);
    1052         362 :   n_left_from = frame->n_vectors;
    1053             : 
    1054         362 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
    1055         362 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
    1056         362 :   vlib_get_buffers (vm, from, b, n_left_from);
    1057             : 
    1058       28967 :   while (n_left_from > 0)
    1059             :     {
    1060             :       vlib_buffer_t *b0;
    1061       28602 :       u32 rx_sw_if_index0, rx_fib_index0, iph_offset0 = 0;
    1062             :       u32 tx_sw_if_index0;
    1063             :       u32 cntr_sw_if_index0;
    1064             :       ip_protocol_t proto0;
    1065             :       ip4_header_t *ip0;
    1066       28602 :       snat_session_t *s0 = 0;
    1067       28602 :       clib_bihash_kv_16_8_t kv0 = { 0 }, value0;
    1068       28602 :       nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
    1069       28602 :       nat_6t_flow_t *f = 0;
    1070             :       nat_6t_t lookup;
    1071       28602 :       int lookup_skipped = 0;
    1072             : 
    1073       28602 :       b0 = *b;
    1074       28602 :       b++;
    1075             : 
    1076             :       /* Prefetch next iteration. */
    1077       28602 :       if (PREDICT_TRUE (n_left_from >= 2))
    1078             :         {
    1079             :           vlib_buffer_t *p2;
    1080             : 
    1081       28237 :           p2 = *b;
    1082             : 
    1083       28237 :           vlib_prefetch_buffer_header (p2, LOAD);
    1084             : 
    1085       28240 :           clib_prefetch_load (p2->data);
    1086             :         }
    1087             : 
    1088       28605 :       if (is_output_feature)
    1089             :         {
    1090          66 :           iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
    1091             :         }
    1092             : 
    1093       28605 :       next[0] = vnet_buffer2 (b0)->nat.arc_next;
    1094             : 
    1095       28604 :       ip0 =
    1096       28605 :         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + iph_offset0);
    1097             : 
    1098       28604 :       rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1099       28604 :       tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
    1100       28604 :       cntr_sw_if_index0 =
    1101       28604 :         is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
    1102       28604 :       rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
    1103             :                                                            rx_sw_if_index0);
    1104       28600 :       lookup.fib_index = rx_fib_index0;
    1105             : 
    1106       28600 :       if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1))
    1107             :         {
    1108           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1109           0 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
    1110             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
    1111             :                                        0);
    1112           0 :           next[0] = NAT_NEXT_ICMP_ERROR;
    1113           0 :           goto trace0;
    1114             :         }
    1115             : 
    1116       28600 :       proto0 = ip0->protocol;
    1117             : 
    1118       28600 :       if (is_output_feature)
    1119             :         {
    1120          66 :           if (PREDICT_FALSE
    1121             :               (nat_not_translate_output_feature_fwd
    1122             :                (sm, ip0, thread_index, now, vm, b0)))
    1123           8 :             goto trace0;
    1124             :         }
    1125             : 
    1126       28592 :       if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP))
    1127             :         {
    1128        6597 :           if (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
    1129          15 :                 ICMP4_echo_request &&
    1130          15 :               vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
    1131           3 :                 ICMP4_echo_reply &&
    1132           3 :               !icmp_type_is_error_message (
    1133           3 :                 vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
    1134             :             {
    1135           0 :               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_BAD_ICMP_TYPE];
    1136           0 :               next[0] = NAT_NEXT_DROP;
    1137           0 :               goto trace0;
    1138             :             }
    1139        6597 :           int err = nat_get_icmp_session_lookup_values (
    1140             :             b0, ip0, &lookup.saddr, &lookup.sport, &lookup.daddr,
    1141             :             &lookup.dport, &lookup.proto);
    1142        6597 :           if (err != 0)
    1143             :             {
    1144           0 :               b0->error = node->errors[err];
    1145           0 :               next[0] = NAT_NEXT_DROP;
    1146           0 :               goto trace0;
    1147             :             }
    1148             :         }
    1149             :       else
    1150             :         {
    1151       21995 :           lookup.proto = ip0->protocol;
    1152       21995 :           lookup.saddr.as_u32 = ip0->src_address.as_u32;
    1153       21995 :           lookup.daddr.as_u32 = ip0->dst_address.as_u32;
    1154       21995 :           lookup.sport = vnet_buffer (b0)->ip.reass.l4_src_port;
    1155       21995 :           lookup.dport = vnet_buffer (b0)->ip.reass.l4_dst_port;
    1156             :         }
    1157             : 
    1158             :       /* there might be a stashed index in vnet_buffer2 from handoff or
    1159             :        * classify node, see if it can be used */
    1160       56999 :       if (is_multi_worker &&
    1161       28409 :           !pool_is_free_index (tsm->sessions,
    1162       28409 :                                vnet_buffer2 (b0)->nat.cached_session_index))
    1163             :         {
    1164       24025 :           s0 = pool_elt_at_index (tsm->sessions,
    1165             :                                   vnet_buffer2 (b0)->nat.cached_session_index);
    1166       24025 :           if (PREDICT_TRUE (
    1167             :                 nat_6t_t_eq (&s0->i2o.match, &lookup)
    1168             :                 // for some hairpinning cases there are two "i2i" flows instead
    1169             :                 // of i2o and o2i as both hosts are on inside
    1170             :                 || (s0->flags & SNAT_SESSION_FLAG_HAIRPINNING &&
    1171             :                     nat_6t_t_eq (&s0->o2i.match, &lookup))))
    1172             :             {
    1173             :               /* yes, this is the droid we're looking for */
    1174         140 :               lookup_skipped = 1;
    1175         140 :               goto skip_lookup;
    1176             :             }
    1177       23885 :           s0 = NULL;
    1178             :         }
    1179             : 
    1180       28450 :       init_ed_k (&kv0, lookup.saddr.as_u32, lookup.sport, lookup.daddr.as_u32,
    1181       28450 :                  lookup.dport, lookup.fib_index, lookup.proto);
    1182             : 
    1183             :       // lookup flow
    1184       28450 :       if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
    1185             :         {
    1186             :           // flow does not exist go slow path
    1187       28417 :           next[0] = def_slow;
    1188       28417 :           goto trace0;
    1189             :         }
    1190             : 
    1191          39 :       ASSERT (thread_index == ed_value_get_thread_index (&value0));
    1192          39 :       s0 =
    1193          39 :         pool_elt_at_index (tsm->sessions,
    1194             :                            ed_value_get_session_index (&value0));
    1195             : 
    1196         179 :     skip_lookup:
    1197             : 
    1198         179 :       ASSERT (thread_index == s0->thread_index);
    1199             : 
    1200         179 :       if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
    1201             :         {
    1202             :           // session is closed, go slow path
    1203           0 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1204           0 :           nat_ed_session_delete (sm, s0, thread_index, 1);
    1205           0 :           s0 = 0;
    1206           0 :           next[0] = def_slow;
    1207           0 :           goto trace0;
    1208             :         }
    1209             : 
    1210             :       // drop if session expired
    1211             :       u64 sess_timeout_time;
    1212         179 :       sess_timeout_time =
    1213         179 :         s0->last_heard + (f64) nat44_session_get_timeout (sm, s0);
    1214         179 :       if (now >= sess_timeout_time)
    1215             :         {
    1216           7 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1217           7 :           nat_ed_session_delete (sm, s0, thread_index, 1);
    1218           7 :           s0 = 0;
    1219             :           // session is closed, go slow path
    1220           7 :           next[0] = def_slow;
    1221           7 :           goto trace0;
    1222             :         }
    1223             : 
    1224         172 :       b0->flags |= VNET_BUFFER_F_IS_NATED;
    1225             : 
    1226         172 :       if (nat_6t_t_eq (&s0->i2o.match, &lookup))
    1227             :         {
    1228         171 :           f = &s0->i2o;
    1229             :         }
    1230           2 :       else if (s0->flags & SNAT_SESSION_FLAG_HAIRPINNING &&
    1231           1 :                nat_6t_t_eq (&s0->o2i.match, &lookup))
    1232             :         {
    1233           1 :           f = &s0->o2i;
    1234             :         }
    1235             :       else
    1236             :         {
    1237           0 :           translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH;
    1238           0 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1239           0 :           nat_ed_session_delete (sm, s0, thread_index, 1);
    1240           0 :           s0 = 0;
    1241           0 :           next[0] = NAT_NEXT_DROP;
    1242           0 :           b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
    1243           0 :           goto trace0;
    1244             :         }
    1245             : 
    1246         172 :       if (NAT_ED_TRNSL_ERR_SUCCESS !=
    1247         172 :           (translation_error = nat_6t_flow_buf_translate_i2o (
    1248             :              vm, sm, b0, ip0, f, proto0, is_output_feature)))
    1249             :         {
    1250           0 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1251           0 :           nat_ed_session_delete (sm, s0, thread_index, 1);
    1252           0 :           s0 = 0;
    1253           0 :           next[0] = NAT_NEXT_DROP;
    1254           0 :           b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
    1255           0 :           goto trace0;
    1256             :         }
    1257             : 
    1258         172 :       switch (proto0)
    1259             :         {
    1260         116 :         case IP_PROTOCOL_TCP:
    1261         116 :           vlib_increment_simple_counter (&sm->counters.fastpath.in2out.tcp,
    1262             :                                          thread_index, cntr_sw_if_index0, 1);
    1263         116 :           nat44_set_tcp_session_state_i2o (
    1264         116 :             sm, now, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
    1265             :             thread_index);
    1266         116 :           break;
    1267          25 :         case IP_PROTOCOL_UDP:
    1268          25 :           vlib_increment_simple_counter (&sm->counters.fastpath.in2out.udp,
    1269             :                                          thread_index, cntr_sw_if_index0, 1);
    1270          25 :           break;
    1271          30 :         case IP_PROTOCOL_ICMP:
    1272          30 :           vlib_increment_simple_counter (&sm->counters.fastpath.in2out.icmp,
    1273             :                                          thread_index, cntr_sw_if_index0, 1);
    1274          30 :           break;
    1275           1 :         default:
    1276           1 :           vlib_increment_simple_counter (&sm->counters.fastpath.in2out.other,
    1277             :                                          thread_index, cntr_sw_if_index0, 1);
    1278           1 :           break;
    1279             :         }
    1280             : 
    1281             :       /* Accounting */
    1282         172 :       nat44_session_update_counters (s0, now,
    1283             :                                      vlib_buffer_length_in_chain (vm, b0),
    1284             :                                      thread_index);
    1285             :       /* Per-user LRU list maintenance */
    1286         172 :       nat44_session_update_lru (sm, s0, thread_index);
    1287             : 
    1288       28604 :     trace0:
    1289       28604 :       if (PREDICT_FALSE
    1290             :           ((node->flags & VLIB_NODE_FLAG_TRACE)
    1291             :            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
    1292             :         {
    1293             :           nat_in2out_ed_trace_t *t =
    1294       20106 :             vlib_add_trace (vm, node, b0, sizeof (*t));
    1295       20110 :           t->sw_if_index = rx_sw_if_index0;
    1296       20110 :           t->next_index = next[0];
    1297       20110 :           t->is_slow_path = 0;
    1298       20110 :           t->translation_error = translation_error;
    1299       20110 :           t->lookup_skipped = lookup_skipped;
    1300       20110 :           clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
    1301             : 
    1302       20106 :           if (s0)
    1303             :             {
    1304         172 :               t->session_index = s0 - tsm->sessions;
    1305         172 :               clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
    1306         172 :               clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
    1307         172 :               t->translation_via_i2of = (&s0->i2o == f);
    1308         172 :               t->tcp_state = s0->tcp_state;
    1309             :             }
    1310             :           else
    1311             :             {
    1312       19934 :               t->session_index = ~0;
    1313             :             }
    1314             :         }
    1315             : 
    1316       28604 :       if (next[0] == NAT_NEXT_DROP)
    1317             :         {
    1318           0 :           vlib_increment_simple_counter (&sm->counters.fastpath.in2out.drops,
    1319             :                                          thread_index, cntr_sw_if_index0, 1);
    1320             :         }
    1321             : 
    1322       28604 :       n_left_from--;
    1323       28604 :       next++;
    1324             :     }
    1325             : 
    1326         365 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
    1327         365 :                                frame->n_vectors);
    1328         365 :   return frame->n_vectors;
    1329             : }
    1330             : 
    1331             : static inline uword
    1332         257 : nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm,
    1333             :                                           vlib_node_runtime_t *node,
    1334             :                                           vlib_frame_t *frame,
    1335             :                                           int is_output_feature,
    1336             :                                           int is_multi_worker)
    1337             : {
    1338             :   u32 n_left_from, *from;
    1339         257 :   snat_main_t *sm = &snat_main;
    1340         257 :   f64 now = vlib_time_now (vm);
    1341         257 :   u32 thread_index = vm->thread_index;
    1342         257 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
    1343             : 
    1344         257 :   from = vlib_frame_vector_args (frame);
    1345         257 :   n_left_from = frame->n_vectors;
    1346             : 
    1347         257 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
    1348         257 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
    1349         257 :   vlib_get_buffers (vm, from, b, n_left_from);
    1350             : 
    1351       28696 :   while (n_left_from > 0)
    1352             :     {
    1353             :       vlib_buffer_t *b0;
    1354       28439 :       u32 rx_sw_if_index0, rx_fib_index0, iph_offset0 = 0;
    1355             :       u32 tx_sw_if_index0;
    1356             :       u32 cntr_sw_if_index0;
    1357             :       ip_protocol_t proto0;
    1358             :       ip4_header_t *ip0;
    1359             :       udp_header_t *udp0;
    1360             :       icmp46_header_t *icmp0;
    1361       28439 :       snat_session_t *s0 = 0;
    1362       28439 :       clib_bihash_kv_16_8_t kv0 = { 0 }, value0;
    1363       28439 :       int translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
    1364             : 
    1365       28439 :       b0 = *b;
    1366             : 
    1367       28439 :       if (is_output_feature)
    1368          52 :         iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
    1369             : 
    1370       28439 :       next[0] = vnet_buffer2 (b0)->nat.arc_next;
    1371             : 
    1372       28439 :       ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) +
    1373             :                               iph_offset0);
    1374             : 
    1375       28439 :       rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1376       28439 :       tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
    1377       28439 :       cntr_sw_if_index0 =
    1378       28439 :         is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
    1379       28439 :       rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
    1380             :                                                            rx_sw_if_index0);
    1381             : 
    1382       28439 :       if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1))
    1383             :         {
    1384           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1385           0 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
    1386             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
    1387             :                                        0);
    1388           0 :           next[0] = NAT_NEXT_ICMP_ERROR;
    1389           0 :           goto trace0;
    1390             :         }
    1391             : 
    1392       28439 :       udp0 = ip4_next_header (ip0);
    1393       28439 :       icmp0 = (icmp46_header_t *) udp0;
    1394       28439 :       proto0 = ip0->protocol;
    1395             : 
    1396       28439 :       if (PREDICT_FALSE (nat44_ed_is_unk_proto (proto0)))
    1397             :         {
    1398           2 :           s0 = nat44_ed_in2out_slowpath_unknown_proto (
    1399             :             sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node);
    1400           2 :           if (!s0)
    1401           0 :             next[0] = NAT_NEXT_DROP;
    1402             : 
    1403           2 :           if (NAT_NEXT_DROP != next[0] && s0 &&
    1404             :               NAT_ED_TRNSL_ERR_SUCCESS !=
    1405           2 :                 (translation_error = nat_6t_flow_buf_translate_i2o (
    1406           2 :                    vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature)))
    1407             :             {
    1408           0 :               nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1409           0 :               nat_ed_session_delete (sm, s0, thread_index, 1);
    1410           0 :               s0 = 0;
    1411           0 :               next[0] = NAT_NEXT_DROP;
    1412           0 :               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
    1413           0 :               goto trace0;
    1414             :             }
    1415             : 
    1416           2 :           vlib_increment_simple_counter (&sm->counters.slowpath.in2out.other,
    1417             :                                          thread_index, cntr_sw_if_index0, 1);
    1418           2 :           goto trace0;
    1419             :         }
    1420             : 
    1421       28437 :       if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP))
    1422             :         {
    1423       13136 :           next[0] = icmp_in2out_ed_slow_path (
    1424             :             sm, b0, ip0, icmp0, rx_sw_if_index0, tx_sw_if_index0,
    1425        6568 :             rx_fib_index0, node, next[0], now, thread_index, &s0,
    1426             :             is_multi_worker);
    1427        6568 :           if (NAT_NEXT_DROP != next[0] && s0 &&
    1428             :               NAT_ED_TRNSL_ERR_SUCCESS !=
    1429        6565 :                 (translation_error = nat_6t_flow_buf_translate_i2o (
    1430        6565 :                    vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature)))
    1431             :             {
    1432           0 :               nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1433           0 :               nat_ed_session_delete (sm, s0, thread_index, 1);
    1434           0 :               s0 = 0;
    1435           0 :               next[0] = NAT_NEXT_DROP;
    1436           0 :               b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
    1437           0 :               goto trace0;
    1438             :             }
    1439             : 
    1440        6568 :           if (NAT_NEXT_DROP != next[0])
    1441             :             {
    1442        6567 :               vlib_increment_simple_counter (
    1443             :                 &sm->counters.slowpath.in2out.icmp, thread_index,
    1444             :                 cntr_sw_if_index0, 1);
    1445             :             }
    1446        6568 :           goto trace0;
    1447             :         }
    1448             : 
    1449       21869 :       init_ed_k (
    1450       21869 :         &kv0, ip0->src_address.as_u32, vnet_buffer (b0)->ip.reass.l4_src_port,
    1451       21869 :         ip0->dst_address.as_u32, vnet_buffer (b0)->ip.reass.l4_dst_port,
    1452       21869 :         rx_fib_index0, ip0->protocol);
    1453       21869 :       if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
    1454             :         {
    1455          21 :           ASSERT (thread_index == ed_value_get_thread_index (&value0));
    1456          21 :           s0 =
    1457          21 :             pool_elt_at_index (tsm->sessions,
    1458             :                                ed_value_get_session_index (&value0));
    1459             :         }
    1460             : 
    1461       21869 :       if (!s0)
    1462             :         {
    1463       21848 :           if (is_output_feature)
    1464             :             {
    1465          38 :               if (PREDICT_FALSE (nat44_ed_not_translate_output_feature (
    1466             :                     sm, b0, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
    1467             :                     vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
    1468             :                     rx_sw_if_index0, tx_sw_if_index0, is_multi_worker)))
    1469          22 :                 goto trace0;
    1470             : 
    1471             :               /*
    1472             :                * Send DHCP packets to the ipv4 stack, or we won't
    1473             :                * be able to use dhcp client on the outside interface
    1474             :                */
    1475          16 :               if (PREDICT_FALSE (
    1476             :                     proto0 == IP_PROTOCOL_UDP &&
    1477             :                     (vnet_buffer (b0)->ip.reass.l4_dst_port ==
    1478             :                      clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server)) &&
    1479             :                     ip0->dst_address.as_u32 == 0xffffffff))
    1480           0 :                 goto trace0;
    1481             :             }
    1482             :           else
    1483             :             {
    1484       21810 :               if (PREDICT_FALSE (
    1485             :                     nat44_ed_not_translate (vm, node, rx_sw_if_index0, b0, ip0,
    1486             :                                             proto0, rx_fib_index0)))
    1487          21 :                 goto trace0;
    1488             :             }
    1489             : 
    1490       21806 :           next[0] =
    1491       21803 :             slow_path_ed (vm, sm, b0, ip0->src_address, ip0->dst_address,
    1492       21803 :                           vnet_buffer (b0)->ip.reass.l4_src_port,
    1493       21803 :                           vnet_buffer (b0)->ip.reass.l4_dst_port,
    1494       21803 :                           ip0->protocol, rx_fib_index0, tx_sw_if_index0, &s0,
    1495       21803 :                           node, next[0], thread_index, now);
    1496             : 
    1497       21806 :           if (PREDICT_FALSE (next[0] == NAT_NEXT_DROP))
    1498         151 :             goto trace0;
    1499             : 
    1500       21655 :           if (PREDICT_FALSE (!s0))
    1501           0 :             goto trace0;
    1502             : 
    1503             :         }
    1504             : 
    1505       21676 :       b0->flags |= VNET_BUFFER_F_IS_NATED;
    1506             : 
    1507       21676 :       if (NAT_ED_TRNSL_ERR_SUCCESS !=
    1508       21676 :           (translation_error = nat_6t_flow_buf_translate_i2o (
    1509       21676 :              vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature)))
    1510             :         {
    1511           0 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
    1512           0 :           nat_ed_session_delete (sm, s0, thread_index, 1);
    1513           0 :           s0 = 0;
    1514           0 :           next[0] = NAT_NEXT_DROP;
    1515           0 :           b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED];
    1516           0 :           goto trace0;
    1517             :         }
    1518             : 
    1519       21676 :       if (PREDICT_TRUE (proto0 == IP_PROTOCOL_TCP))
    1520             :         {
    1521        1608 :           vlib_increment_simple_counter (&sm->counters.slowpath.in2out.tcp,
    1522             :                                          thread_index, cntr_sw_if_index0, 1);
    1523        1608 :           nat44_set_tcp_session_state_i2o (
    1524        1608 :             sm, now, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags,
    1525             :             thread_index);
    1526             :         }
    1527             :       else
    1528             :         {
    1529       20068 :           vlib_increment_simple_counter (&sm->counters.slowpath.in2out.udp,
    1530             :                                          thread_index, cntr_sw_if_index0, 1);
    1531             :         }
    1532             : 
    1533             :       /* Accounting */
    1534       21676 :       nat44_session_update_counters (s0, now,
    1535             :                                      vlib_buffer_length_in_chain
    1536             :                                      (vm, b0), thread_index);
    1537             :       /* Per-user LRU list maintenance */
    1538       21676 :       nat44_session_update_lru (sm, s0, thread_index);
    1539             : 
    1540       28440 :     trace0:
    1541       28440 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
    1542             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
    1543             :         {
    1544             :           nat_in2out_ed_trace_t *t =
    1545       17555 :             vlib_add_trace (vm, node, b0, sizeof (*t));
    1546       17551 :           t->sw_if_index = rx_sw_if_index0;
    1547       17551 :           t->next_index = next[0];
    1548       17551 :           t->is_slow_path = 1;
    1549       17551 :           t->translation_error = translation_error;
    1550       17551 :           clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
    1551             : 
    1552       17552 :           if (s0)
    1553             :             {
    1554       17355 :               t->session_index = s0 - tsm->sessions;
    1555       17355 :               clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
    1556       17355 :               clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
    1557       17357 :               t->translation_via_i2of = 1;
    1558       17357 :               t->tcp_state = s0->tcp_state;
    1559             :             }
    1560             : 
    1561             :           else
    1562             :             {
    1563         197 :               t->session_index = ~0;
    1564             :             }
    1565             :         }
    1566             : 
    1567       28439 :       if (next[0] == NAT_NEXT_DROP)
    1568             :         {
    1569         152 :           vlib_increment_simple_counter (&sm->counters.slowpath.in2out.drops,
    1570             :                                          thread_index, cntr_sw_if_index0, 1);
    1571             :         }
    1572             : 
    1573       28439 :       n_left_from--;
    1574       28439 :       next++;
    1575       28439 :       b++;
    1576             :     }
    1577             : 
    1578         257 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
    1579         257 :                                frame->n_vectors);
    1580             : 
    1581         257 :   return frame->n_vectors;
    1582             : }
    1583             : 
    1584        2638 : VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
    1585             :                                      vlib_node_runtime_t * node,
    1586             :                                      vlib_frame_t * frame)
    1587             : {
    1588         338 :   if (snat_main.num_workers > 1)
    1589             :     {
    1590         302 :       return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0, 1);
    1591             :     }
    1592             :   else
    1593             :     {
    1594          36 :       return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0, 0);
    1595             :     }
    1596             : }
    1597             : 
    1598       58202 : VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
    1599             :   .name = "nat44-ed-in2out",
    1600             :   .vector_size = sizeof (u32),
    1601             :   .sibling_of = "nat-default",
    1602             :   .format_trace = format_nat_in2out_ed_trace,
    1603             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1604             :   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
    1605             :   .error_strings = nat_in2out_ed_error_strings,
    1606             :   .runtime_data_bytes = sizeof (snat_runtime_t),
    1607             : };
    1608             : 
    1609        2327 : VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
    1610             :                                             vlib_node_runtime_t * node,
    1611             :                                             vlib_frame_t * frame)
    1612             : {
    1613          27 :   if (snat_main.num_workers > 1)
    1614             :     {
    1615          15 :       return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1, 1);
    1616             :     }
    1617             :   else
    1618             :     {
    1619          12 :       return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1, 0);
    1620             :     }
    1621             : }
    1622             : 
    1623       58202 : VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
    1624             :   .name = "nat44-ed-in2out-output",
    1625             :   .vector_size = sizeof (u32),
    1626             :   .sibling_of = "nat-default",
    1627             :   .format_trace = format_nat_in2out_ed_trace,
    1628             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1629             :   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
    1630             :   .error_strings = nat_in2out_ed_error_strings,
    1631             :   .runtime_data_bytes = sizeof (snat_runtime_t),
    1632             : };
    1633             : 
    1634        2533 : VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
    1635             :                                               vlib_node_runtime_t *
    1636             :                                               node, vlib_frame_t * frame)
    1637             : {
    1638         233 :   if (snat_main.num_workers > 1)
    1639             :     {
    1640         221 :       return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0, 1);
    1641             :     }
    1642             :   else
    1643             :     {
    1644          12 :       return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0, 0);
    1645             :     }
    1646             : }
    1647             : 
    1648       58202 : VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
    1649             :   .name = "nat44-ed-in2out-slowpath",
    1650             :   .vector_size = sizeof (u32),
    1651             :   .sibling_of = "nat-default",
    1652             :   .format_trace = format_nat_in2out_ed_trace,
    1653             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1654             :   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
    1655             :   .error_strings = nat_in2out_ed_error_strings,
    1656             :   .runtime_data_bytes = sizeof (snat_runtime_t),
    1657             : };
    1658             : 
    1659        2324 : VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
    1660             :                                                      vlib_node_runtime_t
    1661             :                                                      * node,
    1662             :                                                      vlib_frame_t * frame)
    1663             : {
    1664          24 :   if (snat_main.num_workers > 1)
    1665             :     {
    1666          13 :       return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1, 1);
    1667             :     }
    1668             :   else
    1669             :     {
    1670          11 :       return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1, 0);
    1671             :     }
    1672             : }
    1673             : 
    1674       58202 : VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
    1675             :   .name = "nat44-ed-in2out-output-slowpath",
    1676             :   .vector_size = sizeof (u32),
    1677             :   .sibling_of = "nat-default",
    1678             :   .format_trace = format_nat_in2out_ed_trace,
    1679             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1680             :   .n_errors = ARRAY_LEN (nat_in2out_ed_error_strings),
    1681             :   .error_strings = nat_in2out_ed_error_strings,
    1682             :   .runtime_data_bytes = sizeof (snat_runtime_t),
    1683             : };
    1684             : 
    1685             : static u8 *
    1686         141 : format_nat_pre_trace (u8 * s, va_list * args)
    1687             : {
    1688         141 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1689         141 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1690         141 :   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
    1691         141 :   return format (s, "in2out next_index %d arc_next_index %d", t->next_index,
    1692             :                  t->arc_next_index);
    1693             : }
    1694             : 
    1695        2318 : VLIB_NODE_FN (nat_pre_in2out_node)
    1696             :   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
    1697             : {
    1698          18 :   return nat_pre_node_fn_inline (vm, node, frame,
    1699             :                                  NAT_NEXT_IN2OUT_ED_FAST_PATH);
    1700             : }
    1701             : 
    1702        2312 : VLIB_NODE_FN (nat_pre_in2out_output_node)
    1703             :   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
    1704             : {
    1705          12 :   return nat_pre_node_fn_inline (vm, node, frame,
    1706             :                                  NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH);
    1707             : }
    1708             : 
    1709       58202 : VLIB_REGISTER_NODE (nat_pre_in2out_node) = {
    1710             :   .name = "nat-pre-in2out",
    1711             :   .vector_size = sizeof (u32),
    1712             :   .sibling_of = "nat-default",
    1713             :   .format_trace = format_nat_pre_trace,
    1714             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1715             :   .n_errors = 0,
    1716             : };
    1717             : 
    1718       58202 : VLIB_REGISTER_NODE (nat_pre_in2out_output_node) = {
    1719             :   .name = "nat-pre-in2out-output",
    1720             :   .vector_size = sizeof (u32),
    1721             :   .sibling_of = "nat-default",
    1722             :   .format_trace = format_nat_pre_trace,
    1723             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1724             :   .n_errors = 0,
    1725             : };
    1726             : 
    1727             : /*
    1728             :  * fd.io coding-style-patch-verification: ON
    1729             :  *
    1730             :  * Local Variables:
    1731             :  * eval: (c-set-style "gnu")
    1732             :  * End:
    1733             :  */

Generated by: LCOV version 1.14