LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ei - nat44_ei_out2in.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 443 572 77.4 %
Date: 2023-10-26 01:39:38 Functions: 15 19 78.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /**
      16             :  * @file
      17             :  * @brief NAT44 EI outside to inside network translation
      18             :  */
      19             : 
      20             : #include <vlib/vlib.h>
      21             : 
      22             : #include <vnet/vnet.h>
      23             : #include <vnet/ip/ip.h>
      24             : #include <vnet/ethernet/ethernet.h>
      25             : #include <vnet/udp/udp_local.h>
      26             : #include <vnet/fib/ip4_fib.h>
      27             : 
      28             : #include <vppinfra/hash.h>
      29             : #include <vppinfra/error.h>
      30             : 
      31             : #include <nat/lib/log.h>
      32             : #include <nat/lib/nat_syslog.h>
      33             : #include <nat/lib/ipfix_logging.h>
      34             : #include <nat/nat44-ei/nat44_ei_inlines.h>
      35             : #include <nat/nat44-ei/nat44_ei.h>
      36             : 
      37             : typedef struct
      38             : {
      39             :   u32 sw_if_index;
      40             :   u32 next_index;
      41             :   u32 session_index;
      42             : } nat44_ei_out2in_trace_t;
      43             : 
      44             : /* packet trace format function */
      45             : static u8 *
      46          55 : format_nat44_ei_out2in_trace (u8 *s, va_list *args)
      47             : {
      48          55 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      49          55 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      50          55 :   nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
      51             : 
      52             :   s =
      53          55 :     format (s,
      54             :             "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
      55             :             t->sw_if_index, t->next_index, t->session_index);
      56          55 :   return s;
      57             : }
      58             : 
      59             : #define foreach_nat44_ei_out2in_error                                         \
      60             :   _ (UNSUPPORTED_PROTOCOL, "unsupported protocol")                            \
      61             :   _ (OUT_OF_PORTS, "out of ports")                                            \
      62             :   _ (BAD_ICMP_TYPE, "unsupported ICMP type")                                  \
      63             :   _ (NO_TRANSLATION, "no translation")                                        \
      64             :   _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")                      \
      65             :   _ (CANNOT_CREATE_USER, "cannot create NAT user")
      66             : 
      67             : typedef enum
      68             : {
      69             : #define _(sym, str) NAT44_EI_OUT2IN_ERROR_##sym,
      70             :   foreach_nat44_ei_out2in_error
      71             : #undef _
      72             :     NAT44_EI_OUT2IN_N_ERROR,
      73             : } nat44_ei_out2in_error_t;
      74             : 
      75             : static char *nat44_ei_out2in_error_strings[] = {
      76             : #define _(sym,string) string,
      77             :   foreach_nat44_ei_out2in_error
      78             : #undef _
      79             : };
      80             : 
      81             : typedef enum
      82             : {
      83             :   NAT44_EI_OUT2IN_NEXT_DROP,
      84             :   NAT44_EI_OUT2IN_NEXT_LOOKUP,
      85             :   NAT44_EI_OUT2IN_NEXT_ICMP_ERROR,
      86             :   NAT44_EI_OUT2IN_N_NEXT,
      87             : } nat44_ei_out2in_next_t;
      88             : 
      89             : #ifndef CLIB_MARCH_VARIANT
      90             : int
      91          49 : nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
      92             : {
      93          49 :   nat44_ei_main_t *nm = &nat44_ei_main;
      94          49 :   nat44_ei_is_idle_session_ctx_t *ctx = arg;
      95             :   nat44_ei_session_t *s;
      96             :   u64 sess_timeout_time;
      97          49 :   nat44_ei_main_per_thread_data_t *tnm =
      98          49 :     vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
      99             :   clib_bihash_kv_8_8_t s_kv;
     100             : 
     101          49 :   if (ctx->thread_index != nat_value_get_thread_index (kv))
     102             :     {
     103           0 :       return 0;
     104             :     }
     105             : 
     106          49 :   s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (kv));
     107          98 :   sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
     108          49 :                                         &nm->timeouts, s->nat_proto, s->state);
     109          49 :   if (ctx->now >= sess_timeout_time)
     110             :     {
     111           0 :       init_nat_i2o_k (&s_kv, s);
     112           0 :       if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0))
     113           0 :         nat_elog_warn (nm, "out2in key del failed");
     114             : 
     115           0 :       nat_ipfix_logging_nat44_ses_delete (
     116             :         ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
     117           0 :         nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
     118             :         s->in2out.fib_index);
     119             : 
     120           0 :       nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
     121           0 :                                &s->in2out.addr, s->in2out.port,
     122           0 :                                &s->out2in.addr, s->out2in.port, s->nat_proto);
     123             : 
     124           0 :       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
     125           0 :                    s->ext_host_port, s->nat_proto, s->out2in.fib_index,
     126             :                    ctx->thread_index);
     127             : 
     128           0 :       if (!nat44_ei_is_session_static (s))
     129           0 :         nat44_ei_free_outside_address_and_port (
     130           0 :           nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
     131             :           s->nat_proto);
     132             : 
     133           0 :       nat44_ei_delete_session (nm, s, ctx->thread_index);
     134           0 :       return 1;
     135             :     }
     136             : 
     137          49 :   return 0;
     138             : }
     139             : #endif
     140             : 
     141             : /**
     142             :  * @brief Create session for static mapping.
     143             :  *
     144             :  * Create NAT session initiated by host from external network with static
     145             :  * mapping.
     146             :  *
     147             :  * @param nm     NAT main.
     148             :  * @param b0     Vlib buffer.
     149             :  * @param in2out In2out NAT44 session key.
     150             :  * @param out2in Out2in NAT44 session key.
     151             :  * @param node   Vlib node.
     152             :  *
     153             :  * @returns NAT44_EI session if successfully created otherwise 0.
     154             :  */
     155             : static inline nat44_ei_session_t *
     156          17 : create_session_for_static_mapping (
     157             :   nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_address_t i2o_addr, u16 i2o_port,
     158             :   u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
     159             :   nat_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, f64 now)
     160             : {
     161             :   nat44_ei_user_t *u;
     162             :   nat44_ei_session_t *s;
     163             :   clib_bihash_kv_8_8_t kv0;
     164             :   ip4_header_t *ip0;
     165             :   udp_header_t *udp0;
     166             :   nat44_ei_is_idle_session_ctx_t ctx0;
     167             : 
     168          17 :   if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
     169             :     {
     170           0 :       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
     171           0 :       nat_elog_notice (nm, "maximum sessions exceeded");
     172           0 :       return 0;
     173             :     }
     174             : 
     175          17 :   ip0 = vlib_buffer_get_current (b0);
     176          17 :   udp0 = ip4_next_header (ip0);
     177             : 
     178          17 :   u = nat44_ei_user_get_or_create (nm, &i2o_addr, i2o_fib_index, thread_index);
     179          17 :   if (!u)
     180             :     {
     181           0 :       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_CANNOT_CREATE_USER];
     182           0 :       return 0;
     183             :     }
     184             : 
     185          17 :   s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
     186          17 :   if (!s)
     187             :     {
     188           0 :       nat44_ei_delete_user_with_no_session (nm, u, thread_index);
     189           0 :       nat_elog_warn (nm, "create NAT session failed");
     190           0 :       return 0;
     191             :     }
     192             : 
     193          17 :   s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
     194          17 :   s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
     195          17 :   s->ext_host_port = udp0->src_port;
     196          17 :   nat44_ei_user_session_increment (nm, u, 1 /* static */);
     197          17 :   s->in2out.addr = i2o_addr;
     198          17 :   s->in2out.port = i2o_port;
     199          17 :   s->in2out.fib_index = i2o_fib_index;
     200          17 :   s->out2in.addr = o2i_addr;
     201          17 :   s->out2in.port = o2i_port;
     202          17 :   s->out2in.fib_index = o2i_fib_index;
     203          17 :   s->nat_proto = proto;
     204             : 
     205             :   /* Add to translation hashes */
     206          17 :   ctx0.now = now;
     207          17 :   ctx0.thread_index = thread_index;
     208          17 :   init_nat_i2o_kv (&kv0, s, thread_index,
     209          17 :                    s - nm->per_thread_data[thread_index].sessions);
     210          17 :   if (clib_bihash_add_or_overwrite_stale_8_8 (
     211             :         &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
     212           0 :     nat_elog_notice (nm, "in2out key add failed");
     213             : 
     214          17 :   init_nat_o2i_kv (&kv0, s, thread_index,
     215          17 :                    s - nm->per_thread_data[thread_index].sessions);
     216          17 :   if (clib_bihash_add_or_overwrite_stale_8_8 (
     217             :         &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
     218           0 :     nat_elog_notice (nm, "out2in key add failed");
     219             : 
     220             :   /* log NAT event */
     221          17 :   nat_ipfix_logging_nat44_ses_create (
     222             :     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
     223          17 :     nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
     224             :     s->in2out.fib_index);
     225             : 
     226          17 :   nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
     227          17 :                            &s->in2out.addr, s->in2out.port, &s->out2in.addr,
     228          17 :                            s->out2in.port, s->nat_proto);
     229             : 
     230          17 :   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
     231          17 :                s->out2in.port, &s->ext_host_addr, s->ext_host_port,
     232          17 :                &s->ext_host_nat_addr, s->ext_host_nat_port,
     233          17 :                s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
     234             : 
     235          17 :   return s;
     236             : }
     237             : 
     238             : #ifndef CLIB_MARCH_VARIANT
     239             : static_always_inline nat44_ei_out2in_error_t
     240          37 : icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
     241             :               u16 *port, nat_protocol_t *nat_proto)
     242             : {
     243             :   icmp46_header_t *icmp0;
     244          37 :   icmp_echo_header_t *echo0, *inner_echo0 = 0;
     245             :   ip4_header_t *inner_ip0;
     246          37 :   void *l4_header = 0;
     247             :   icmp46_header_t *inner_icmp0;
     248             : 
     249          37 :   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
     250          37 :   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
     251             : 
     252          37 :   if (!icmp_type_is_error_message
     253          37 :       (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
     254             :     {
     255          33 :       *nat_proto = NAT_PROTOCOL_ICMP;
     256          33 :       *addr = ip0->dst_address;
     257          33 :       *port = vnet_buffer (b)->ip.reass.l4_src_port;
     258             :     }
     259             :   else
     260             :     {
     261           4 :       inner_ip0 = (ip4_header_t *) (echo0 + 1);
     262           4 :       l4_header = ip4_next_header (inner_ip0);
     263           4 :       *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
     264           4 :       *addr = inner_ip0->src_address;
     265           4 :       switch (*nat_proto)
     266             :         {
     267           1 :         case NAT_PROTOCOL_ICMP:
     268           1 :           inner_icmp0 = (icmp46_header_t *) l4_header;
     269           1 :           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
     270           1 :           *port = inner_echo0->identifier;
     271           1 :           break;
     272           3 :         case NAT_PROTOCOL_UDP:
     273             :         case NAT_PROTOCOL_TCP:
     274           3 :           *port = ((tcp_udp_header_t *) l4_header)->src_port;
     275           3 :           break;
     276           0 :         default:
     277           0 :           return NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
     278             :         }
     279             :     }
     280          37 :   return -1;                    /* success */
     281             : }
     282             : 
     283             : /**
     284             :  * Get address and port values to be used for ICMP packet translation
     285             :  * and create session if needed
     286             :  *
     287             :  * @param[in,out] nm             NAT main
     288             :  * @param[in,out] node           NAT node runtime
     289             :  * @param[in] thread_index       thread index
     290             :  * @param[in,out] b0             buffer containing packet to be translated
     291             :  * @param[in,out] ip0            ip header
     292             :  * @param[out] p_proto           protocol used for matching
     293             :  * @param[out] p_value           address and port after NAT translation
     294             :  * @param[out] p_dont_translate  if packet should not be translated
     295             :  * @param d                      optional parameter
     296             :  * @param e                      optional parameter
     297             :  */
     298             : u32
     299          37 : nat44_ei_icmp_match_out2in_slow (vlib_node_runtime_t *node, u32 thread_index,
     300             :                                  vlib_buffer_t *b0, ip4_header_t *ip0,
     301             :                                  ip4_address_t *addr, u16 *port,
     302             :                                  u32 *fib_index, nat_protocol_t *proto,
     303             :                                  nat44_ei_session_t **p_s0, u8 *dont_translate)
     304             : {
     305          37 :   nat44_ei_main_t *nm = &nat44_ei_main;
     306          37 :   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
     307             :   u32 sw_if_index0;
     308          37 :   nat44_ei_session_t *s0 = 0;
     309             :   clib_bihash_kv_8_8_t kv0, value0;
     310             :   u8 is_addr_only;
     311          37 :   u32 next0 = ~0;
     312             :   int err;
     313             :   u8 identity_nat;
     314          37 :   vlib_main_t *vm = vlib_get_main ();
     315          37 :   *dont_translate = 0;
     316             : 
     317          37 :   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     318          37 :   *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     319             : 
     320          37 :   *proto = 0;
     321             : 
     322          37 :   err = icmp_get_key (b0, ip0, addr, port, proto);
     323          37 :   if (err != -1)
     324             :     {
     325           0 :       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
     326           0 :       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     327           0 :       goto out;
     328             :     }
     329             : 
     330             :   ip4_address_t mapping_addr;
     331             :   u16 mapping_port;
     332             :   u32 mapping_fib_index;
     333             : 
     334          37 :   init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
     335          37 :   if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
     336             :     {
     337             :       /* Try to match static mapping by external address and port,
     338             :          destination address and port in packet */
     339           8 :       if (nat44_ei_static_mapping_match (
     340           8 :             *addr, *port, *fib_index, *proto, &mapping_addr, &mapping_port,
     341             :             &mapping_fib_index, 1, &is_addr_only, &identity_nat))
     342             :         {
     343           2 :           if (!nm->forwarding_enabled)
     344             :             {
     345             :               /* Don't NAT packet aimed at the intfc address */
     346           1 :               if (PREDICT_FALSE (nat44_ei_is_interface_addr (
     347             :                     nm->ip4_main, node, sw_if_index0,
     348             :                     ip0->dst_address.as_u32)))
     349             :                 {
     350           1 :                   *dont_translate = 1;
     351           1 :                   goto out;
     352             :                 }
     353           0 :               b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
     354           0 :               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     355           0 :               goto out;
     356             :             }
     357             :           else
     358             :             {
     359           1 :               *dont_translate = 1;
     360           1 :               goto out;
     361             :             }
     362             :         }
     363             : 
     364           6 :       if (PREDICT_FALSE
     365             :           (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     366             :            ICMP4_echo_reply
     367             :            && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     368             :                ICMP4_echo_request || !is_addr_only)))
     369             :         {
     370           0 :           b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
     371           0 :           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     372           0 :           goto out;
     373             :         }
     374             : 
     375           6 :       if (PREDICT_FALSE (identity_nat))
     376             :         {
     377           0 :           *dont_translate = 1;
     378           0 :           goto out;
     379             :         }
     380             :       /* Create session initiated by host from external network */
     381           6 :       s0 = create_session_for_static_mapping (
     382           6 :         nm, b0, mapping_addr, mapping_port, mapping_fib_index, *addr, *port,
     383             :         *fib_index, *proto, node, thread_index, vlib_time_now (vm));
     384             : 
     385           6 :       if (!s0)
     386             :         {
     387           0 :           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     388           0 :           goto out;
     389             :         }
     390             :     }
     391             :   else
     392             :     {
     393          29 :       if (PREDICT_FALSE
     394             :           (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     395             :            ICMP4_echo_reply
     396             :            && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     397             :            ICMP4_echo_request
     398             :            && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
     399             :                                            reass.icmp_type_or_tcp_flags)))
     400             :         {
     401           0 :           b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
     402           0 :           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     403           0 :           goto out;
     404             :         }
     405             : 
     406          29 :       s0 = pool_elt_at_index (tnm->sessions,
     407             :                               nat_value_get_session_index (&value0));
     408             :     }
     409             : 
     410          37 : out:
     411          37 :   if (s0)
     412             :     {
     413          35 :       *addr = s0->in2out.addr;
     414          35 :       *port = s0->in2out.port;
     415          35 :       *fib_index = s0->in2out.fib_index;
     416             :     }
     417          37 :   if (p_s0)
     418          37 :     *p_s0 = s0;
     419          37 :   return next0;
     420             : }
     421             : #endif
     422             : 
     423             : #ifndef CLIB_MARCH_VARIANT
     424             : u32
     425           0 : nat44_ei_icmp_match_out2in_fast (vlib_node_runtime_t *node, u32 thread_index,
     426             :                                  vlib_buffer_t *b0, ip4_header_t *ip0,
     427             :                                  ip4_address_t *mapping_addr,
     428             :                                  u16 *mapping_port, u32 *mapping_fib_index,
     429             :                                  nat_protocol_t *proto,
     430             :                                  nat44_ei_session_t **p_s0, u8 *dont_translate)
     431             : {
     432           0 :   nat44_ei_main_t *nm = &nat44_ei_main;
     433             :   u32 sw_if_index0;
     434             :   u32 rx_fib_index0;
     435             :   u8 is_addr_only;
     436           0 :   u32 next0 = ~0;
     437             :   int err;
     438             :   ip4_address_t addr;
     439             :   u16 port;
     440           0 :   *dont_translate = 0;
     441             : 
     442           0 :   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     443           0 :   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     444             : 
     445           0 :   err = icmp_get_key (b0, ip0, &addr, &port, proto);
     446           0 :   if (err != -1)
     447             :     {
     448           0 :       b0->error = node->errors[err];
     449           0 :       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     450           0 :       goto out;
     451             :     }
     452           0 :   if (nat44_ei_static_mapping_match (addr, port, rx_fib_index0, *proto,
     453             :                                      mapping_addr, mapping_port,
     454             :                                      mapping_fib_index, 1, &is_addr_only, 0))
     455             :     {
     456             :       /* Don't NAT packet aimed at the intfc address */
     457           0 :       if (nat44_ei_is_interface_addr (nm->ip4_main, node, sw_if_index0,
     458             :                                       ip0->dst_address.as_u32))
     459             :         {
     460           0 :           *dont_translate = 1;
     461           0 :           goto out;
     462             :         }
     463           0 :       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
     464           0 :       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     465           0 :       goto out;
     466             :     }
     467             : 
     468           0 :   if (PREDICT_FALSE
     469             :       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
     470             :        && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
     471             :            ICMP4_echo_request || !is_addr_only)
     472             :        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
     473             :                                        reass.icmp_type_or_tcp_flags)))
     474             :     {
     475           0 :       b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
     476           0 :       next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     477           0 :       goto out;
     478             :     }
     479             : 
     480           0 : out:
     481           0 :   return next0;
     482             : }
     483             : #endif
     484             : 
     485             : u32 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
     486             :                           icmp46_header_t *icmp0, u32 sw_if_index0,
     487             :                           u32 rx_fib_index0, vlib_node_runtime_t *node,
     488             :                           u32 next0, u32 thread_index,
     489             :                           nat44_ei_session_t **p_s0);
     490             : 
     491             : #ifndef CLIB_MARCH_VARIANT
     492             : u32
     493          37 : nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
     494             :                       icmp46_header_t *icmp0, u32 sw_if_index0,
     495             :                       u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
     496             :                       u32 thread_index, nat44_ei_session_t **p_s0)
     497             : {
     498          37 :   nat44_ei_main_t *nm = &nat44_ei_main;
     499          37 :   icmp_echo_header_t *echo0, *inner_echo0 = 0;
     500          37 :   ip4_header_t *inner_ip0 = 0;
     501          37 :   void *l4_header = 0;
     502             :   icmp46_header_t *inner_icmp0;
     503             :   u8 dont_translate;
     504             :   u32 new_addr0, old_addr0;
     505             :   u16 old_id0, new_id0;
     506             :   ip_csum_t sum0;
     507             :   u16 checksum0;
     508             :   u32 next0_tmp;
     509          37 :   vlib_main_t *vm = vlib_get_main ();
     510             :   ip4_address_t addr;
     511             :   u16 port;
     512             :   u32 fib_index;
     513             :   nat_protocol_t proto;
     514             : 
     515          37 :   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
     516             : 
     517          37 :   if (PREDICT_TRUE (nm->pat))
     518             :     {
     519          37 :       next0_tmp = nat44_ei_icmp_match_out2in_slow (
     520             :         node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
     521             :         &dont_translate);
     522             :     }
     523             :   else
     524             :     {
     525           0 :       next0_tmp = nat44_ei_icmp_match_out2in_fast (
     526             :         node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
     527             :         &dont_translate);
     528             :     }
     529             : 
     530          37 :   if (next0_tmp != ~0)
     531           0 :     next0 = next0_tmp;
     532          37 :   if (next0 == NAT44_EI_OUT2IN_NEXT_DROP || dont_translate)
     533           2 :     goto out;
     534             : 
     535          35 :   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
     536             :     {
     537             :       sum0 =
     538          52 :         ip_incremental_checksum_buffer (vm, b0,
     539          26 :                                         (u8 *) icmp0 -
     540          26 :                                         (u8 *) vlib_buffer_get_current (b0),
     541          26 :                                         ntohs (ip0->length) -
     542          26 :                                         ip4_header_bytes (ip0), 0);
     543          26 :       checksum0 = ~ip_csum_fold (sum0);
     544          26 :       if (checksum0 != 0 && checksum0 != 0xffff)
     545             :         {
     546           0 :           next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     547           0 :           goto out;
     548             :         }
     549             :     }
     550             : 
     551          35 :   old_addr0 = ip0->dst_address.as_u32;
     552          35 :   new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
     553          35 :   vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
     554             : 
     555          35 :   sum0 = ip0->checksum;
     556          35 :   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
     557             :                          dst_address /* changed member */ );
     558          35 :   ip0->checksum = ip_csum_fold (sum0);
     559             : 
     560             : 
     561          35 :   if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
     562             :     {
     563          29 :       if (icmp0->checksum == 0)
     564           0 :         icmp0->checksum = 0xffff;
     565             : 
     566          29 :       if (!icmp_type_is_error_message (icmp0->type))
     567             :         {
     568          25 :           new_id0 = port;
     569          25 :           if (PREDICT_FALSE (new_id0 != echo0->identifier))
     570             :             {
     571          19 :               old_id0 = echo0->identifier;
     572          19 :               new_id0 = port;
     573          19 :               echo0->identifier = new_id0;
     574             : 
     575          19 :               sum0 = icmp0->checksum;
     576             :               sum0 =
     577          19 :                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
     578             :                                 identifier /* changed member */ );
     579          19 :               icmp0->checksum = ip_csum_fold (sum0);
     580             :             }
     581             :         }
     582             :       else
     583             :         {
     584           4 :           inner_ip0 = (ip4_header_t *) (echo0 + 1);
     585           4 :           l4_header = ip4_next_header (inner_ip0);
     586             : 
     587           4 :           if (!ip4_header_checksum_is_valid (inner_ip0))
     588             :             {
     589           0 :               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     590           0 :               goto out;
     591             :             }
     592             : 
     593           4 :           old_addr0 = inner_ip0->src_address.as_u32;
     594           4 :           inner_ip0->src_address = addr;
     595           4 :           new_addr0 = inner_ip0->src_address.as_u32;
     596             : 
     597           4 :           sum0 = icmp0->checksum;
     598           4 :           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
     599             :                                  src_address /* changed member */ );
     600           4 :           icmp0->checksum = ip_csum_fold (sum0);
     601             : 
     602           4 :           switch (proto)
     603             :             {
     604           1 :             case NAT_PROTOCOL_ICMP:
     605           1 :               inner_icmp0 = (icmp46_header_t *) l4_header;
     606           1 :               inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
     607             : 
     608           1 :               old_id0 = inner_echo0->identifier;
     609           1 :               new_id0 = port;
     610           1 :               inner_echo0->identifier = new_id0;
     611             : 
     612           1 :               sum0 = icmp0->checksum;
     613             :               sum0 =
     614           1 :                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
     615             :                                 identifier);
     616           1 :               icmp0->checksum = ip_csum_fold (sum0);
     617           1 :               break;
     618           3 :             case NAT_PROTOCOL_UDP:
     619             :             case NAT_PROTOCOL_TCP:
     620           3 :               old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
     621           3 :               new_id0 = port;
     622           3 :               ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
     623             : 
     624           3 :               sum0 = icmp0->checksum;
     625           3 :               sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
     626             :                                      src_port);
     627           3 :               icmp0->checksum = ip_csum_fold (sum0);
     628           3 :               break;
     629           0 :             default:
     630           0 :               ASSERT (0);
     631             :             }
     632             :         }
     633             :     }
     634             : 
     635           6 : out:
     636          37 :   return next0;
     637             : }
     638             : #endif
     639             : 
     640             : static inline u32
     641          37 : nat44_ei_icmp_out2in_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
     642             :                                 ip4_header_t *ip0, icmp46_header_t *icmp0,
     643             :                                 u32 sw_if_index0, u32 rx_fib_index0,
     644             :                                 vlib_node_runtime_t *node, u32 next0, f64 now,
     645             :                                 u32 thread_index, nat44_ei_session_t **p_s0)
     646             : {
     647          37 :   vlib_main_t *vm = vlib_get_main ();
     648             : 
     649          37 :   next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
     650             :                                 node, next0, thread_index, p_s0);
     651          37 :   nat44_ei_session_t *s0 = *p_s0;
     652          37 :   if (PREDICT_TRUE (next0 != NAT44_EI_OUT2IN_NEXT_DROP && s0))
     653             :     {
     654             :       /* Accounting */
     655          35 :       nat44_ei_session_update_counters (
     656             :         s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
     657             :       /* Per-user LRU list maintenance */
     658          35 :       nat44_ei_session_update_lru (nm, s0, thread_index);
     659             :     }
     660          37 :   return next0;
     661             : }
     662             : 
     663             : static int
     664           1 : nat_out2in_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
     665             :                              ip4_header_t *ip, u32 rx_fib_index)
     666             : {
     667             :   clib_bihash_kv_8_8_t kv, value;
     668             :   nat44_ei_static_mapping_t *m;
     669             :   u32 old_addr, new_addr;
     670             :   ip_csum_t sum;
     671             : 
     672           1 :   init_nat_k (&kv, ip->dst_address, 0, 0, 0);
     673           1 :   if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
     674           0 :     return 1;
     675             : 
     676           1 :   m = pool_elt_at_index (nm->static_mappings, value.value);
     677             : 
     678           1 :   old_addr = ip->dst_address.as_u32;
     679           1 :   new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
     680           1 :   sum = ip->checksum;
     681           1 :   sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
     682           1 :   ip->checksum = ip_csum_fold (sum);
     683             : 
     684           1 :   vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
     685           1 :   return 0;
     686             : }
     687             : 
     688        2342 : VLIB_NODE_FN (nat44_ei_out2in_node)
     689             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     690             : {
     691             :   u32 n_left_from, *from;
     692          42 :   nat44_ei_main_t *nm = &nat44_ei_main;
     693          42 :   f64 now = vlib_time_now (vm);
     694          42 :   u32 thread_index = vm->thread_index;
     695          42 :   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
     696             : 
     697          42 :   from = vlib_frame_vector_args (frame);
     698          42 :   n_left_from = frame->n_vectors;
     699             : 
     700          42 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     701          42 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
     702          42 :   vlib_get_buffers (vm, from, b, n_left_from);
     703             : 
     704         100 :   while (n_left_from >= 2)
     705             :     {
     706             :       vlib_buffer_t *b0, *b1;
     707          58 :       u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
     708          58 :       u32 next1 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
     709             :       u32 sw_if_index0, sw_if_index1;
     710             :       ip4_header_t *ip0, *ip1;
     711             :       ip_csum_t sum0, sum1;
     712             :       u32 new_addr0, old_addr0;
     713             :       u16 new_port0, old_port0;
     714             :       u32 new_addr1, old_addr1;
     715             :       u16 new_port1, old_port1;
     716             :       udp_header_t *udp0, *udp1;
     717             :       tcp_header_t *tcp0, *tcp1;
     718             :       icmp46_header_t *icmp0, *icmp1;
     719             :       u32 rx_fib_index0, rx_fib_index1;
     720             :       u32 proto0, proto1;
     721          58 :       nat44_ei_session_t *s0 = 0, *s1 = 0;
     722             :       clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
     723             :       u8 identity_nat0, identity_nat1;
     724             :       ip4_address_t sm_addr0, sm_addr1;
     725             :       u16 sm_port0, sm_port1;
     726             :       u32 sm_fib_index0, sm_fib_index1;
     727             : 
     728          58 :       b0 = *b;
     729          58 :       b++;
     730          58 :       b1 = *b;
     731          58 :       b++;
     732             : 
     733             :       /* Prefetch next iteration. */
     734          58 :       if (PREDICT_TRUE (n_left_from >= 4))
     735             :         {
     736             :           vlib_buffer_t *p2, *p3;
     737             : 
     738          24 :           p2 = *b;
     739          24 :           p3 = *(b + 1);
     740             : 
     741          24 :           vlib_prefetch_buffer_header (p2, LOAD);
     742          24 :           vlib_prefetch_buffer_header (p3, LOAD);
     743             : 
     744          24 :           clib_prefetch_load (p2->data);
     745          24 :           clib_prefetch_load (p3->data);
     746             :         }
     747             : 
     748          58 :       vnet_buffer (b0)->snat.flags = 0;
     749          58 :       vnet_buffer (b1)->snat.flags = 0;
     750             : 
     751          58 :       ip0 = vlib_buffer_get_current (b0);
     752          58 :       udp0 = ip4_next_header (ip0);
     753          58 :       tcp0 = (tcp_header_t *) udp0;
     754          58 :       icmp0 = (icmp46_header_t *) udp0;
     755             : 
     756          58 :       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     757          58 :       rx_fib_index0 =
     758          58 :         vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
     759             : 
     760          58 :       if (PREDICT_FALSE (ip0->ttl == 1))
     761             :         {
     762           2 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
     763           2 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
     764             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     765             :                                        0);
     766           2 :           next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
     767           2 :           goto trace0;
     768             :         }
     769             : 
     770          56 :       proto0 = ip_proto_to_nat_proto (ip0->protocol);
     771             : 
     772          56 :       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
     773             :         {
     774           0 :           if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
     775             :             {
     776           0 :               if (!nm->forwarding_enabled)
     777             :                 {
     778           0 :                   b0->error =
     779           0 :                     node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
     780           0 :                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     781             :                 }
     782             :             }
     783           0 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
     784             :                                          thread_index, sw_if_index0, 1);
     785             : 
     786           0 :           goto trace0;
     787             :         }
     788             : 
     789          56 :       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
     790             :         {
     791           5 :           next0 = nat44_ei_icmp_out2in_slow_path (
     792             :             nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
     793             :             thread_index, &s0);
     794           5 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
     795             :                                          thread_index, sw_if_index0, 1);
     796           5 :           goto trace0;
     797             :         }
     798             : 
     799          51 :       init_nat_k (&kv0, ip0->dst_address,
     800          51 :                   vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
     801             :                   proto0);
     802          51 :       if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
     803             :         {
     804             :           /* Try to match static mapping by external address and port,
     805             :              destination address and port in packet */
     806          14 :           if (nat44_ei_static_mapping_match (
     807          14 :                 ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
     808             :                 rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
     809             :                 0, &identity_nat0))
     810             :             {
     811             :               /*
     812             :                * Send DHCP packets to the ipv4 stack, or we won't
     813             :                * be able to use dhcp client on the outside interface
     814             :                */
     815           4 :               if (PREDICT_FALSE
     816             :                   (proto0 == NAT_PROTOCOL_UDP
     817             :                    && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
     818             :                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
     819             :                 {
     820           0 :                   vnet_feature_next (&next0, b0);
     821           0 :                   goto trace0;
     822             :                 }
     823             : 
     824           4 :               if (!nm->forwarding_enabled)
     825             :                 {
     826           1 :                   b0->error =
     827           1 :                     node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
     828           1 :                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     829             :                 }
     830           4 :               goto trace0;
     831             :             }
     832             : 
     833          10 :           if (PREDICT_FALSE (identity_nat0))
     834           0 :             goto trace0;
     835             : 
     836             :           /* Create session initiated by host from external network */
     837          20 :           s0 = create_session_for_static_mapping (
     838             :             nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
     839          10 :             vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
     840             :             node, thread_index, now);
     841          10 :           if (!s0)
     842             :             {
     843           0 :               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
     844           0 :               goto trace0;
     845             :             }
     846             :         }
     847             :       else
     848          37 :         s0 = pool_elt_at_index (tnm->sessions,
     849             :                                 nat_value_get_session_index (&value0));
     850             : 
     851          47 :       old_addr0 = ip0->dst_address.as_u32;
     852          47 :       ip0->dst_address = s0->in2out.addr;
     853          47 :       new_addr0 = ip0->dst_address.as_u32;
     854          47 :       vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
     855             : 
     856          47 :       sum0 = ip0->checksum;
     857          47 :       sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
     858             :                              ip4_header_t, dst_address /* changed member */ );
     859          47 :       ip0->checksum = ip_csum_fold (sum0);
     860             : 
     861          47 :       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
     862             :         {
     863          23 :           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
     864             :             {
     865          21 :               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
     866          21 :               new_port0 = udp0->dst_port = s0->in2out.port;
     867          21 :               sum0 = tcp0->checksum;
     868          21 :               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
     869             :                                      ip4_header_t,
     870             :                                      dst_address /* changed member */ );
     871             : 
     872          21 :               sum0 = ip_csum_update (sum0, old_port0, new_port0,
     873             :                                      ip4_header_t /* cheat */ ,
     874             :                                      length /* changed member */ );
     875          21 :               tcp0->checksum = ip_csum_fold (sum0);
     876             :             }
     877          23 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
     878             :                                          thread_index, sw_if_index0, 1);
     879             :         }
     880             :       else
     881             :         {
     882          24 :           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
     883             :             {
     884          22 :               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
     885          22 :               new_port0 = udp0->dst_port = s0->in2out.port;
     886          22 :               if (PREDICT_FALSE (udp0->checksum))
     887             :                 {
     888          22 :                   sum0 = udp0->checksum;
     889          22 :                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address  /* changed member */
     890             :                     );
     891             :                   sum0 =
     892          22 :                     ip_csum_update (sum0, old_port0, new_port0,
     893             :                                     ip4_header_t /* cheat */ ,
     894             :                                     length /* changed member */ );
     895          22 :                   udp0->checksum = ip_csum_fold (sum0);
     896             :                 }
     897             :             }
     898          24 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
     899             :                                          thread_index, sw_if_index0, 1);
     900             :         }
     901             : 
     902             :       /* Accounting */
     903          47 :       nat44_ei_session_update_counters (
     904             :         s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
     905             :       /* Per-user LRU list maintenance */
     906          47 :       nat44_ei_session_update_lru (nm, s0, thread_index);
     907          58 :     trace0:
     908             : 
     909          58 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     910             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     911             :         {
     912             :           nat44_ei_out2in_trace_t *t =
     913          58 :             vlib_add_trace (vm, node, b0, sizeof (*t));
     914          58 :           t->sw_if_index = sw_if_index0;
     915          58 :           t->next_index = next0;
     916          58 :           t->session_index = ~0;
     917          58 :           if (s0)
     918          52 :             t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
     919             :         }
     920             : 
     921          58 :       if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
     922             :         {
     923           1 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
     924             :                                          thread_index, sw_if_index0, 1);
     925             :         }
     926             : 
     927             : 
     928          58 :       ip1 = vlib_buffer_get_current (b1);
     929          58 :       udp1 = ip4_next_header (ip1);
     930          58 :       tcp1 = (tcp_header_t *) udp1;
     931          58 :       icmp1 = (icmp46_header_t *) udp1;
     932             : 
     933          58 :       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
     934          58 :       rx_fib_index1 =
     935          58 :         vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
     936             : 
     937          58 :       if (PREDICT_FALSE (ip1->ttl == 1))
     938             :         {
     939           2 :           vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
     940           2 :           icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
     941             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     942             :                                        0);
     943           2 :           next1 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
     944           2 :           goto trace1;
     945             :         }
     946             : 
     947          56 :       proto1 = ip_proto_to_nat_proto (ip1->protocol);
     948             : 
     949          56 :       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
     950             :         {
     951           0 :           if (nat_out2in_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
     952             :             {
     953           0 :               if (!nm->forwarding_enabled)
     954             :                 {
     955           0 :                   b1->error =
     956           0 :                     node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
     957           0 :                   next1 = NAT44_EI_OUT2IN_NEXT_DROP;
     958             :                 }
     959             :             }
     960           0 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
     961             :                                          thread_index, sw_if_index1, 1);
     962           0 :           goto trace1;
     963             :         }
     964             : 
     965          56 :       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
     966             :         {
     967          27 :           next1 = nat44_ei_icmp_out2in_slow_path (
     968             :             nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1, now,
     969             :             thread_index, &s1);
     970          27 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
     971             :                                          thread_index, sw_if_index1, 1);
     972          27 :           goto trace1;
     973             :         }
     974             : 
     975          29 :       init_nat_k (&kv1, ip1->dst_address,
     976          29 :                   vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1,
     977             :                   proto1);
     978          29 :       if (clib_bihash_search_8_8 (&nm->out2in, &kv1, &value1))
     979             :         {
     980             :           /* Try to match static mapping by external address and port,
     981             :              destination address and port in packet */
     982           3 :           if (nat44_ei_static_mapping_match (
     983           3 :                 ip1->dst_address, vnet_buffer (b1)->ip.reass.l4_dst_port,
     984             :                 rx_fib_index1, proto1, &sm_addr1, &sm_port1, &sm_fib_index1, 1,
     985             :                 0, &identity_nat1))
     986             :             {
     987             :               /*
     988             :                * Send DHCP packets to the ipv4 stack, or we won't
     989             :                * be able to use dhcp client on the outside interface
     990             :                */
     991           3 :               if (PREDICT_FALSE
     992             :                   (proto1 == NAT_PROTOCOL_UDP
     993             :                    && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
     994             :                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
     995             :                 {
     996           0 :                   vnet_feature_next (&next1, b1);
     997           0 :                   goto trace1;
     998             :                 }
     999             : 
    1000           3 :               if (!nm->forwarding_enabled)
    1001             :                 {
    1002           1 :                   b1->error =
    1003           1 :                     node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
    1004           1 :                   next1 = NAT44_EI_OUT2IN_NEXT_DROP;
    1005             :                 }
    1006           3 :               goto trace1;
    1007             :             }
    1008             : 
    1009           0 :           if (PREDICT_FALSE (identity_nat1))
    1010           0 :             goto trace1;
    1011             : 
    1012             :           /* Create session initiated by host from external network */
    1013           0 :           s1 = create_session_for_static_mapping (
    1014             :             nm, b1, sm_addr1, sm_port1, sm_fib_index1, ip1->dst_address,
    1015           0 :             vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1, proto1,
    1016             :             node, thread_index, now);
    1017           0 :           if (!s1)
    1018             :             {
    1019           0 :               next1 = NAT44_EI_OUT2IN_NEXT_DROP;
    1020           0 :               goto trace1;
    1021             :             }
    1022             :         }
    1023             :       else
    1024          26 :         s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
    1025             :                                 nat_value_get_session_index (&value1));
    1026             : 
    1027          26 :       old_addr1 = ip1->dst_address.as_u32;
    1028          26 :       ip1->dst_address = s1->in2out.addr;
    1029          26 :       new_addr1 = ip1->dst_address.as_u32;
    1030          26 :       vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
    1031             : 
    1032          26 :       sum1 = ip1->checksum;
    1033          26 :       sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
    1034             :                              ip4_header_t, dst_address /* changed member */ );
    1035          26 :       ip1->checksum = ip_csum_fold (sum1);
    1036             : 
    1037          26 :       if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
    1038             :         {
    1039          23 :           if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
    1040             :             {
    1041          20 :               old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
    1042          20 :               new_port1 = udp1->dst_port = s1->in2out.port;
    1043             : 
    1044          20 :               sum1 = tcp1->checksum;
    1045          20 :               sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
    1046             :                                      ip4_header_t,
    1047             :                                      dst_address /* changed member */ );
    1048             : 
    1049          20 :               sum1 = ip_csum_update (sum1, old_port1, new_port1,
    1050             :                                      ip4_header_t /* cheat */ ,
    1051             :                                      length /* changed member */ );
    1052          20 :               tcp1->checksum = ip_csum_fold (sum1);
    1053             :             }
    1054          23 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
    1055             :                                          thread_index, sw_if_index1, 1);
    1056             :         }
    1057             :       else
    1058             :         {
    1059           3 :           if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
    1060             :             {
    1061           0 :               old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
    1062           0 :               new_port1 = udp1->dst_port = s1->in2out.port;
    1063           0 :               if (PREDICT_FALSE (udp1->checksum))
    1064             :                 {
    1065             : 
    1066           0 :                   sum1 = udp1->checksum;
    1067             :                   sum1 =
    1068           0 :                     ip_csum_update (sum1, old_addr1, new_addr1,
    1069             :                                     ip4_header_t,
    1070             :                                     dst_address /* changed member */ );
    1071             :                   sum1 =
    1072           0 :                     ip_csum_update (sum1, old_port1, new_port1,
    1073             :                                     ip4_header_t /* cheat */ ,
    1074             :                                     length /* changed member */ );
    1075           0 :                   udp1->checksum = ip_csum_fold (sum1);
    1076             :                 }
    1077             :             }
    1078           3 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
    1079             :                                          thread_index, sw_if_index1, 1);
    1080             :         }
    1081             : 
    1082             :       /* Accounting */
    1083          26 :       nat44_ei_session_update_counters (
    1084             :         s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
    1085             :       /* Per-user LRU list maintenance */
    1086          26 :       nat44_ei_session_update_lru (nm, s1, thread_index);
    1087          58 :     trace1:
    1088             : 
    1089          58 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
    1090             :                          && (b1->flags & VLIB_BUFFER_IS_TRACED)))
    1091             :         {
    1092             :           nat44_ei_out2in_trace_t *t =
    1093          58 :             vlib_add_trace (vm, node, b1, sizeof (*t));
    1094          58 :           t->sw_if_index = sw_if_index1;
    1095          58 :           t->next_index = next1;
    1096          58 :           t->session_index = ~0;
    1097          58 :           if (s1)
    1098          52 :             t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
    1099             :         }
    1100             : 
    1101          58 :       if (next1 == NAT44_EI_OUT2IN_NEXT_DROP)
    1102             :         {
    1103           1 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
    1104             :                                          thread_index, sw_if_index1, 1);
    1105             :         }
    1106             : 
    1107          58 :       n_left_from -= 2;
    1108          58 :       next[0] = next0;
    1109          58 :       next[1] = next1;
    1110          58 :       next += 2;
    1111             :     }
    1112             : 
    1113          60 :   while (n_left_from > 0)
    1114             :     {
    1115             :       vlib_buffer_t *b0;
    1116          18 :       u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
    1117             :       u32 sw_if_index0;
    1118             :       ip4_header_t *ip0;
    1119             :       ip_csum_t sum0;
    1120             :       u32 new_addr0, old_addr0;
    1121             :       u16 new_port0, old_port0;
    1122             :       udp_header_t *udp0;
    1123             :       tcp_header_t *tcp0;
    1124             :       icmp46_header_t *icmp0;
    1125             :       u32 rx_fib_index0;
    1126             :       u32 proto0;
    1127          18 :       nat44_ei_session_t *s0 = 0;
    1128             :       clib_bihash_kv_8_8_t kv0, value0;
    1129             :       u8 identity_nat0;
    1130             :       ip4_address_t sm_addr0;
    1131             :       u16 sm_port0;
    1132             :       u32 sm_fib_index0;
    1133             : 
    1134          18 :       b0 = *b;
    1135          18 :       ++b;
    1136             : 
    1137          18 :       vnet_buffer (b0)->snat.flags = 0;
    1138             : 
    1139          18 :       ip0 = vlib_buffer_get_current (b0);
    1140          18 :       udp0 = ip4_next_header (ip0);
    1141          18 :       tcp0 = (tcp_header_t *) udp0;
    1142          18 :       icmp0 = (icmp46_header_t *) udp0;
    1143             : 
    1144          18 :       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
    1145          18 :       rx_fib_index0 =
    1146          18 :         vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
    1147             : 
    1148          18 :       proto0 = ip_proto_to_nat_proto (ip0->protocol);
    1149             : 
    1150          18 :       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
    1151             :         {
    1152           1 :           if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
    1153             :             {
    1154           0 :               if (!nm->forwarding_enabled)
    1155             :                 {
    1156           0 :                   b0->error =
    1157           0 :                     node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
    1158           0 :                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
    1159             :                 }
    1160             :             }
    1161           1 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
    1162             :                                          thread_index, sw_if_index0, 1);
    1163           1 :           goto trace00;
    1164             :         }
    1165             : 
    1166          17 :       if (PREDICT_FALSE (ip0->ttl == 1))
    1167             :         {
    1168           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
    1169           0 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
    1170             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
    1171             :                                        0);
    1172           0 :           next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
    1173           0 :           goto trace00;
    1174             :         }
    1175             : 
    1176          17 :       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
    1177             :         {
    1178           5 :           next0 = nat44_ei_icmp_out2in_slow_path (
    1179             :             nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
    1180             :             thread_index, &s0);
    1181           5 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
    1182             :                                          thread_index, sw_if_index0, 1);
    1183           5 :           goto trace00;
    1184             :         }
    1185             : 
    1186          12 :       init_nat_k (&kv0, ip0->dst_address,
    1187          12 :                   vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
    1188             :                   proto0);
    1189             : 
    1190          12 :       if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
    1191             :         {
    1192             :           /* Try to match static mapping by external address and port,
    1193             :              destination address and port in packet */
    1194           3 :           if (nat44_ei_static_mapping_match (
    1195           3 :                 ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
    1196             :                 rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
    1197             :                 0, &identity_nat0))
    1198             :             {
    1199             :               /*
    1200             :                * Send DHCP packets to the ipv4 stack, or we won't
    1201             :                * be able to use dhcp client on the outside interface
    1202             :                */
    1203           1 :               if (PREDICT_FALSE
    1204             :                   (proto0 == NAT_PROTOCOL_UDP
    1205             :                    && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
    1206             :                        clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
    1207             :                 {
    1208           0 :                   vnet_feature_next (&next0, b0);
    1209           0 :                   goto trace00;
    1210             :                 }
    1211             : 
    1212           1 :               if (!nm->forwarding_enabled)
    1213             :                 {
    1214           0 :                   b0->error =
    1215           0 :                     node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
    1216           0 :                   next0 = NAT44_EI_OUT2IN_NEXT_DROP;
    1217             :                 }
    1218           1 :               goto trace00;
    1219             :             }
    1220             : 
    1221           2 :           if (PREDICT_FALSE (identity_nat0))
    1222           1 :             goto trace00;
    1223             : 
    1224             :           /* Create session initiated by host from external network */
    1225           2 :           s0 = create_session_for_static_mapping (
    1226             :             nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
    1227           1 :             vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
    1228             :             node, thread_index, now);
    1229           1 :           if (!s0)
    1230             :             {
    1231           0 :               next0 = NAT44_EI_OUT2IN_NEXT_DROP;
    1232           0 :               goto trace00;
    1233             :             }
    1234             :         }
    1235             :       else
    1236           9 :         s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
    1237             :                                 nat_value_get_session_index (&value0));
    1238             : 
    1239          10 :       old_addr0 = ip0->dst_address.as_u32;
    1240          10 :       ip0->dst_address = s0->in2out.addr;
    1241          10 :       new_addr0 = ip0->dst_address.as_u32;
    1242          10 :       vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
    1243             : 
    1244          10 :       sum0 = ip0->checksum;
    1245          10 :       sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
    1246             :                              ip4_header_t, dst_address /* changed member */ );
    1247          10 :       ip0->checksum = ip_csum_fold (sum0);
    1248             : 
    1249          10 :       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
    1250             :         {
    1251           7 :           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
    1252             :             {
    1253           6 :               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
    1254           6 :               new_port0 = udp0->dst_port = s0->in2out.port;
    1255             : 
    1256           6 :               sum0 = tcp0->checksum;
    1257           6 :               sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
    1258             :                                      ip4_header_t,
    1259             :                                      dst_address /* changed member */ );
    1260             : 
    1261           6 :               sum0 = ip_csum_update (sum0, old_port0, new_port0,
    1262             :                                      ip4_header_t /* cheat */ ,
    1263             :                                      length /* changed member */ );
    1264           6 :               tcp0->checksum = ip_csum_fold (sum0);
    1265             :             }
    1266           7 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
    1267             :                                          thread_index, sw_if_index0, 1);
    1268             :         }
    1269             :       else
    1270             :         {
    1271           3 :           if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
    1272             :             {
    1273           2 :               old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
    1274           2 :               new_port0 = udp0->dst_port = s0->in2out.port;
    1275           2 :               if (PREDICT_FALSE (udp0->checksum))
    1276             :                 {
    1277           2 :                   sum0 = udp0->checksum;
    1278           2 :                   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address  /* changed member */
    1279             :                     );
    1280             :                   sum0 =
    1281           2 :                     ip_csum_update (sum0, old_port0, new_port0,
    1282             :                                     ip4_header_t /* cheat */ ,
    1283             :                                     length /* changed member */ );
    1284           2 :                   udp0->checksum = ip_csum_fold (sum0);
    1285             :                 }
    1286             :             }
    1287           3 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
    1288             :                                          thread_index, sw_if_index0, 1);
    1289             :         }
    1290             : 
    1291             :       /* Accounting */
    1292          10 :       nat44_ei_session_update_counters (
    1293             :         s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
    1294             :       /* Per-user LRU list maintenance */
    1295          10 :       nat44_ei_session_update_lru (nm, s0, thread_index);
    1296          18 :     trace00:
    1297             : 
    1298          18 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
    1299             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
    1300             :         {
    1301             :           nat44_ei_out2in_trace_t *t =
    1302          18 :             vlib_add_trace (vm, node, b0, sizeof (*t));
    1303          18 :           t->sw_if_index = sw_if_index0;
    1304          18 :           t->next_index = next0;
    1305          18 :           t->session_index = ~0;
    1306          18 :           if (s0)
    1307          14 :             t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
    1308             :         }
    1309             : 
    1310          18 :       if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
    1311             :         {
    1312           0 :           vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
    1313             :                                          thread_index, sw_if_index0, 1);
    1314             :         }
    1315             : 
    1316          18 :       n_left_from--;
    1317          18 :       next[0] = next0;
    1318          18 :       next++;
    1319             :     }
    1320             : 
    1321          42 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
    1322          42 :                                frame->n_vectors);
    1323             : 
    1324          42 :   return frame->n_vectors;
    1325             : }
    1326             : 
    1327       72026 : VLIB_REGISTER_NODE (nat44_ei_out2in_node) = {
    1328             :   .name = "nat44-ei-out2in",
    1329             :   .vector_size = sizeof (u32),
    1330             :   .format_trace = format_nat44_ei_out2in_trace,
    1331             :   .type = VLIB_NODE_TYPE_INTERNAL,
    1332             : 
    1333             :   .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
    1334             :   .error_strings = nat44_ei_out2in_error_strings,
    1335             : 
    1336             :   .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
    1337             : 
    1338             :   .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
    1339             : 
    1340             :   /* edit / add dispositions here */
    1341             :   .next_nodes = {
    1342             :     [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
    1343             :     [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
    1344             :     [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
    1345             :   },
    1346             : };
    1347             : 
    1348             : /*
    1349             :  * fd.io coding-style-patch-verification: ON
    1350             :  *
    1351             :  * Local Variables:
    1352             :  * eval: (c-set-style "gnu")
    1353             :  * End:
    1354             :  */

Generated by: LCOV version 1.14