LCOV - code coverage report
Current view: top level - plugins/nat/det44 - det44_out2in.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 243 387 62.8 %
Date: 2023-10-26 01:39:38 Functions: 10 13 76.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 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             : /**
      17             :  * @file
      18             :  * @brief Deterministic NAT (CGN) outside to inside translation
      19             :  */
      20             : 
      21             : #include <vlib/vlib.h>
      22             : #include <vnet/vnet.h>
      23             : #include <vnet/ip/ip.h>
      24             : #include <vnet/fib/ip4_fib.h>
      25             : #include <vppinfra/error.h>
      26             : #include <vppinfra/elog.h>
      27             : 
      28             : #include <nat/det44/det44.h>
      29             : #include <nat/det44/det44_inlines.h>
      30             : 
      31             : #include <nat/lib/lib.h>
      32             : #include <nat/lib/inlines.h>
      33             : #include <nat/lib/nat_inlines.h>
      34             : 
      35             : typedef enum
      36             : {
      37             :   DET44_OUT2IN_NEXT_DROP,
      38             :   DET44_OUT2IN_NEXT_LOOKUP,
      39             :   DET44_OUT2IN_NEXT_ICMP_ERROR,
      40             :   DET44_OUT2IN_N_NEXT,
      41             : } det44_out2in_next_t;
      42             : 
      43             : typedef struct
      44             : {
      45             :   u32 sw_if_index;
      46             :   u32 next_index;
      47             :   u32 session_index;
      48             : } det44_out2in_trace_t;
      49             : 
      50             : #define foreach_det44_out2in_error                 \
      51             : _(UNSUPPORTED_PROTOCOL, "Unsupported protocol")    \
      52             : _(NO_TRANSLATION, "No translation")                \
      53             : _(BAD_ICMP_TYPE, "unsupported ICMP type")          \
      54             : _(OUT2IN_PACKETS, "Good out2in packets processed")
      55             : 
      56             : typedef enum
      57             : {
      58             : #define _(sym,str) DET44_OUT2IN_ERROR_##sym,
      59             :   foreach_det44_out2in_error
      60             : #undef _
      61             :     DET44_OUT2IN_N_ERROR,
      62             : } det44_out2in_error_t;
      63             : 
      64             : static char *det44_out2in_error_strings[] = {
      65             : #define _(sym,string) string,
      66             :   foreach_det44_out2in_error
      67             : #undef _
      68             : };
      69             : 
      70             : static u8 *
      71           5 : format_det44_out2in_trace (u8 * s, va_list * args)
      72             : {
      73           5 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      74           5 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      75           5 :   det44_out2in_trace_t *t = va_arg (*args, det44_out2in_trace_t *);
      76             : 
      77             :   s =
      78           5 :     format (s,
      79             :             "DET44_OUT2IN: sw_if_index %d, next index %d, session index %d",
      80             :             t->sw_if_index, t->next_index, t->session_index);
      81           5 :   return s;
      82             : }
      83             : 
      84             : #ifndef CLIB_MARCH_VARIANT
      85             : /**
      86             :  * Get address and port values to be used for ICMP packet translation
      87             :  * and create session if needed
      88             :  *
      89             :  * @param[in,out] node           NAT node runtime
      90             :  * @param[in] thread_index       thread index
      91             :  * @param[in,out] b0             buffer containing packet to be translated
      92             :  * @param[in,out] ip0            ip header
      93             :  * @param[out] p_proto           protocol used for matching
      94             :  * @param[out] p_value           address and port after NAT translation
      95             :  * @param[out] p_dont_translate  if packet should not be translated
      96             :  * @param d                      optional parameter
      97             :  * @param e                      optional parameter
      98             :  */
      99             : u32
     100           1 : icmp_match_out2in_det (vlib_node_runtime_t * node,
     101             :                        u32 thread_index, vlib_buffer_t * b0,
     102             :                        ip4_header_t * ip0, ip4_address_t * addr,
     103             :                        u16 * port, u32 * fib_index,
     104             :                        nat_protocol_t * proto, void *d, void *e,
     105             :                        u8 * dont_translate)
     106             : {
     107           1 :   det44_main_t *dm = &det44_main;
     108             :   icmp46_header_t *icmp0;
     109             :   u32 sw_if_index0;
     110             :   u8 protocol;
     111             :   snat_det_out_key_t key0;
     112           1 :   u32 next0 = ~0;
     113           1 :   icmp_echo_header_t *echo0, *inner_echo0 = 0;
     114             :   ip4_header_t *inner_ip0;
     115           1 :   void *l4_header = 0;
     116             :   icmp46_header_t *inner_icmp0;
     117           1 :   snat_det_map_t *mp0 = 0;
     118           1 :   ip4_address_t new_addr0 = { {0} };
     119           1 :   snat_det_session_t *ses0 = 0;
     120             :   ip4_address_t out_addr;
     121           1 :   *dont_translate = 0;
     122             : 
     123           1 :   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
     124           1 :   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
     125           1 :   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     126             : 
     127           1 :   if (!icmp_type_is_error_message
     128           1 :       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
     129             :     {
     130           1 :       protocol = NAT_PROTOCOL_ICMP;
     131           1 :       key0.ext_host_addr = ip0->src_address;
     132           1 :       key0.ext_host_port = 0;
     133           1 :       key0.out_port = vnet_buffer (b0)->ip.reass.l4_src_port;
     134           1 :       out_addr = ip0->dst_address;
     135             :     }
     136             :   else
     137             :     {
     138             :       /* if error message, then it's not fragmented and we can access it */
     139           0 :       inner_ip0 = (ip4_header_t *) (echo0 + 1);
     140           0 :       l4_header = ip4_next_header (inner_ip0);
     141           0 :       protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
     142           0 :       key0.ext_host_addr = inner_ip0->dst_address;
     143           0 :       out_addr = inner_ip0->src_address;
     144           0 :       switch (protocol)
     145             :         {
     146           0 :         case NAT_PROTOCOL_ICMP:
     147           0 :           inner_icmp0 = (icmp46_header_t *) l4_header;
     148           0 :           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
     149           0 :           key0.ext_host_port = 0;
     150           0 :           key0.out_port = inner_echo0->identifier;
     151           0 :           break;
     152           0 :         case NAT_PROTOCOL_UDP:
     153             :         case NAT_PROTOCOL_TCP:
     154           0 :           key0.ext_host_port = ((tcp_udp_header_t *) l4_header)->dst_port;
     155           0 :           key0.out_port = ((tcp_udp_header_t *) l4_header)->src_port;
     156           0 :           break;
     157           0 :         default:
     158           0 :           b0->error = node->errors[DET44_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
     159           0 :           next0 = DET44_OUT2IN_NEXT_DROP;
     160           0 :           goto out;
     161             :         }
     162             :     }
     163             : 
     164           1 :   mp0 = snat_det_map_by_out (&out_addr);
     165           1 :   if (PREDICT_FALSE (!mp0))
     166             :     {
     167             :       /* Don't NAT packet aimed at the intfc address */
     168           0 :       if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
     169             :                                                    ip0->dst_address.as_u32)))
     170             :         {
     171           0 :           *dont_translate = 1;
     172           0 :           goto out;
     173             :         }
     174           0 :       det44_log_info ("unknown dst address:  %U",
     175             :                       format_ip4_address, &ip0->dst_address);
     176           0 :       b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     177           0 :       next0 = DET44_OUT2IN_NEXT_DROP;
     178             : 
     179           0 :       goto out;
     180             :     }
     181             : 
     182           1 :   snat_det_reverse (mp0, &ip0->dst_address,
     183           1 :                     clib_net_to_host_u16 (key0.out_port), &new_addr0);
     184             : 
     185           1 :   ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
     186           1 :   if (PREDICT_FALSE (!ses0))
     187             :     {
     188             :       /* Don't NAT packet aimed at the intfc address */
     189           0 :       if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
     190             :                                                    ip0->dst_address.as_u32)))
     191             :         {
     192           0 :           *dont_translate = 1;
     193           0 :           goto out;
     194             :         }
     195           0 :       det44_log_info ("no match src %U:%d dst %U:%d for user %U",
     196             :                       format_ip4_address, &key0.ext_host_addr,
     197             :                       clib_net_to_host_u16 (key0.ext_host_port),
     198             :                       format_ip4_address, &out_addr,
     199             :                       clib_net_to_host_u16 (key0.out_port),
     200             :                       format_ip4_address, &new_addr0);
     201           0 :       b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     202           0 :       next0 = DET44_OUT2IN_NEXT_DROP;
     203           0 :       goto out;
     204             :     }
     205             : 
     206           1 :   if (PREDICT_FALSE
     207             :       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
     208             :        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
     209             :                                        reass.icmp_type_or_tcp_flags)))
     210             :     {
     211           0 :       b0->error = node->errors[DET44_OUT2IN_ERROR_BAD_ICMP_TYPE];
     212           0 :       next0 = DET44_OUT2IN_NEXT_DROP;
     213           0 :       goto out;
     214             :     }
     215             : 
     216           1 :   goto out;
     217             : 
     218           1 : out:
     219           1 :   *proto = protocol;
     220           1 :   if (ses0)
     221             :     {
     222           1 :       *addr = new_addr0;
     223           1 :       *fib_index = dm->inside_fib_index;
     224           1 :       *port = ses0->in_port;
     225             :     }
     226           1 :   if (d)
     227           1 :     *(snat_det_session_t **) d = ses0;
     228           1 :   if (e)
     229           1 :     *(snat_det_map_t **) e = mp0;
     230           1 :   return next0;
     231             : }
     232             : #endif
     233             : 
     234             : #ifndef CLIB_MARCH_VARIANT
     235             : u32
     236           1 : det44_icmp_out2in (vlib_buffer_t * b0,
     237             :                    ip4_header_t * ip0,
     238             :                    icmp46_header_t * icmp0,
     239             :                    u32 sw_if_index0,
     240             :                    u32 rx_fib_index0,
     241             :                    vlib_node_runtime_t * node,
     242             :                    u32 next0, u32 thread_index, void *d, void *e)
     243             : {
     244           1 :   vlib_main_t *vm = vlib_get_main ();
     245             :   u32 new_addr0, old_addr0, next0_tmp, fib_index;
     246             :   u16 old_id0, new_id0, port, checksum0;
     247             :   icmp_echo_header_t *echo0, *inner_echo0;
     248             :   icmp46_header_t *inner_icmp0;
     249             :   ip4_header_t *inner_ip0;
     250             :   ip4_address_t addr;
     251             :   void *l4_header;
     252             :   u8 dont_translate;
     253             :   ip_csum_t sum0;
     254             :   nat_protocol_t proto;
     255             : 
     256           1 :   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
     257           1 :   next0_tmp = icmp_match_out2in_det (node, thread_index, b0, ip0,
     258             :                                      &addr, &port, &fib_index, &proto,
     259             :                                      d, e, &dont_translate);
     260           1 :   if (next0_tmp != ~0)
     261           0 :     next0 = next0_tmp;
     262           1 :   if (next0 == DET44_OUT2IN_NEXT_DROP || dont_translate)
     263           0 :     goto out;
     264             : 
     265           1 :   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
     266             :     {
     267             :       sum0 =
     268           2 :         ip_incremental_checksum_buffer (vm, b0,
     269           1 :                                         (u8 *) icmp0 -
     270           1 :                                         (u8 *) vlib_buffer_get_current (b0),
     271           1 :                                         ntohs (ip0->length) -
     272           1 :                                         ip4_header_bytes (ip0), 0);
     273           1 :       checksum0 = ~ip_csum_fold (sum0);
     274           1 :       if (checksum0 != 0 && checksum0 != 0xffff)
     275             :         {
     276           0 :           next0 = DET44_OUT2IN_NEXT_DROP;
     277           0 :           goto out;
     278             :         }
     279             :     }
     280             : 
     281           1 :   old_addr0 = ip0->dst_address.as_u32;
     282           1 :   new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
     283           1 :   vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
     284             : 
     285           1 :   sum0 = ip0->checksum;
     286           1 :   sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
     287             :                          dst_address /* changed member */ );
     288           1 :   ip0->checksum = ip_csum_fold (sum0);
     289             : 
     290             : 
     291           1 :   if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
     292             :     {
     293           1 :       if (icmp0->checksum == 0)
     294           0 :         icmp0->checksum = 0xffff;
     295             : 
     296           1 :       if (!icmp_type_is_error_message (icmp0->type))
     297             :         {
     298           1 :           new_id0 = port;
     299           1 :           if (PREDICT_FALSE (new_id0 != echo0->identifier))
     300             :             {
     301           1 :               old_id0 = echo0->identifier;
     302           1 :               new_id0 = port;
     303           1 :               echo0->identifier = new_id0;
     304             : 
     305           1 :               sum0 = icmp0->checksum;
     306             :               sum0 =
     307           1 :                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
     308             :                                 identifier /* changed member */ );
     309           1 :               icmp0->checksum = ip_csum_fold (sum0);
     310             :             }
     311             :         }
     312             :       else
     313             :         {
     314           0 :           inner_ip0 = (ip4_header_t *) (echo0 + 1);
     315           0 :           l4_header = ip4_next_header (inner_ip0);
     316             : 
     317           0 :           if (!ip4_header_checksum_is_valid (inner_ip0))
     318             :             {
     319           0 :               next0 = DET44_OUT2IN_NEXT_DROP;
     320           0 :               goto out;
     321             :             }
     322             : 
     323           0 :           old_addr0 = inner_ip0->src_address.as_u32;
     324           0 :           inner_ip0->src_address = addr;
     325           0 :           new_addr0 = inner_ip0->src_address.as_u32;
     326             : 
     327           0 :           sum0 = icmp0->checksum;
     328           0 :           sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
     329             :                                  src_address /* changed member */ );
     330           0 :           icmp0->checksum = ip_csum_fold (sum0);
     331             : 
     332           0 :           switch (proto)
     333             :             {
     334           0 :             case NAT_PROTOCOL_ICMP:
     335           0 :               inner_icmp0 = (icmp46_header_t *) l4_header;
     336           0 :               inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
     337             : 
     338           0 :               old_id0 = inner_echo0->identifier;
     339           0 :               new_id0 = port;
     340           0 :               inner_echo0->identifier = new_id0;
     341             : 
     342           0 :               sum0 = icmp0->checksum;
     343             :               sum0 =
     344           0 :                 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
     345             :                                 identifier);
     346           0 :               icmp0->checksum = ip_csum_fold (sum0);
     347           0 :               break;
     348           0 :             case NAT_PROTOCOL_UDP:
     349             :             case NAT_PROTOCOL_TCP:
     350           0 :               old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
     351           0 :               new_id0 = port;
     352           0 :               ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
     353             : 
     354           0 :               sum0 = icmp0->checksum;
     355           0 :               sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
     356             :                                      src_port);
     357           0 :               icmp0->checksum = ip_csum_fold (sum0);
     358           0 :               break;
     359           0 :             default:
     360           0 :               ASSERT (0);
     361             :             }
     362             :         }
     363             :     }
     364             : 
     365           0 : out:
     366           1 :   return next0;
     367             : }
     368             : #endif
     369             : 
     370        2309 : VLIB_NODE_FN (det44_out2in_node) (vlib_main_t * vm,
     371             :                                   vlib_node_runtime_t * node,
     372             :                                   vlib_frame_t * frame)
     373             : {
     374             :   u32 n_left_from, *from;
     375           9 :   u32 pkts_processed = 0;
     376           9 :   det44_main_t *dm = &det44_main;
     377           9 :   u32 thread_index = vm->thread_index;
     378             : 
     379           9 :   from = vlib_frame_vector_args (frame);
     380           9 :   n_left_from = frame->n_vectors;
     381             : 
     382           9 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     383           9 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
     384           9 :   vlib_get_buffers (vm, from, b, n_left_from);
     385             : 
     386          11 :   while (n_left_from >= 2)
     387             :     {
     388             :       vlib_buffer_t *b0, *b1;
     389           2 :       u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
     390           2 :       u32 next1 = DET44_OUT2IN_NEXT_LOOKUP;
     391             :       u32 sw_if_index0, sw_if_index1;
     392             :       ip4_header_t *ip0, *ip1;
     393             :       ip_csum_t sum0, sum1;
     394             :       ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
     395             :       u16 new_port0, old_port0, old_port1, new_port1;
     396             :       udp_header_t *udp0, *udp1;
     397             :       tcp_header_t *tcp0, *tcp1;
     398             :       u32 proto0, proto1;
     399             :       snat_det_out_key_t key0, key1;
     400             :       snat_det_map_t *mp0, *mp1;
     401           2 :       snat_det_session_t *ses0 = 0, *ses1 = 0;
     402             :       u32 rx_fib_index0, rx_fib_index1;
     403             :       icmp46_header_t *icmp0, *icmp1;
     404             : 
     405           2 :       b0 = *b;
     406           2 :       b++;
     407           2 :       b1 = *b;
     408           2 :       b++;
     409             : 
     410             :       /* Prefetch next iteration. */
     411           2 :       if (PREDICT_TRUE (n_left_from >= 4))
     412             :         {
     413             :           vlib_buffer_t *p2, *p3;
     414             : 
     415           0 :           p2 = *b;
     416           0 :           p3 = *(b + 1);
     417             : 
     418           0 :           vlib_prefetch_buffer_header (p2, LOAD);
     419           0 :           vlib_prefetch_buffer_header (p3, LOAD);
     420             : 
     421           0 :           clib_prefetch_load (p2->data);
     422           0 :           clib_prefetch_load (p3->data);
     423             :         }
     424             : 
     425             : 
     426           2 :       ip0 = vlib_buffer_get_current (b0);
     427           2 :       udp0 = ip4_next_header (ip0);
     428           2 :       tcp0 = (tcp_header_t *) udp0;
     429             : 
     430           2 :       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     431             : 
     432           2 :       if (PREDICT_FALSE (ip0->ttl == 1))
     433             :         {
     434           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
     435           0 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
     436             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     437             :                                        0);
     438           0 :           next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
     439           0 :           goto trace0;
     440             :         }
     441             : 
     442           2 :       proto0 = ip_proto_to_nat_proto (ip0->protocol);
     443             : 
     444           2 :       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
     445             :         {
     446             :           rx_fib_index0 =
     447           0 :             ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     448           0 :           icmp0 = (icmp46_header_t *) udp0;
     449             : 
     450           0 :           next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
     451             :                                      rx_fib_index0, node, next0,
     452             :                                      thread_index, &ses0, &mp0);
     453           0 :           goto trace0;
     454             :         }
     455             : 
     456           2 :       key0.ext_host_addr = ip0->src_address;
     457           2 :       key0.ext_host_port = tcp0->src;
     458           2 :       key0.out_port = tcp0->dst;
     459             : 
     460           2 :       mp0 = snat_det_map_by_out (&ip0->dst_address);
     461           2 :       if (PREDICT_FALSE (!mp0))
     462             :         {
     463           0 :           det44_log_info ("unknown dst address:  %U",
     464             :                           format_ip4_address, &ip0->dst_address);
     465           0 :           next0 = DET44_OUT2IN_NEXT_DROP;
     466           0 :           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     467           0 :           goto trace0;
     468             :         }
     469             : 
     470           2 :       snat_det_reverse (mp0, &ip0->dst_address,
     471           2 :                         clib_net_to_host_u16 (tcp0->dst), &new_addr0);
     472             : 
     473           2 :       ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
     474           2 :       if (PREDICT_FALSE (!ses0))
     475             :         {
     476           0 :           det44_log_info ("no match src %U:%d dst %U:%d for user %U",
     477             :                           format_ip4_address, &ip0->src_address,
     478             :                           clib_net_to_host_u16 (tcp0->src),
     479             :                           format_ip4_address, &ip0->dst_address,
     480             :                           clib_net_to_host_u16 (tcp0->dst),
     481             :                           format_ip4_address, &new_addr0);
     482           0 :           next0 = DET44_OUT2IN_NEXT_DROP;
     483           0 :           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     484           0 :           goto trace0;
     485             :         }
     486           2 :       old_port0 = udp0->dst_port;
     487           2 :       udp0->dst_port = new_port0 = ses0->in_port;
     488             : 
     489           2 :       old_addr0 = ip0->dst_address;
     490           2 :       ip0->dst_address = new_addr0;
     491           2 :       vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
     492             : 
     493           2 :       sum0 = ip0->checksum;
     494           2 :       sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
     495             :                              ip4_header_t, dst_address /* changed member */ );
     496           2 :       ip0->checksum = ip_csum_fold (sum0);
     497             : 
     498           2 :       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
     499             :         {
     500           2 :           if (tcp0->flags & TCP_FLAG_FIN
     501           0 :               && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
     502           0 :             ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
     503           2 :           else if (tcp0->flags & TCP_FLAG_ACK
     504           1 :                    && ses0->state == DET44_SESSION_TCP_LAST_ACK)
     505           0 :             snat_det_ses_close (mp0, ses0);
     506             : 
     507           2 :           sum0 = tcp0->checksum;
     508           2 :           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
     509             :                                  ip4_header_t,
     510             :                                  dst_address /* changed member */ );
     511           2 :           sum0 = ip_csum_update (sum0, old_port0, new_port0,
     512             :                                  ip4_header_t /* cheat */ ,
     513             :                                  length /* changed member */ );
     514           2 :           tcp0->checksum = ip_csum_fold (sum0);
     515             :         }
     516           0 :       else if (udp0->checksum)
     517             :         {
     518           0 :           sum0 = udp0->checksum;
     519           0 :           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
     520             :                                  ip4_header_t,
     521             :                                  dst_address /* changed member */ );
     522           0 :           sum0 = ip_csum_update (sum0, old_port0, new_port0,
     523             :                                  ip4_header_t /* cheat */ ,
     524             :                                  length /* changed member */ );
     525           0 :           udp0->checksum = ip_csum_fold (sum0);
     526             :         }
     527             : 
     528           0 :     trace0:
     529             : 
     530           2 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     531             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     532             :         {
     533             :           det44_out2in_trace_t *t =
     534           2 :             vlib_add_trace (vm, node, b0, sizeof (*t));
     535           2 :           t->sw_if_index = sw_if_index0;
     536           2 :           t->next_index = next0;
     537           2 :           t->session_index = ~0;
     538           2 :           if (ses0)
     539           2 :             t->session_index = ses0 - mp0->sessions;
     540             :         }
     541             : 
     542           2 :       pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
     543             : 
     544           2 :       ip1 = vlib_buffer_get_current (b1);
     545           2 :       udp1 = ip4_next_header (ip1);
     546           2 :       tcp1 = (tcp_header_t *) udp1;
     547             : 
     548           2 :       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
     549             : 
     550           2 :       if (PREDICT_FALSE (ip1->ttl == 1))
     551             :         {
     552           0 :           vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
     553           0 :           icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
     554             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     555             :                                        0);
     556           0 :           next1 = DET44_OUT2IN_NEXT_ICMP_ERROR;
     557           0 :           goto trace1;
     558             :         }
     559             : 
     560           2 :       proto1 = ip_proto_to_nat_proto (ip1->protocol);
     561             : 
     562           2 :       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
     563             :         {
     564             :           rx_fib_index1 =
     565           0 :             ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
     566           0 :           icmp1 = (icmp46_header_t *) udp1;
     567             : 
     568           0 :           next1 = det44_icmp_out2in (b1, ip1, icmp1, sw_if_index1,
     569             :                                      rx_fib_index1, node, next1,
     570             :                                      thread_index, &ses1, &mp1);
     571           0 :           goto trace1;
     572             :         }
     573             : 
     574           2 :       key1.ext_host_addr = ip1->src_address;
     575           2 :       key1.ext_host_port = tcp1->src;
     576           2 :       key1.out_port = tcp1->dst;
     577             : 
     578           2 :       mp1 = snat_det_map_by_out (&ip1->dst_address);
     579           2 :       if (PREDICT_FALSE (!mp1))
     580             :         {
     581           0 :           det44_log_info ("unknown dst address:  %U",
     582             :                           format_ip4_address, &ip1->dst_address);
     583           0 :           next1 = DET44_OUT2IN_NEXT_DROP;
     584           0 :           b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     585           0 :           goto trace1;
     586             :         }
     587             : 
     588           2 :       snat_det_reverse (mp1, &ip1->dst_address,
     589           2 :                         clib_net_to_host_u16 (tcp1->dst), &new_addr1);
     590             : 
     591           2 :       ses1 = snat_det_get_ses_by_out (mp1, &new_addr1, key1.as_u64);
     592           2 :       if (PREDICT_FALSE (!ses1))
     593             :         {
     594           0 :           det44_log_info ("no match src %U:%d dst %U:%d for user %U",
     595             :                           format_ip4_address, &ip1->src_address,
     596             :                           clib_net_to_host_u16 (tcp1->src),
     597             :                           format_ip4_address, &ip1->dst_address,
     598             :                           clib_net_to_host_u16 (tcp1->dst),
     599             :                           format_ip4_address, &new_addr1);
     600           0 :           next1 = DET44_OUT2IN_NEXT_DROP;
     601           0 :           b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     602           0 :           goto trace1;
     603             :         }
     604           2 :       old_port1 = udp1->dst_port;
     605           2 :       udp1->dst_port = new_port1 = ses1->in_port;
     606             : 
     607           2 :       old_addr1 = ip1->dst_address;
     608           2 :       ip1->dst_address = new_addr1;
     609           2 :       vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
     610             : 
     611           2 :       sum1 = ip1->checksum;
     612           2 :       sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
     613             :                              ip4_header_t, dst_address /* changed member */ );
     614           2 :       ip1->checksum = ip_csum_fold (sum1);
     615             : 
     616           2 :       if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
     617             :         {
     618           1 :           if (tcp1->flags & TCP_FLAG_FIN
     619           1 :               && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
     620           0 :             ses1->state = DET44_SESSION_TCP_CLOSE_WAIT;
     621           1 :           else if (tcp1->flags & TCP_FLAG_ACK
     622           0 :                    && ses1->state == DET44_SESSION_TCP_LAST_ACK)
     623           0 :             snat_det_ses_close (mp1, ses1);
     624             : 
     625           1 :           sum1 = tcp1->checksum;
     626           1 :           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
     627             :                                  ip4_header_t,
     628             :                                  dst_address /* changed member */ );
     629           1 :           sum1 = ip_csum_update (sum1, old_port1, new_port1,
     630             :                                  ip4_header_t /* cheat */ ,
     631             :                                  length /* changed member */ );
     632           1 :           tcp1->checksum = ip_csum_fold (sum1);
     633             :         }
     634           1 :       else if (udp1->checksum)
     635             :         {
     636           1 :           sum1 = udp1->checksum;
     637           1 :           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
     638             :                                  ip4_header_t,
     639             :                                  dst_address /* changed member */ );
     640           1 :           sum1 = ip_csum_update (sum1, old_port1, new_port1,
     641             :                                  ip4_header_t /* cheat */ ,
     642             :                                  length /* changed member */ );
     643           1 :           udp1->checksum = ip_csum_fold (sum1);
     644             :         }
     645             : 
     646           0 :     trace1:
     647             : 
     648           2 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     649             :                          && (b1->flags & VLIB_BUFFER_IS_TRACED)))
     650             :         {
     651             :           det44_out2in_trace_t *t =
     652           2 :             vlib_add_trace (vm, node, b1, sizeof (*t));
     653           2 :           t->sw_if_index = sw_if_index1;
     654           2 :           t->next_index = next1;
     655           2 :           t->session_index = ~0;
     656           2 :           if (ses1)
     657           2 :             t->session_index = ses1 - mp1->sessions;
     658             :         }
     659             : 
     660           2 :       pkts_processed += next1 != DET44_OUT2IN_NEXT_DROP;
     661             : 
     662           2 :       n_left_from -= 2;
     663           2 :       next[0] = next0;
     664           2 :       next[1] = next1;
     665           2 :       next += 2;
     666             :     }
     667             : 
     668          17 :   while (n_left_from > 0)
     669             :     {
     670             :       vlib_buffer_t *b0;
     671           8 :       u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
     672             :       u32 sw_if_index0;
     673             :       ip4_header_t *ip0;
     674             :       ip_csum_t sum0;
     675             :       ip4_address_t new_addr0, old_addr0;
     676             :       u16 new_port0, old_port0;
     677             :       udp_header_t *udp0;
     678             :       tcp_header_t *tcp0;
     679             :       u32 proto0;
     680             :       snat_det_out_key_t key0;
     681             :       snat_det_map_t *mp0;
     682           8 :       snat_det_session_t *ses0 = 0;
     683             :       u32 rx_fib_index0;
     684             :       icmp46_header_t *icmp0;
     685             : 
     686           8 :       b0 = *b;
     687           8 :       b++;
     688             : 
     689           8 :       ip0 = vlib_buffer_get_current (b0);
     690           8 :       udp0 = ip4_next_header (ip0);
     691           8 :       tcp0 = (tcp_header_t *) udp0;
     692             : 
     693           8 :       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     694             : 
     695           8 :       if (PREDICT_FALSE (ip0->ttl == 1))
     696             :         {
     697           0 :           vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
     698           0 :           icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
     699             :                                        ICMP4_time_exceeded_ttl_exceeded_in_transit,
     700             :                                        0);
     701           0 :           next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
     702           0 :           goto trace00;
     703             :         }
     704             : 
     705           8 :       proto0 = ip_proto_to_nat_proto (ip0->protocol);
     706             : 
     707           8 :       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
     708             :         {
     709             :           rx_fib_index0 =
     710           1 :             ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     711           1 :           icmp0 = (icmp46_header_t *) udp0;
     712             : 
     713           1 :           next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
     714             :                                      rx_fib_index0, node, next0,
     715             :                                      thread_index, &ses0, &mp0);
     716           1 :           goto trace00;
     717             :         }
     718             : 
     719           7 :       key0.ext_host_addr = ip0->src_address;
     720           7 :       key0.ext_host_port = tcp0->src;
     721           7 :       key0.out_port = tcp0->dst;
     722             : 
     723           7 :       mp0 = snat_det_map_by_out (&ip0->dst_address);
     724           7 :       if (PREDICT_FALSE (!mp0))
     725             :         {
     726           0 :           det44_log_info ("unknown dst address:  %U",
     727             :                           format_ip4_address, &ip0->dst_address);
     728           0 :           next0 = DET44_OUT2IN_NEXT_DROP;
     729           0 :           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     730           0 :           goto trace00;
     731             :         }
     732             : 
     733           7 :       snat_det_reverse (mp0, &ip0->dst_address,
     734           7 :                         clib_net_to_host_u16 (tcp0->dst), &new_addr0);
     735             : 
     736           7 :       ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
     737           7 :       if (PREDICT_FALSE (!ses0))
     738             :         {
     739           0 :           det44_log_info ("no match src %U:%d dst %U:%d for user %U",
     740             :                           format_ip4_address, &ip0->src_address,
     741             :                           clib_net_to_host_u16 (tcp0->src),
     742             :                           format_ip4_address, &ip0->dst_address,
     743             :                           clib_net_to_host_u16 (tcp0->dst),
     744             :                           format_ip4_address, &new_addr0);
     745           0 :           next0 = DET44_OUT2IN_NEXT_DROP;
     746           0 :           b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
     747           0 :           goto trace00;
     748             :         }
     749           7 :       old_port0 = udp0->dst_port;
     750           7 :       udp0->dst_port = new_port0 = ses0->in_port;
     751             : 
     752           7 :       old_addr0 = ip0->dst_address;
     753           7 :       ip0->dst_address = new_addr0;
     754           7 :       vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
     755             : 
     756           7 :       sum0 = ip0->checksum;
     757           7 :       sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
     758             :                              ip4_header_t, dst_address /* changed member */ );
     759           7 :       ip0->checksum = ip_csum_fold (sum0);
     760             : 
     761           7 :       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
     762             :         {
     763           7 :           if (tcp0->flags & TCP_FLAG_FIN
     764           1 :               && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
     765           1 :             ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
     766           6 :           else if (tcp0->flags & TCP_FLAG_ACK
     767           4 :                    && ses0->state == DET44_SESSION_TCP_LAST_ACK)
     768           1 :             snat_det_ses_close (mp0, ses0);
     769             : 
     770           7 :           sum0 = tcp0->checksum;
     771           7 :           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
     772             :                                  ip4_header_t,
     773             :                                  dst_address /* changed member */ );
     774           7 :           sum0 = ip_csum_update (sum0, old_port0, new_port0,
     775             :                                  ip4_header_t /* cheat */ ,
     776             :                                  length /* changed member */ );
     777           7 :           tcp0->checksum = ip_csum_fold (sum0);
     778             :         }
     779           0 :       else if (udp0->checksum)
     780             :         {
     781           0 :           sum0 = udp0->checksum;
     782           0 :           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
     783             :                                  ip4_header_t,
     784             :                                  dst_address /* changed member */ );
     785           0 :           sum0 = ip_csum_update (sum0, old_port0, new_port0,
     786             :                                  ip4_header_t /* cheat */ ,
     787             :                                  length /* changed member */ );
     788           0 :           udp0->checksum = ip_csum_fold (sum0);
     789             :         }
     790             : 
     791           0 :     trace00:
     792             : 
     793           8 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     794             :                          && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     795             :         {
     796             :           det44_out2in_trace_t *t =
     797           8 :             vlib_add_trace (vm, node, b0, sizeof (*t));
     798           8 :           t->sw_if_index = sw_if_index0;
     799           8 :           t->next_index = next0;
     800           8 :           t->session_index = ~0;
     801           8 :           if (ses0)
     802           8 :             t->session_index = ses0 - mp0->sessions;
     803             :         }
     804             : 
     805           8 :       pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
     806             : 
     807           8 :       n_left_from--;
     808           8 :       next[0] = next0;
     809           8 :       next++;
     810             :     }
     811           9 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
     812           9 :                                frame->n_vectors);
     813             : 
     814             : 
     815           9 :   vlib_node_increment_counter (vm, dm->out2in_node_index,
     816             :                                DET44_OUT2IN_ERROR_OUT2IN_PACKETS,
     817             :                                pkts_processed);
     818           9 :   return frame->n_vectors;
     819             : }
     820             : 
     821             : /* *INDENT-OFF* */
     822      161324 : VLIB_REGISTER_NODE (det44_out2in_node) = {
     823             :   .name = "det44-out2in",
     824             :   .vector_size = sizeof (u32),
     825             :   .format_trace = format_det44_out2in_trace,
     826             :   .type = VLIB_NODE_TYPE_INTERNAL,
     827             :   .n_errors = ARRAY_LEN(det44_out2in_error_strings),
     828             :   .error_strings = det44_out2in_error_strings,
     829             :   .runtime_data_bytes = sizeof (det44_runtime_t),
     830             :   .n_next_nodes = DET44_OUT2IN_N_NEXT,
     831             :   /* edit / add dispositions here */
     832             :   .next_nodes = {
     833             :     [DET44_OUT2IN_NEXT_DROP] = "error-drop",
     834             :     [DET44_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
     835             :     [DET44_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     836             :   },
     837             : };
     838             : /* *INDENT-ON* */
     839             : 
     840             : /*
     841             :  * fd.io coding-style-patch-verification: ON
     842             :  *
     843             :  * Local Variables:
     844             :  * eval: (c-set-style "gnu")
     845             :  * End:
     846             :  */

Generated by: LCOV version 1.14