LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ed - nat44_ed_out2in.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 451 611 73.8 %
Date: 2023-07-05 22:20:52 Functions: 32 42 76.2 %

          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 outside to inside 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/ipfix_logging.h>
      29             : 
      30             : #include <nat/nat44-ed/nat44_ed.h>
      31             : #include <nat/nat44-ed/nat44_ed_inlines.h>
      32             : 
      33             : static char *nat_out2in_ed_error_strings[] = {
      34             : #define _(sym,string) string,
      35             :   foreach_nat_out2in_ed_error
      36             : #undef _
      37             : };
      38             : 
      39             : typedef enum
      40             : {
      41             :   NAT_ED_SP_REASON_NO_REASON,
      42             :   NAT_ED_SP_REASON_LOOKUP_FAILED,
      43             :   NAT_ED_SP_REASON_VRF_EXPIRED,
      44             :   NAT_ED_SP_SESS_EXPIRED,
      45             : } nat_slow_path_reason_e;
      46             : 
      47             : typedef struct
      48             : {
      49             :   u32 sw_if_index;
      50             :   u32 next_index;
      51             :   u32 session_index;
      52             :   nat_translation_error_e translation_error;
      53             :   nat_6t_flow_t i2of;
      54             :   nat_6t_flow_t o2if;
      55             :   clib_bihash_kv_16_8_t search_key;
      56             :   u8 is_slow_path;
      57             :   u8 translation_via_i2of;
      58             :   u8 lookup_skipped;
      59             :   u8 tcp_state;
      60             :   nat_slow_path_reason_e slow_path_reason;
      61             : } nat44_ed_out2in_trace_t;
      62             : 
      63             : static u8 *
      64        1466 : format_slow_path_reason (u8 *s, va_list *args)
      65             : {
      66        1466 :   nat_slow_path_reason_e reason = va_arg (*args, nat_slow_path_reason_e);
      67        1466 :   switch (reason)
      68             :     {
      69        1253 :     case NAT_ED_SP_REASON_NO_REASON:
      70        1253 :       return format (s, "no reason for slow path");
      71         211 :     case NAT_ED_SP_REASON_LOOKUP_FAILED:
      72         211 :       return format (s, "slow path because lookup failed");
      73           0 :     case NAT_ED_SP_REASON_VRF_EXPIRED:
      74           0 :       return format (s, "slow path because vrf expired");
      75           2 :     case NAT_ED_SP_SESS_EXPIRED:
      76           2 :       return format (s, "slow path because session expired");
      77             :     }
      78           0 :   return format (s, "invalid reason value");
      79             : }
      80             : 
      81             : static u8 *
      82        1679 : format_nat44_ed_out2in_trace (u8 * s, va_list * args)
      83             : {
      84        1679 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      85        1679 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      86        1679 :   nat44_ed_out2in_trace_t *t = va_arg (*args, nat44_ed_out2in_trace_t *);
      87             :   char *tag;
      88             : 
      89        1679 :   tag =
      90        1679 :     t->is_slow_path ? "NAT44_OUT2IN_ED_SLOW_PATH" :
      91             :     "NAT44_OUT2IN_ED_FAST_PATH";
      92             : 
      93        1679 :   s = format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index,
      94             :               t->next_index);
      95        1679 :   if (~0 != t->session_index)
      96             :     {
      97        1397 :       s = format (s, ", session %d, translation result '%U' via %s",
      98             :                   t->session_index, format_nat_ed_translation_error,
      99        1397 :                   t->translation_error,
     100        1397 :                   t->translation_via_i2of ? "i2of" : "o2if");
     101        1397 :       s = format (s, "\n  i2of %U", format_nat_6t_flow, &t->i2of);
     102        1397 :       s = format (s, "\n  o2if %U", format_nat_6t_flow, &t->o2if);
     103             :     }
     104        1679 :   if (!t->is_slow_path)
     105             :     {
     106        1466 :       if (t->lookup_skipped)
     107             :         {
     108         819 :           s = format (s, "\n  lookup skipped - cached session index used");
     109             :         }
     110             :       else
     111             :         {
     112         647 :           s = format (s, "\n  search key %U", format_ed_session_kvp,
     113             :                       &t->search_key);
     114             :         }
     115        1466 :       s = format (s, "\n  %U", format_slow_path_reason, t->slow_path_reason);
     116             :     }
     117        1679 :   if (IP_PROTOCOL_TCP == t->i2of.match.proto)
     118             :     {
     119         611 :       s = format (s, "\n  TCP state: %U", format_nat44_ed_tcp_state,
     120         611 :                   t->tcp_state);
     121             :     }
     122             : 
     123        1679 :   return s;
     124             : }
     125             : 
     126             : static int
     127          54 : next_src_nat (snat_main_t *sm, ip4_header_t *ip, u16 src_port, u16 dst_port,
     128             :               u32 rx_fib_index)
     129             : {
     130             :   clib_bihash_kv_16_8_t kv, value;
     131             : 
     132          54 :   init_ed_k (&kv, ip->src_address.as_u32, src_port, ip->dst_address.as_u32,
     133          54 :              dst_port, rx_fib_index, ip->protocol);
     134          54 :   if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
     135           0 :     return 1;
     136             : 
     137          54 :   return 0;
     138             : }
     139             : 
     140             : static void create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b,
     141             :                                    snat_session_t *s, ip4_header_t *ip,
     142             :                                    u32 rx_fib_index, u32 thread_index);
     143             : 
     144             : static snat_session_t *create_session_for_static_mapping_ed (
     145             :   snat_main_t *sm, vlib_buffer_t *b, ip4_address_t i2o_addr, u16 i2o_port,
     146             :   u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
     147             :   ip_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index,
     148             :   twice_nat_type_t twice_nat, lb_nat_type_t lb_nat, f64 now,
     149             :   snat_static_mapping_t *mapping);
     150             : 
     151             : static inline u32
     152          29 : icmp_out2in_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip,
     153             :                           icmp46_header_t *icmp, u32 sw_if_index,
     154             :                           u32 rx_fib_index, vlib_node_runtime_t *node,
     155             :                           u32 next, f64 now, u32 thread_index,
     156             :                           snat_session_t **s_p)
     157             : {
     158          29 :   vlib_main_t *vm = vlib_get_main ();
     159             : 
     160             :   ip_csum_t sum;
     161             :   u16 checksum;
     162             : 
     163          29 :   snat_session_t *s = 0;
     164             :   u8 is_addr_only, identity_nat;
     165             :   ip4_address_t sm_addr;
     166             :   u16 sm_port;
     167             :   u32 sm_fib_index;
     168             :   snat_static_mapping_t *m;
     169             :   u8 lookup_protocol;
     170             :   ip4_address_t lookup_saddr, lookup_daddr;
     171             :   u16 lookup_sport, lookup_dport;
     172             : 
     173          29 :   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
     174          29 :   rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
     175             : 
     176          29 :   if (nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr, &lookup_sport,
     177             :                                           &lookup_daddr, &lookup_dport,
     178             :                                           &lookup_protocol))
     179             :     {
     180           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
     181           0 :       next = NAT_NEXT_DROP;
     182           0 :       goto out;
     183             :     }
     184             : 
     185          29 :   if (snat_static_mapping_match (vm, ip->dst_address, lookup_sport,
     186          29 :                                  rx_fib_index, ip->protocol, &sm_addr,
     187             :                                  &sm_port, &sm_fib_index, 1, &is_addr_only, 0,
     188             :                                  0, 0, &identity_nat, &m))
     189             :     {
     190             :       // static mapping not matched
     191          19 :       if (!sm->forwarding_enabled)
     192             :         {
     193             :           /* Don't NAT packet aimed at the intfc address */
     194          11 :           if (!is_interface_addr (sm, node, sw_if_index,
     195             :                                   ip->dst_address.as_u32))
     196             :             {
     197          11 :               b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
     198          11 :               next = NAT_NEXT_DROP;
     199             :             }
     200             :         }
     201             :       else
     202             :         {
     203           8 :           if (next_src_nat (sm, ip, lookup_sport, lookup_dport, rx_fib_index))
     204             :             {
     205           0 :               next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
     206             :             }
     207             :           else
     208             :             {
     209           8 :               create_bypass_for_fwd (sm, b, s, ip, rx_fib_index, thread_index);
     210             :             }
     211             :         }
     212          19 :       goto out;
     213             :     }
     214             : 
     215          10 :   if (PREDICT_FALSE (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
     216             :                        ICMP4_echo_reply &&
     217             :                      (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
     218             :                         ICMP4_echo_request ||
     219             :                       !is_addr_only)))
     220             :     {
     221           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
     222           0 :       next = NAT_NEXT_DROP;
     223           0 :       goto out;
     224             :     }
     225             : 
     226          10 :   if (PREDICT_FALSE (identity_nat))
     227             :     {
     228           0 :       goto out;
     229             :     }
     230             : 
     231             :   /* Create session initiated by host from external network */
     232          10 :   s = create_session_for_static_mapping_ed (
     233             :     sm, b, sm_addr, sm_port, sm_fib_index, ip->dst_address, lookup_sport,
     234             :     rx_fib_index, lookup_protocol, node, thread_index, 0, 0,
     235             :     vlib_time_now (vm), m);
     236          10 :   if (!s)
     237           0 :     next = NAT_NEXT_DROP;
     238             : 
     239          10 :   if (PREDICT_TRUE (!ip4_is_fragment (ip)))
     240             :     {
     241           8 :       sum = ip_incremental_checksum_buffer (
     242           4 :         vm, b, (u8 *) icmp - (u8 *) vlib_buffer_get_current (b),
     243           4 :         ntohs (ip->length) - ip4_header_bytes (ip), 0);
     244           4 :       checksum = ~ip_csum_fold (sum);
     245           4 :       if (checksum != 0 && checksum != 0xffff)
     246             :         {
     247           0 :           next = NAT_NEXT_DROP;
     248           0 :           goto out;
     249             :         }
     250             :     }
     251             : 
     252          10 :   if (PREDICT_TRUE (next != NAT_NEXT_DROP && s))
     253             :     {
     254             :       /* Accounting */
     255          10 :       nat44_session_update_counters (
     256             :         s, now, vlib_buffer_length_in_chain (vm, b), thread_index);
     257             :       /* Per-user LRU list maintenance */
     258          10 :       nat44_session_update_lru (sm, s, thread_index);
     259             :     }
     260           0 : out:
     261          29 :   if (NAT_NEXT_DROP == next && s)
     262             :     {
     263           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
     264           0 :       s = 0;
     265             :     }
     266          29 :   *s_p = s;
     267          29 :   return next;
     268             : }
     269             : 
     270             : static_always_inline int
     271          11 : nat44_ed_alloc_i2o_port (snat_main_t *sm, snat_address_t *a, snat_session_t *s,
     272             :                          ip4_address_t i2o_addr, u16 i2o_port,
     273             :                          u32 i2o_fib_index, ip_protocol_t proto,
     274             :                          u32 thread_index, u32 snat_thread_index,
     275             :                          ip4_address_t *outside_addr, u16 *outside_port)
     276             : {
     277             :   u32 portnum;
     278             : 
     279          11 :   for (int i = 0; i < ED_PORT_ALLOC_ATTEMPTS; ++i)
     280             :     {
     281          22 :       portnum = (sm->port_per_thread * snat_thread_index) +
     282          11 :                 snat_random_port (0, sm->port_per_thread - 1) +
     283             :                 ED_USER_PORT_OFFSET;
     284          11 :       portnum = clib_host_to_net_u16 (portnum);
     285          11 :       nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port, a->addr,
     286             :                             portnum, i2o_fib_index, proto);
     287          11 :       if (!nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s,
     288             :                                              1 /* is_add */))
     289             :         {
     290          11 :           *outside_addr = a->addr;
     291          11 :           *outside_port = portnum;
     292          11 :           return 0;
     293             :         }
     294             :     }
     295             : 
     296             :   /* Totally out of translations to use... */
     297           0 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
     298           0 :   return 1;
     299             : }
     300             : 
     301             : static_always_inline int
     302          11 : nat44_ed_alloc_i2o_addr_and_port (snat_main_t *sm, snat_address_t *addresses,
     303             :                                   snat_session_t *s, ip4_address_t i2o_addr,
     304             :                                   u16 i2o_port, u32 i2o_fib_index,
     305             :                                   ip_protocol_t proto, u32 thread_index,
     306             :                                   u32 snat_thread_index,
     307             :                                   ip4_address_t *outside_addr,
     308             :                                   u16 *outside_port)
     309             : {
     310          11 :   snat_address_t *a, *ga = 0;
     311             :   int i;
     312             : 
     313          11 :   if (vec_len (addresses) > 0)
     314             :     {
     315          11 :       int s_addr_offset = i2o_addr.as_u32 % vec_len (addresses);
     316             : 
     317          22 :       for (i = s_addr_offset; i < vec_len (addresses); ++i)
     318             :         {
     319          11 :           a = addresses + i;
     320          11 :           if (a->fib_index == i2o_fib_index)
     321             :             {
     322           0 :               return nat44_ed_alloc_i2o_port (
     323             :                 sm, a, s, i2o_addr, i2o_port, i2o_fib_index, proto,
     324             :                 thread_index, snat_thread_index, outside_addr, outside_port);
     325             :             }
     326          11 :           else if (a->fib_index == ~0)
     327             :             {
     328          11 :               ga = a;
     329             :             }
     330             :         }
     331             : 
     332          11 :       for (i = 0; i < s_addr_offset; ++i)
     333             :         {
     334           0 :           a = addresses + i;
     335           0 :           if (a->fib_index == i2o_fib_index)
     336             :             {
     337           0 :               return nat44_ed_alloc_i2o_port (
     338             :                 sm, a, s, i2o_addr, i2o_port, i2o_fib_index, proto,
     339             :                 thread_index, snat_thread_index, outside_addr, outside_port);
     340             :             }
     341           0 :           else if (a->fib_index == ~0)
     342             :             {
     343           0 :               ga = a;
     344             :             }
     345             :         }
     346             : 
     347          11 :       if (ga)
     348             :         {
     349          11 :           return nat44_ed_alloc_i2o_port (
     350             :             sm, a, s, i2o_addr, i2o_port, i2o_fib_index, proto, thread_index,
     351             :             snat_thread_index, outside_addr, outside_port);
     352             :         }
     353             :     }
     354             : 
     355             :   /* Totally out of translations to use... */
     356           0 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
     357           0 :   return 1;
     358             : }
     359             : 
     360             : static snat_session_t *
     361         299 : create_session_for_static_mapping_ed (
     362             :   snat_main_t *sm, vlib_buffer_t *b, ip4_address_t i2o_addr, u16 i2o_port,
     363             :   u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
     364             :   ip_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index,
     365             :   twice_nat_type_t twice_nat, lb_nat_type_t lb_nat, f64 now,
     366             :   snat_static_mapping_t *mapping)
     367             : {
     368             :   snat_session_t *s;
     369             :   ip4_header_t *ip;
     370         299 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     371             : 
     372         299 :   if (PREDICT_FALSE (
     373             :         nat44_ed_maximum_sessions_exceeded (sm, o2i_fib_index, thread_index)))
     374             :     {
     375           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     376           0 :       nat_elog_notice (sm, "maximum sessions exceeded");
     377           0 :       return 0;
     378             :     }
     379             : 
     380         299 :   s = nat_ed_session_alloc (sm, thread_index, now, proto);
     381         299 :   if (!s)
     382             :     {
     383           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     384           0 :       nat_elog_warn (sm, "create NAT session failed");
     385           0 :       return 0;
     386             :     }
     387             : 
     388         299 :   ip = vlib_buffer_get_current (b);
     389             : 
     390         299 :   s->ext_host_addr.as_u32 = ip->src_address.as_u32;
     391         299 :   s->ext_host_port =
     392         289 :     proto == IP_PROTOCOL_ICMP ? 0 : vnet_buffer (b)->ip.reass.l4_src_port;
     393         299 :   s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
     394         299 :   if (lb_nat)
     395         258 :     s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
     396         299 :   if (lb_nat == AFFINITY_LB_NAT)
     397         142 :     s->flags |= SNAT_SESSION_FLAG_AFFINITY;
     398         299 :   s->out2in.addr = o2i_addr;
     399         299 :   s->out2in.port = o2i_port;
     400         299 :   s->out2in.fib_index = o2i_fib_index;
     401         299 :   s->in2out.addr = i2o_addr;
     402         299 :   s->in2out.port = i2o_port;
     403         299 :   s->in2out.fib_index = i2o_fib_index;
     404         299 :   s->proto = proto;
     405             : 
     406         299 :   if (IP_PROTOCOL_ICMP == proto)
     407             :     {
     408          10 :       nat_6t_o2i_flow_init (sm, thread_index, s, s->ext_host_addr, o2i_port,
     409          10 :                             o2i_addr, o2i_port, o2i_fib_index, ip->protocol);
     410          10 :       nat_6t_flow_icmp_id_rewrite_set (&s->o2i, i2o_port);
     411             :     }
     412             :   else
     413             :     {
     414         289 :       nat_6t_o2i_flow_init (sm, thread_index, s, s->ext_host_addr,
     415         289 :                             s->ext_host_port, o2i_addr, o2i_port,
     416         289 :                             o2i_fib_index, ip->protocol);
     417         289 :       nat_6t_flow_dport_rewrite_set (&s->o2i, i2o_port);
     418             :     }
     419         299 :   nat_6t_flow_daddr_rewrite_set (&s->o2i, i2o_addr.as_u32);
     420         298 :   nat_6t_flow_txfib_rewrite_set (&s->o2i, i2o_fib_index);
     421             : 
     422         298 :   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
     423             :     {
     424           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_HASH_ADD_FAILED];
     425           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
     426           0 :       nat_elog_warn (sm, "out2in flow hash add failed");
     427           0 :       return 0;
     428             :     }
     429             : 
     430         298 :   if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF &&
     431           7 :                                  ip->src_address.as_u32 == i2o_addr.as_u32))
     432          11 :     {
     433          11 :       int rc = 0;
     434          11 :       snat_address_t *filter = 0;
     435             : 
     436             :       // if exact address is specified use this address
     437          11 :       if (is_sm_exact_address (mapping->flags))
     438             :         {
     439             :           snat_address_t *ap;
     440           0 :           vec_foreach (ap, sm->twice_nat_addresses)
     441             :           {
     442           0 :             if (mapping->pool_addr.as_u32 == ap->addr.as_u32)
     443             :               {
     444           0 :                 filter = ap;
     445           0 :                 break;
     446             :               }
     447             :           }
     448             :         }
     449             : 
     450          11 :       if (filter)
     451             :         {
     452           0 :           rc = nat44_ed_alloc_i2o_port (
     453             :             sm, filter, s, i2o_addr, i2o_port, i2o_fib_index, proto,
     454             :             thread_index, tsm->snat_thread_index, &s->ext_host_nat_addr,
     455             :             &s->ext_host_nat_port);
     456           0 :           s->flags |= SNAT_SESSION_FLAG_EXACT_ADDRESS;
     457             :         }
     458             :       else
     459             :         {
     460          11 :           rc = nat44_ed_alloc_i2o_addr_and_port (
     461             :             sm, sm->twice_nat_addresses, s, i2o_addr, i2o_port, i2o_fib_index,
     462             :             proto, thread_index, tsm->snat_thread_index, &s->ext_host_nat_addr,
     463             :             &s->ext_host_nat_port);
     464             :         }
     465             : 
     466          11 :       if (rc)
     467             :         {
     468           0 :           b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS];
     469           0 :           nat_ed_session_delete (sm, s, thread_index, 1);
     470           0 :           return 0;
     471             :         }
     472             : 
     473          11 :       s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
     474             : 
     475          11 :       nat_6t_flow_saddr_rewrite_set (&s->o2i, s->ext_host_nat_addr.as_u32);
     476          11 :       if (IP_PROTOCOL_ICMP == proto)
     477             :         {
     478           0 :           nat_6t_flow_icmp_id_rewrite_set (&s->o2i, s->ext_host_nat_port);
     479             :         }
     480             :       else
     481             :         {
     482          11 :           nat_6t_flow_sport_rewrite_set (&s->o2i, s->ext_host_nat_port);
     483             :         }
     484             : 
     485          11 :       nat_6t_l3_l4_csum_calc (&s->o2i);
     486             : 
     487          11 :       nat_6t_flow_daddr_rewrite_set (&s->i2o, s->ext_host_addr.as_u32);
     488          11 :       if (IP_PROTOCOL_ICMP == proto)
     489             :         {
     490           0 :           nat_6t_flow_icmp_id_rewrite_set (&s->i2o, s->ext_host_port);
     491             :         }
     492             :       else
     493             :         {
     494          11 :           nat_6t_flow_dport_rewrite_set (&s->i2o, s->ext_host_port);
     495             :         }
     496             : 
     497          11 :       nat_6t_flow_saddr_rewrite_set (&s->i2o, o2i_addr.as_u32);
     498          11 :       if (IP_PROTOCOL_ICMP == proto)
     499             :         {
     500           0 :           nat_6t_flow_icmp_id_rewrite_set (&s->i2o, o2i_port);
     501             :         }
     502             :       else
     503             :         {
     504          11 :           nat_6t_flow_sport_rewrite_set (&s->i2o, o2i_port);
     505             :         }
     506          11 :       nat_6t_l3_l4_csum_calc (&s->i2o);
     507             :     }
     508             :   else
     509             :     {
     510         287 :       if (IP_PROTOCOL_ICMP == proto)
     511             :         {
     512          10 :           nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port,
     513             :                                 s->ext_host_addr, i2o_port, i2o_fib_index,
     514          10 :                                 ip->protocol);
     515             :         }
     516             :       else
     517             :         {
     518         277 :           nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port,
     519         277 :                                 s->ext_host_addr, s->ext_host_port,
     520         277 :                                 i2o_fib_index, ip->protocol);
     521             :         }
     522             : 
     523         287 :   nat_6t_flow_saddr_rewrite_set (&s->i2o, o2i_addr.as_u32);
     524         287 :   if (IP_PROTOCOL_ICMP == proto)
     525             :     {
     526          10 :       nat_6t_flow_icmp_id_rewrite_set (&s->i2o, o2i_port);
     527             :     }
     528             :   else
     529             :     {
     530         277 :       nat_6t_flow_sport_rewrite_set (&s->i2o, o2i_port);
     531             :     }
     532             : 
     533         287 :   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     534             :     {
     535           0 :       nat_elog_notice (sm, "in2out flow hash add failed");
     536           0 :       if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
     537             :         {
     538           0 :           nat_elog_warn (sm, "out2in flow hash del failed");
     539             :         }
     540           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
     541           0 :       return 0;
     542             :     }
     543             :     }
     544         299 :   nat_ipfix_logging_nat44_ses_create (
     545         299 :     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
     546         299 :     s->in2out.port, s->out2in.port, s->in2out.fib_index);
     547             : 
     548         299 :   nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
     549         299 :                          s->in2out.port, &s->ext_host_nat_addr,
     550         299 :                          s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
     551         299 :                          &s->ext_host_addr, s->ext_host_port, s->proto,
     552         299 :                          nat44_ed_is_twice_nat_session (s));
     553             : 
     554         298 :   per_vrf_sessions_register_session (s, thread_index);
     555             : 
     556         298 :   return s;
     557             : }
     558             : 
     559             : static void
     560          54 : create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s,
     561             :                        ip4_header_t *ip, u32 rx_fib_index, u32 thread_index)
     562             : {
     563             :   clib_bihash_kv_16_8_t kv, value;
     564          54 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     565          54 :   vlib_main_t *vm = vlib_get_main ();
     566          54 :   f64 now = vlib_time_now (vm);
     567             :   u16 lookup_sport, lookup_dport;
     568             :   u8 lookup_protocol;
     569             :   ip4_address_t lookup_saddr, lookup_daddr;
     570             : 
     571          54 :   if (ip->protocol == IP_PROTOCOL_ICMP)
     572             :     {
     573           8 :       if (nat_get_icmp_session_lookup_values (b, ip, &lookup_daddr,
     574             :                                               &lookup_sport, &lookup_saddr,
     575             :                                               &lookup_dport, &lookup_protocol))
     576           0 :         return;
     577             :     }
     578             :   else
     579             :     {
     580          46 :       if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
     581             :         {
     582          46 :           lookup_sport = vnet_buffer (b)->ip.reass.l4_dst_port;
     583          46 :           lookup_dport = vnet_buffer (b)->ip.reass.l4_src_port;
     584             :         }
     585             :       else
     586             :         {
     587           0 :           lookup_sport = 0;
     588           0 :           lookup_dport = 0;
     589             :         }
     590          46 :       lookup_saddr.as_u32 = ip->dst_address.as_u32;
     591          46 :       lookup_daddr.as_u32 = ip->src_address.as_u32;
     592          46 :       lookup_protocol = ip->protocol;
     593             :     }
     594             : 
     595          54 :   init_ed_k (&kv, lookup_saddr.as_u32, lookup_sport, lookup_daddr.as_u32,
     596             :              lookup_dport, rx_fib_index, lookup_protocol);
     597             : 
     598          54 :   if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
     599             :     {
     600          20 :       ASSERT (thread_index == ed_value_get_thread_index (&value));
     601          20 :       s =
     602          20 :         pool_elt_at_index (tsm->sessions,
     603             :                            ed_value_get_session_index (&value));
     604             :     }
     605          42 :   else if (ip->protocol == IP_PROTOCOL_ICMP &&
     606           8 :            icmp_type_is_error_message
     607           8 :            (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
     608             :     {
     609           0 :       return;
     610             :     }
     611             :   else
     612             :     {
     613          34 :       if (PREDICT_FALSE
     614             :           (nat44_ed_maximum_sessions_exceeded
     615             :            (sm, rx_fib_index, thread_index)))
     616           0 :         return;
     617             : 
     618          34 :       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
     619          34 :       if (!s)
     620             :         {
     621           0 :           nat_elog_warn (sm, "create NAT session failed");
     622           0 :           return;
     623             :         }
     624             : 
     625          34 :       s->ext_host_addr = ip->src_address;
     626          34 :       s->ext_host_port = lookup_dport;
     627          34 :       s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
     628          34 :       s->out2in.addr = ip->dst_address;
     629          34 :       s->out2in.port = lookup_sport;
     630          34 :       s->proto = ip->protocol;
     631          34 :       s->out2in.fib_index = rx_fib_index;
     632          34 :       s->in2out.addr = s->out2in.addr;
     633          34 :       s->in2out.port = s->out2in.port;
     634          34 :       s->in2out.fib_index = s->out2in.fib_index;
     635             : 
     636          34 :       nat_6t_i2o_flow_init (sm, thread_index, s, ip->dst_address, lookup_sport,
     637             :                             ip->src_address, lookup_dport, rx_fib_index,
     638          34 :                             ip->protocol);
     639          34 :       nat_6t_flow_txfib_rewrite_set (&s->i2o, rx_fib_index);
     640          34 :       if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     641             :         {
     642           0 :           nat_elog_notice (sm, "in2out flow add failed");
     643           0 :           nat_ed_session_delete (sm, s, thread_index, 1);
     644           0 :           return;
     645             :         }
     646             : 
     647          34 :       per_vrf_sessions_register_session (s, thread_index);
     648             :     }
     649             : 
     650          54 :   if (ip->protocol == IP_PROTOCOL_TCP)
     651             :     {
     652          37 :       nat44_set_tcp_session_state_o2i (
     653          37 :         sm, now, s, vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags,
     654             :         thread_index);
     655             :     }
     656             : 
     657             :   /* Accounting */
     658          54 :   nat44_session_update_counters (s, now, 0, thread_index);
     659             :   /* Per-user LRU list maintenance */
     660          54 :   nat44_session_update_lru (sm, s, thread_index);
     661             : }
     662             : 
     663             : static snat_session_t *
     664           0 : nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
     665             :                                         ip4_header_t *ip, u32 rx_fib_index,
     666             :                                         u32 thread_index, f64 now,
     667             :                                         vlib_main_t *vm,
     668             :                                         vlib_node_runtime_t *node)
     669             : {
     670             :   snat_static_mapping_t *m;
     671             :   snat_session_t *s;
     672             : 
     673           0 :   if (PREDICT_FALSE (
     674             :         nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
     675             :     {
     676           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     677           0 :       nat_elog_notice (sm, "maximum sessions exceeded");
     678           0 :       return 0;
     679             :     }
     680             : 
     681           0 :   m = nat44_ed_sm_o2i_lookup (sm, ip->dst_address, 0, 0, ip->protocol);
     682           0 :   if (!m)
     683             :     {
     684           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
     685           0 :       return 0;
     686             :     }
     687             : 
     688             :   /* Create a new session */
     689           0 :   s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
     690           0 :   if (!s)
     691             :     {
     692           0 :       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
     693           0 :       nat_elog_warn (sm, "create NAT session failed");
     694           0 :       return 0;
     695             :     }
     696             : 
     697           0 :   s->ext_host_addr.as_u32 = ip->src_address.as_u32;
     698           0 :   s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
     699           0 :   s->out2in.addr.as_u32 = ip->dst_address.as_u32;
     700           0 :   s->out2in.fib_index = rx_fib_index;
     701           0 :   s->in2out.addr.as_u32 = m->local_addr.as_u32;
     702           0 :   s->in2out.fib_index = m->fib_index;
     703           0 :   s->in2out.port = s->out2in.port = ip->protocol;
     704             : 
     705           0 :   nat_6t_o2i_flow_init (sm, thread_index, s, ip->dst_address, 0,
     706           0 :                         ip->src_address, 0, m->fib_index, ip->protocol);
     707           0 :   nat_6t_flow_saddr_rewrite_set (&s->i2o, ip->dst_address.as_u32);
     708           0 :   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     709             :     {
     710           0 :       nat_elog_notice (sm, "in2out key add failed");
     711           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
     712           0 :       return NULL;
     713             :     }
     714             : 
     715           0 :   nat_6t_o2i_flow_init (sm, thread_index, s, ip->src_address, 0,
     716           0 :                         ip->dst_address, 0, rx_fib_index, ip->protocol);
     717           0 :   nat_6t_flow_daddr_rewrite_set (&s->o2i, m->local_addr.as_u32);
     718           0 :   nat_6t_flow_txfib_rewrite_set (&s->o2i, m->fib_index);
     719           0 :   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
     720             :     {
     721           0 :       nat_elog_notice (sm, "out2in flow hash add failed");
     722           0 :       nat_ed_session_delete (sm, s, thread_index, 1);
     723           0 :       return NULL;
     724             :     }
     725             : 
     726           0 :   per_vrf_sessions_register_session (s, thread_index);
     727             : 
     728             :   /* Accounting */
     729           0 :   nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
     730             :                                  thread_index);
     731             :   /* Per-user LRU list maintenance */
     732           0 :   nat44_session_update_lru (sm, s, thread_index);
     733             : 
     734           0 :   return s;
     735             : }
     736             : 
     737             : static inline uword
     738         173 : nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
     739             :                                           vlib_node_runtime_t * node,
     740             :                                           vlib_frame_t * frame,
     741             :                                           int is_multi_worker)
     742             : {
     743             :   u32 n_left_from, *from;
     744         173 :   snat_main_t *sm = &snat_main;
     745         173 :   f64 now = vlib_time_now (vm);
     746         173 :   u32 thread_index = vm->thread_index;
     747         173 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     748             : 
     749         173 :   from = vlib_frame_vector_args (frame);
     750         173 :   n_left_from = frame->n_vectors;
     751             : 
     752         173 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     753         173 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
     754         173 :   vlib_get_buffers (vm, from, b, n_left_from);
     755             : 
     756        5358 :   while (n_left_from > 0)
     757             :     {
     758             :       vlib_buffer_t *b0;
     759             :       u32 sw_if_index0, rx_fib_index0;
     760             :       ip_protocol_t proto0;
     761             :       ip4_header_t *ip0;
     762        5184 :       snat_session_t *s0 = 0;
     763        5184 :       clib_bihash_kv_16_8_t kv0 = {}, value0;
     764        5184 :       nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
     765        5184 :       nat_slow_path_reason_e slow_path_reason = NAT_ED_SP_REASON_NO_REASON;
     766        5184 :       nat_6t_flow_t *f = 0;
     767             :       nat_6t_t lookup;
     768        5184 :       int lookup_skipped = 0;
     769             : 
     770        5184 :       b0 = *b;
     771        5184 :       b++;
     772             : 
     773             :       /* Prefetch next iteration. */
     774        5184 :       if (PREDICT_TRUE (n_left_from >= 2))
     775             :         {
     776             :           vlib_buffer_t *p2;
     777             : 
     778        5010 :           p2 = *b;
     779             : 
     780        5010 :           vlib_prefetch_buffer_header (p2, LOAD);
     781             : 
     782        5010 :           clib_prefetch_load (p2->data);
     783             :         }
     784             : 
     785        5183 :       next[0] = vnet_buffer2 (b0)->nat.arc_next;
     786             : 
     787        5183 :       lookup.sport = vnet_buffer (b0)->ip.reass.l4_src_port;
     788        5183 :       lookup.dport = vnet_buffer (b0)->ip.reass.l4_dst_port;
     789             : 
     790        5183 :       vnet_buffer (b0)->snat.flags = 0;
     791        5183 :       ip0 = vlib_buffer_get_current (b0);
     792             : 
     793        5183 :       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     794             :       rx_fib_index0 =
     795        5183 :         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0);
     796             : 
     797        5186 :       lookup.fib_index = rx_fib_index0;
     798             : 
     799        5186 :       if (PREDICT_FALSE (ip0->ttl == 1))
     800             :         {
     801           8 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
     802           8 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
     803             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     804             :                                        0);
     805           8 :           next[0] = NAT_NEXT_ICMP_ERROR;
     806           8 :           goto trace0;
     807             :         }
     808             : 
     809        5178 :       proto0 = ip0->protocol;
     810             : 
     811        5178 :       if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP))
     812             :         {
     813        1601 :           if (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     814        1585 :                 ICMP4_echo_request &&
     815        1585 :               vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     816           8 :                 ICMP4_echo_reply &&
     817           8 :               !icmp_type_is_error_message (
     818           8 :                 vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
     819             :             {
     820           0 :               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
     821           0 :               next[0] = NAT_NEXT_DROP;
     822           0 :               goto trace0;
     823             :             }
     824        1601 :           int err = nat_get_icmp_session_lookup_values (
     825             :             b0, ip0, &lookup.saddr, &lookup.sport, &lookup.daddr,
     826             :             &lookup.dport, &lookup.proto);
     827        1601 :           if (err != 0)
     828             :             {
     829           0 :               b0->error = node->errors[err];
     830           0 :               next[0] = NAT_NEXT_DROP;
     831           0 :               goto trace0;
     832             :             }
     833             :         }
     834             :       else
     835             :         {
     836        3577 :           lookup.saddr.as_u32 = ip0->src_address.as_u32;
     837        3577 :           lookup.daddr.as_u32 = ip0->dst_address.as_u32;
     838        3577 :           lookup.proto = ip0->protocol;
     839             :         }
     840             : 
     841             :       /* there might be a stashed index in vnet_buffer2 from handoff or
     842             :        * classify node, see if it can be used */
     843       10196 :       if (is_multi_worker &&
     844        5019 :           !pool_is_free_index (tsm->sessions,
     845        5019 :                                vnet_buffer2 (b0)->nat.cached_session_index))
     846             :         {
     847        4790 :           s0 = pool_elt_at_index (tsm->sessions,
     848             :                                   vnet_buffer2 (b0)->nat.cached_session_index);
     849        4789 :           if (PREDICT_TRUE (nat_6t_t_eq (&s0->o2i.match, &lookup)) ||
     850        1603 :               (s0->flags & SNAT_SESSION_FLAG_TWICE_NAT &&
     851           1 :                nat_6t_t_eq (&s0->i2o.match, &lookup)))
     852             :             {
     853             :               /* yes, this is the droid we're looking for */
     854        3192 :               lookup_skipped = 1;
     855        3192 :               goto skip_lookup;
     856             :             }
     857        1597 :           s0 = NULL;
     858             :         }
     859             : 
     860        1984 :       init_ed_k (&kv0, lookup.saddr.as_u32, lookup.sport, lookup.daddr.as_u32,
     861        1984 :                  lookup.dport, lookup.fib_index, lookup.proto);
     862             : 
     863             :       // lookup flow
     864        1988 :       if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
     865             :         {
     866             :           // flow does not exist go slow path
     867         396 :           slow_path_reason = NAT_ED_SP_REASON_LOOKUP_FAILED;
     868         396 :           next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
     869         396 :           goto trace0;
     870             :         }
     871        1592 :       ASSERT (thread_index == ed_value_get_thread_index (&value0));
     872        1592 :       s0 =
     873        1592 :         pool_elt_at_index (tsm->sessions,
     874             :                            ed_value_get_session_index (&value0));
     875        4784 :     skip_lookup:
     876             : 
     877        4784 :       ASSERT (thread_index == s0->thread_index);
     878             : 
     879        4784 :       if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
     880             :         {
     881             :           // session is closed, go slow path
     882           0 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
     883           0 :           nat_ed_session_delete (sm, s0, thread_index, 1);
     884           0 :           s0 = 0;
     885           0 :           slow_path_reason = NAT_ED_SP_REASON_VRF_EXPIRED;
     886           0 :           next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
     887           0 :           goto trace0;
     888             :         }
     889             : 
     890             :       // drop if session expired
     891             :       u64 sess_timeout_time;
     892        4780 :       sess_timeout_time =
     893        4780 :         s0->last_heard + (f64) nat44_session_get_timeout (sm, s0);
     894        4780 :       if (now >= sess_timeout_time)
     895             :         {
     896             :           // session is closed, go slow path
     897           2 :           nat44_ed_free_session_data (sm, s0, thread_index, 0);
     898           2 :           nat_ed_session_delete (sm, s0, thread_index, 1);
     899           2 :           s0 = 0;
     900           2 :           slow_path_reason = NAT_ED_SP_SESS_EXPIRED;
     901           2 :           next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
     902           2 :           goto trace0;
     903             :         }
     904             : 
     905        4778 :       if (nat_6t_t_eq (&s0->o2i.match, &lookup))
     906             :         {
     907        4768 :           f = &s0->o2i;
     908             :         }
     909          11 :       else if (s0->flags & SNAT_SESSION_FLAG_TWICE_NAT &&
     910           1 :                nat_6t_t_eq (&s0->i2o.match, &lookup))
     911             :         {
     912           1 :           f = &s0->i2o;
     913             :         }
     914             :       else
     915             :         {
     916             :           /*
     917             :            * Send DHCP packets to the ipv4 stack, or we won't
     918             :            * be able to use dhcp client on the outside interface
     919             :            */
     920           9 :           if (PREDICT_FALSE (
     921             :                 proto0 == IP_PROTOCOL_UDP &&
     922             :                 (vnet_buffer (b0)->ip.reass.l4_dst_port ==
     923             :                  clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
     924             :             {
     925           0 :               goto trace0;
     926             :             }
     927             : 
     928           9 :           if (!sm->forwarding_enabled)
     929             :             {
     930           0 :               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
     931           0 :               next[0] = NAT_NEXT_DROP;
     932           0 :               goto trace0;
     933             :             }
     934             :           else
     935             :             {
     936           9 :               if (nat_6t_t_eq (&s0->i2o.match, &lookup))
     937             :                 {
     938           9 :                   f = &s0->i2o;
     939             :                 }
     940             :               else
     941             :                 {
     942             :                   // FIXME TODO bypass ???
     943             :                   //  create_bypass_for_fwd (sm, b0, s0, ip0, rx_fib_index0,
     944             :                   //                       thread_index);
     945           0 :                   translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH;
     946           0 :                   nat44_ed_free_session_data (sm, s0, thread_index, 0);
     947           0 :                   nat_ed_session_delete (sm, s0, thread_index, 1);
     948           0 :                   s0 = 0;
     949           0 :                   next[0] = NAT_NEXT_DROP;
     950           0 :                   b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
     951           0 :                   goto trace0;
     952             :                 }
     953             :             }
     954             :         }
     955             : 
     956        4779 :       if (NAT_ED_TRNSL_ERR_SUCCESS !=
     957        4778 :           (translation_error = nat_6t_flow_buf_translate_o2i (
     958             :              vm, sm, b0, ip0, f, proto0, 0 /* is_output_feature */)))
     959             :         {
     960           0 :           next[0] = NAT_NEXT_DROP;
     961           0 :           b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
     962           0 :           goto trace0;
     963             :         }
     964             : 
     965        4779 :       switch (proto0)
     966             :         {
     967        1648 :         case IP_PROTOCOL_TCP:
     968        1648 :           vlib_increment_simple_counter (&sm->counters.fastpath.out2in.tcp,
     969             :                                          thread_index, sw_if_index0, 1);
     970        1648 :           nat44_set_tcp_session_state_o2i (sm, now, s0,
     971        1648 :                                            vnet_buffer (b0)->ip.
     972        1648 :                                            reass.icmp_type_or_tcp_flags,
     973             :                                            thread_index);
     974        1648 :           break;
     975        1562 :         case IP_PROTOCOL_UDP:
     976        1562 :           vlib_increment_simple_counter (&sm->counters.fastpath.out2in.udp,
     977             :                                          thread_index, sw_if_index0, 1);
     978        1562 :           break;
     979        1572 :         case IP_PROTOCOL_ICMP:
     980        1572 :           vlib_increment_simple_counter (&sm->counters.fastpath.out2in.icmp,
     981             :                                          thread_index, sw_if_index0, 1);
     982        1572 :           break;
     983           0 :         default:
     984           0 :           vlib_increment_simple_counter (&sm->counters.fastpath.out2in.other,
     985             :                                          thread_index, sw_if_index0, 1);
     986           1 :           break;
     987             :         }
     988             : 
     989             :       /* Accounting */
     990        4783 :       nat44_session_update_counters (s0, now,
     991             :                                      vlib_buffer_length_in_chain (vm, b0),
     992             :                                      thread_index);
     993             :       /* Per-user LRU list maintenance */
     994        4778 :       nat44_session_update_lru (sm, s0, thread_index);
     995             : 
     996        5182 :     trace0:
     997        5182 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     998             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     999             :         {
    1000             :           nat44_ed_out2in_trace_t *t =
    1001        4682 :             vlib_add_trace (vm, node, b0, sizeof (*t));
    1002        4683 :           t->sw_if_index = sw_if_index0;
    1003        4683 :           t->next_index = next[0];
    1004        4683 :           t->is_slow_path = 0;
    1005        4683 :           t->translation_error = translation_error;
    1006        4683 :           clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
    1007        4686 :           t->lookup_skipped = lookup_skipped;
    1008        4686 :           t->slow_path_reason = slow_path_reason;
    1009             : 
    1010        4686 :           if (s0)
    1011             :             {
    1012        4282 :               t->session_index = s0 - tsm->sessions;
    1013        4282 :               clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
    1014        4282 :               clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
    1015        4282 :               t->translation_via_i2of = (&s0->i2o == f);
    1016        4282 :               t->tcp_state = s0->tcp_state;
    1017             :             }
    1018             :           else
    1019             :             {
    1020         404 :               t->session_index = ~0;
    1021             :             }
    1022             :         }
    1023             : 
    1024        5186 :       if (next[0] == NAT_NEXT_DROP)
    1025             :         {
    1026           0 :           vlib_increment_simple_counter (&sm->counters.fastpath.out2in.drops,
    1027             :                                          thread_index, sw_if_index0, 1);
    1028             :         }
    1029             : 
    1030        5186 :       n_left_from--;
    1031        5186 :       next++;
    1032             :     }
    1033             : 
    1034         174 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
    1035         174 :                                frame->n_vectors);
    1036         174 :   return frame->n_vectors;
    1037             : }
    1038             : 
    1039             : static inline uword
    1040          74 : nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
    1041             :                                           vlib_node_runtime_t * node,
    1042             :                                           vlib_frame_t * frame)
    1043             : {
    1044             :   u32 n_left_from, *from;
    1045          74 :   snat_main_t *sm = &snat_main;
    1046          74 :   f64 now = vlib_time_now (vm);
    1047          74 :   u32 thread_index = vm->thread_index;
    1048          74 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
    1049             :   snat_static_mapping_t *m;
    1050             : 
    1051          74 :   from = vlib_frame_vector_args (frame);
    1052          74 :   n_left_from = frame->n_vectors;
    1053             : 
    1054          74 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
    1055          74 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
    1056          74 :   vlib_get_buffers (vm, from, b, n_left_from);
    1057             : 
    1058         474 :   while (n_left_from > 0)
    1059             :     {
    1060             :       vlib_buffer_t *b0;
    1061             :       u32 sw_if_index0, rx_fib_index0;
    1062             :       ip_protocol_t proto0;
    1063             :       ip4_header_t *ip0;
    1064             :       udp_header_t *udp0;
    1065             :       icmp46_header_t *icmp0;
    1066         400 :       snat_session_t *s0 = 0;
    1067         400 :       clib_bihash_kv_16_8_t kv0 = {}, value0;
    1068             :       lb_nat_type_t lb_nat0;
    1069             :       twice_nat_type_t twice_nat0;
    1070             :       u8 identity_nat0;
    1071             :       ip4_address_t sm_addr;
    1072             :       u16 sm_port;
    1073             :       u32 sm_fib_index;
    1074         400 :       nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
    1075             : 
    1076         400 :       b0 = *b;
    1077         400 :       next[0] = vnet_buffer2 (b0)->nat.arc_next;
    1078             : 
    1079         400 :       vnet_buffer (b0)->snat.flags = 0;
    1080         400 :       ip0 = vlib_buffer_get_current (b0);
    1081             : 
    1082         400 :       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1083             :       rx_fib_index0 =
    1084         400 :         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0);
    1085             : 
    1086         400 :       if (PREDICT_FALSE (ip0->ttl == 1))
    1087             :         {
    1088           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1089           0 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
    1090             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
    1091             :                                        0);
    1092           0 :           next[0] = NAT_NEXT_ICMP_ERROR;
    1093           0 :           goto trace0;
    1094             :         }
    1095             : 
    1096         400 :       udp0 = ip4_next_header (ip0);
    1097         400 :       icmp0 = (icmp46_header_t *) udp0;
    1098         400 :       proto0 = ip0->protocol;
    1099             : 
    1100         400 :       if (PREDICT_FALSE (nat44_ed_is_unk_proto (proto0)))
    1101             :         {
    1102           0 :           s0 = nat44_ed_out2in_slowpath_unknown_proto (
    1103             :             sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node);
    1104           0 :           if (!sm->forwarding_enabled)
    1105             :             {
    1106           0 :               if (!s0)
    1107           0 :                 next[0] = NAT_NEXT_DROP;
    1108             :             }
    1109           0 :           if (NAT_NEXT_DROP != next[0] && s0 &&
    1110             :               NAT_ED_TRNSL_ERR_SUCCESS !=
    1111           0 :                 (translation_error = nat_6t_flow_buf_translate_o2i (
    1112           0 :                    vm, sm, b0, ip0, &s0->o2i, proto0,
    1113             :                    0 /* is_output_feature */)))
    1114             :             {
    1115           0 :               next[0] = NAT_NEXT_DROP;
    1116           0 :               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
    1117           0 :               goto trace0;
    1118             :             }
    1119             : 
    1120           0 :           vlib_increment_simple_counter (&sm->counters.slowpath.out2in.other,
    1121             :                                          thread_index, sw_if_index0, 1);
    1122           0 :           goto trace0;
    1123             :         }
    1124             : 
    1125         400 :       if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP))
    1126             :         {
    1127          58 :           next[0] = icmp_out2in_ed_slow_path
    1128             :             (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
    1129          29 :              next[0], now, thread_index, &s0);
    1130             : 
    1131          39 :           if (NAT_NEXT_DROP != next[0] && s0 &&
    1132             :               NAT_ED_TRNSL_ERR_SUCCESS !=
    1133          10 :                 (translation_error = nat_6t_flow_buf_translate_o2i (
    1134          10 :                    vm, sm, b0, ip0, &s0->o2i, proto0,
    1135             :                    0 /* is_output_feature */)))
    1136             :             {
    1137           0 :               next[0] = NAT_NEXT_DROP;
    1138           0 :               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
    1139           0 :               goto trace0;
    1140             :             }
    1141             : 
    1142          29 :           if (NAT_NEXT_DROP != next[0])
    1143             :             {
    1144          18 :               vlib_increment_simple_counter (
    1145             :                 &sm->counters.slowpath.out2in.icmp, thread_index, sw_if_index0,
    1146             :                 1);
    1147             :             }
    1148          29 :           goto trace0;
    1149             :         }
    1150             : 
    1151         371 :       init_ed_k (
    1152         371 :         &kv0, ip0->src_address.as_u32, vnet_buffer (b0)->ip.reass.l4_src_port,
    1153         371 :         ip0->dst_address.as_u32, vnet_buffer (b0)->ip.reass.l4_dst_port,
    1154         371 :         rx_fib_index0, ip0->protocol);
    1155             : 
    1156         371 :       s0 = NULL;
    1157         371 :       if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
    1158             :         {
    1159          12 :           ASSERT (thread_index == ed_value_get_thread_index (&value0));
    1160          12 :           s0 =
    1161          12 :             pool_elt_at_index (tsm->sessions,
    1162             :                                ed_value_get_session_index (&value0));
    1163             :         }
    1164             : 
    1165         372 :       if (!s0)
    1166             :         {
    1167             :           /* Try to match static mapping by external address and port,
    1168             :              destination address and port in packet */
    1169             : 
    1170         360 :           if (snat_static_mapping_match (
    1171         360 :                 vm, ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
    1172             :                 rx_fib_index0, proto0, &sm_addr, &sm_port, &sm_fib_index, 1, 0,
    1173             :                 &twice_nat0, &lb_nat0, &ip0->src_address, &identity_nat0, &m))
    1174             :             {
    1175             :               /*
    1176             :                * Send DHCP packets to the ipv4 stack, or we won't
    1177             :                * be able to use dhcp client on the outside interface
    1178             :                */
    1179          70 :               if (PREDICT_FALSE (
    1180             :                     proto0 == IP_PROTOCOL_UDP &&
    1181             :                     (vnet_buffer (b0)->ip.reass.l4_dst_port ==
    1182             :                      clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
    1183             :                 {
    1184           0 :                   goto trace0;
    1185             :                 }
    1186             : 
    1187          70 :               if (!sm->forwarding_enabled)
    1188             :                 {
    1189          24 :                   b0->error =
    1190          24 :                     node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
    1191          24 :                   next[0] = NAT_NEXT_DROP;
    1192             :                 }
    1193             :               else
    1194             :                 {
    1195          46 :                   if (next_src_nat (
    1196          46 :                         sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
    1197          46 :                         vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0))
    1198             :                     {
    1199           0 :                       next[0] = NAT_NEXT_IN2OUT_ED_FAST_PATH;
    1200             :                     }
    1201             :                   else
    1202             :                     {
    1203          46 :                       create_bypass_for_fwd (sm, b0, s0, ip0, rx_fib_index0,
    1204             :                                              thread_index);
    1205             :                     }
    1206             :                 }
    1207          70 :               goto trace0;
    1208             :             }
    1209             : 
    1210         290 :           if (PREDICT_FALSE (identity_nat0))
    1211           0 :             goto trace0;
    1212             : 
    1213         290 :           if ((proto0 == IP_PROTOCOL_TCP) &&
    1214         284 :               !tcp_flags_is_init (
    1215         284 :                 vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
    1216             :             {
    1217           1 :               b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN];
    1218           1 :               next[0] = NAT_NEXT_DROP;
    1219           1 :               goto trace0;
    1220             :             }
    1221             : 
    1222             :           /* Create session initiated by host from external network */
    1223         577 :           s0 = create_session_for_static_mapping_ed (
    1224             :             sm, b0, sm_addr, sm_port, sm_fib_index, ip0->dst_address,
    1225         289 :             vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
    1226             :             node, thread_index, twice_nat0, lb_nat0, now, m);
    1227         288 :           if (!s0)
    1228             :             {
    1229           0 :               next[0] = NAT_NEXT_DROP;
    1230           0 :               goto trace0;
    1231             :             }
    1232             :         }
    1233             : 
    1234         300 :       if (NAT_ED_TRNSL_ERR_SUCCESS !=
    1235         300 :           (translation_error = nat_6t_flow_buf_translate_o2i (
    1236         300 :              vm, sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
    1237             :         {
    1238           0 :           next[0] = NAT_NEXT_DROP;
    1239           0 :           goto trace0;
    1240             :         }
    1241             : 
    1242         300 :       if (PREDICT_TRUE (proto0 == IP_PROTOCOL_TCP))
    1243             :         {
    1244         290 :           vlib_increment_simple_counter (&sm->counters.slowpath.out2in.tcp,
    1245             :                                          thread_index, sw_if_index0, 1);
    1246         290 :           nat44_set_tcp_session_state_o2i (sm, now, s0,
    1247         290 :                                            vnet_buffer (b0)->ip.
    1248         290 :                                            reass.icmp_type_or_tcp_flags,
    1249             :                                            thread_index);
    1250             :         }
    1251             :       else
    1252             :         {
    1253          10 :           vlib_increment_simple_counter (&sm->counters.slowpath.out2in.udp,
    1254             :                                          thread_index, sw_if_index0, 1);
    1255             :         }
    1256             : 
    1257             :       /* Accounting */
    1258         300 :       nat44_session_update_counters (s0, now,
    1259             :                                      vlib_buffer_length_in_chain (vm, b0),
    1260             :                                      thread_index);
    1261             :       /* Per-user LRU list maintenance */
    1262         300 :       nat44_session_update_lru (sm, s0, thread_index);
    1263             : 
    1264         400 :     trace0:
    1265         400 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
    1266             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
    1267             :         {
    1268             :           nat44_ed_out2in_trace_t *t =
    1269         400 :             vlib_add_trace (vm, node, b0, sizeof (*t));
    1270         401 :           t->sw_if_index = sw_if_index0;
    1271         401 :           t->next_index = next[0];
    1272         401 :           t->is_slow_path = 1;
    1273         401 :           t->translation_error = translation_error;
    1274         401 :           clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
    1275             : 
    1276         400 :           if (s0)
    1277             :             {
    1278         310 :               t->session_index = s0 - tsm->sessions;
    1279         310 :               clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
    1280         310 :               clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
    1281         310 :               t->tcp_state = s0->tcp_state;
    1282             :             }
    1283             :           else
    1284             :             {
    1285          90 :               t->session_index = ~0;
    1286             :             }
    1287             :         }
    1288             : 
    1289         400 :       if (next[0] == NAT_NEXT_DROP)
    1290             :         {
    1291          36 :           vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
    1292             :                                          thread_index, sw_if_index0, 1);
    1293             :         }
    1294             : 
    1295         400 :       n_left_from--;
    1296         400 :       next++;
    1297         400 :       b++;
    1298             :     }
    1299             : 
    1300          74 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
    1301          74 :                                frame->n_vectors);
    1302             : 
    1303          74 :   return frame->n_vectors;
    1304             : }
    1305             : 
    1306        2409 : VLIB_NODE_FN (nat44_ed_out2in_node) (vlib_main_t * vm,
    1307             :                                      vlib_node_runtime_t * node,
    1308             :                                      vlib_frame_t * frame)
    1309             : {
    1310         173 :   if (snat_main.num_workers > 1)
    1311             :     {
    1312         135 :       return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame, 1);
    1313             :     }
    1314             :   else
    1315             :     {
    1316          38 :       return nat44_ed_out2in_fast_path_node_fn_inline (vm, node, frame, 0);
    1317             :     }
    1318             : }
    1319             : 
    1320       49304 : VLIB_REGISTER_NODE (nat44_ed_out2in_node) = {
    1321             :   .name = "nat44-ed-out2in",
    1322             :   .vector_size = sizeof (u32),
    1323             :   .sibling_of = "nat-default",
    1324             :   .format_trace = format_nat44_ed_out2in_trace,
    1325             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1326             :   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
    1327             :   .error_strings = nat_out2in_ed_error_strings,
    1328             :   .runtime_data_bytes = sizeof (snat_runtime_t),
    1329             : };
    1330             : 
    1331        2310 : VLIB_NODE_FN (nat44_ed_out2in_slowpath_node) (vlib_main_t * vm,
    1332             :                                               vlib_node_runtime_t * node,
    1333             :                                               vlib_frame_t * frame)
    1334             : {
    1335          74 :   return nat44_ed_out2in_slow_path_node_fn_inline (vm, node, frame);
    1336             : }
    1337             : 
    1338       49304 : VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
    1339             :   .name = "nat44-ed-out2in-slowpath",
    1340             :   .vector_size = sizeof (u32),
    1341             :   .sibling_of = "nat-default",
    1342             :   .format_trace = format_nat44_ed_out2in_trace,
    1343             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1344             :   .n_errors = ARRAY_LEN(nat_out2in_ed_error_strings),
    1345             :   .error_strings = nat_out2in_ed_error_strings,
    1346             :   .runtime_data_bytes = sizeof (snat_runtime_t),
    1347             : };
    1348             : 
    1349             : static u8 *
    1350         122 : format_nat_pre_trace (u8 * s, va_list * args)
    1351             : {
    1352         122 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1353         122 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1354         122 :   nat_pre_trace_t *t = va_arg (*args, nat_pre_trace_t *);
    1355         122 :   return format (s, "out2in next_index %d arc_next_index %d", t->next_index,
    1356             :                  t->arc_next_index);
    1357             : }
    1358             : 
    1359        2271 : VLIB_NODE_FN (nat_pre_out2in_node) (vlib_main_t * vm,
    1360             :                                     vlib_node_runtime_t * node,
    1361             :                                     vlib_frame_t * frame)
    1362             : {
    1363          35 :   return nat_pre_node_fn_inline (vm, node, frame,
    1364             :                                  NAT_NEXT_OUT2IN_ED_FAST_PATH);
    1365             : }
    1366             : 
    1367       49304 : VLIB_REGISTER_NODE (nat_pre_out2in_node) = {
    1368             :   .name = "nat-pre-out2in",
    1369             :   .vector_size = sizeof (u32),
    1370             :   .sibling_of = "nat-default",
    1371             :   .format_trace = format_nat_pre_trace,
    1372             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1373             :   .n_errors = 0,
    1374             :  };
    1375             : 
    1376             : /*
    1377             :  * fd.io coding-style-patch-verification: ON
    1378             :  *
    1379             :  * Local Variables:
    1380             :  * eval: (c-set-style "gnu")
    1381             :  * End:
    1382             :  */

Generated by: LCOV version 1.14