LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ed - nat44_ed_inlines.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 395 408 96.8 %
Date: 2023-10-26 01:39:38 Functions: 40 40 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : /**
      17             :  * @brief The NAT inline functions
      18             :  */
      19             : 
      20             : #ifndef __included_nat44_ed_inlines_h__
      21             : #define __included_nat44_ed_inlines_h__
      22             : 
      23             : #include <float.h>
      24             : #include <vppinfra/clib.h>
      25             : #include <vnet/fib/ip4_fib.h>
      26             : 
      27             : #include <nat/lib/log.h>
      28             : #include <nat/lib/ipfix_logging.h>
      29             : #include <nat/nat44-ed/nat44_ed.h>
      30             : 
      31             : always_inline void
      32      546953 : init_ed_k (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr,
      33             :            u16 r_port, u32 fib_index, ip_protocol_t proto)
      34             : {
      35      546953 :   kv->key[0] = (u64) r_addr << 32 | l_addr;
      36      546953 :   kv->key[1] =
      37      546953 :     (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
      38      546953 : }
      39             : 
      40             : always_inline void
      41      286498 : init_ed_kv (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr,
      42             :             u16 r_port, u32 fib_index, u8 proto, u32 thread_index,
      43             :             u32 session_index)
      44             : {
      45      286498 :   init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto);
      46      286508 :   kv->value = (u64) thread_index << 32 | session_index;
      47      286508 : }
      48             : 
      49             : always_inline void
      50       56874 : nat44_ed_sm_init_i2o_kv (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
      51             :                          u32 fib_index, u8 proto, u32 sm_index)
      52             : {
      53       56874 :   return init_ed_kv (kv, addr, port, 0, 0, fib_index, proto, 0, sm_index);
      54             : }
      55             : 
      56             : always_inline void
      57      157487 : nat44_ed_sm_init_o2i_kv (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port,
      58             :                          u32 fib_index, u8 proto, u32 sm_index)
      59             : {
      60      157487 :   return init_ed_kv (kv, 0, 0, e_addr, e_port, fib_index, proto, 0, sm_index);
      61             : }
      62             : 
      63             : always_inline void
      64       56827 : nat44_ed_sm_init_i2o_k (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port,
      65             :                         u32 fib_index, u8 proto)
      66             : {
      67       56827 :   return nat44_ed_sm_init_i2o_kv (kv, addr, port, fib_index, proto, 0);
      68             : }
      69             : 
      70             : always_inline void
      71      157429 : nat44_ed_sm_init_o2i_k (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port,
      72             :                         u32 fib_index, u8 proto)
      73             : {
      74      157429 :   return nat44_ed_sm_init_o2i_kv (kv, e_addr, e_port, fib_index, proto, 0);
      75             : }
      76             : 
      77             : always_inline u32
      78        9590 : ed_value_get_thread_index (clib_bihash_kv_16_8_t *value)
      79             : {
      80        9590 :   return value->value >> 32;
      81             : }
      82             : 
      83             : always_inline u32
      84        8308 : ed_value_get_session_index (clib_bihash_kv_16_8_t *value)
      85             : {
      86        8308 :   return value->value & ~(u32) 0;
      87             : }
      88             : 
      89             : always_inline void
      90        2725 : split_ed_kv (clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr,
      91             :              ip4_address_t *r_addr, u8 *proto, u32 *fib_index, u16 *l_port,
      92             :              u16 *r_port)
      93             : {
      94        2725 :   if (l_addr)
      95             :     {
      96        2725 :       l_addr->as_u32 = kv->key[0] & (u32) ~0;
      97             :     }
      98        2725 :   if (r_addr)
      99             :     {
     100        2725 :       r_addr->as_u32 = kv->key[0] >> 32;
     101             :     }
     102        2725 :   if (r_port)
     103             :     {
     104        2725 :       *r_port = kv->key[1] >> 48;
     105             :     }
     106        2725 :   if (l_port)
     107             :     {
     108        2725 :       *l_port = (kv->key[1] >> 32) & (u16) ~0;
     109             :     }
     110        2725 :   if (fib_index)
     111             :     {
     112        2725 :       *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
     113             :     }
     114        2725 :   if (proto)
     115             :     {
     116        2725 :       *proto = kv->key[1] & (u8) ~0;
     117             :     }
     118        2725 : }
     119             : 
     120             : static_always_inline int
     121       22928 : nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0,
     122             :                                     ip4_address_t *lookup_saddr,
     123             :                                     u16 *lookup_sport,
     124             :                                     ip4_address_t *lookup_daddr,
     125             :                                     u16 *lookup_dport, u8 *lookup_protocol)
     126             : {
     127             :   icmp46_header_t *icmp0;
     128       22928 :   nat_icmp_echo_header_t *echo0, *inner_echo0 = 0;
     129       22928 :   ip4_header_t *inner_ip0 = 0;
     130       22928 :   void *l4_header = 0;
     131             :   icmp46_header_t *inner_icmp0;
     132             : 
     133       22928 :   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
     134       22922 :   echo0 = (nat_icmp_echo_header_t *) (icmp0 + 1);
     135             : 
     136             :   // avoid warning about unused variables in caller by setting to bogus values
     137       22922 :   *lookup_sport = 0;
     138       22922 :   *lookup_dport = 0;
     139             : 
     140       22929 :   if (!icmp_type_is_error_message (
     141       22922 :         vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
     142             :     {
     143       22912 :       *lookup_protocol = IP_PROTOCOL_ICMP;
     144       22912 :       lookup_saddr->as_u32 = ip0->src_address.as_u32;
     145       22912 :       *lookup_sport = vnet_buffer (b)->ip.reass.l4_src_port;
     146       22912 :       lookup_daddr->as_u32 = ip0->dst_address.as_u32;
     147       22912 :       *lookup_dport = vnet_buffer (b)->ip.reass.l4_dst_port;
     148             :     }
     149             :   else
     150             :     {
     151          17 :       inner_ip0 = (ip4_header_t *) (echo0 + 1);
     152          17 :       l4_header = ip4_next_header (inner_ip0);
     153          17 :       *lookup_protocol = inner_ip0->protocol;
     154          17 :       lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32;
     155          17 :       lookup_daddr->as_u32 = inner_ip0->src_address.as_u32;
     156          17 :       switch (inner_ip0->protocol)
     157             :         {
     158           3 :         case IP_PROTOCOL_ICMP:
     159           3 :           inner_icmp0 = (icmp46_header_t *) l4_header;
     160           3 :           inner_echo0 = (nat_icmp_echo_header_t *) (inner_icmp0 + 1);
     161           3 :           *lookup_sport = inner_echo0->identifier;
     162           3 :           *lookup_dport = inner_echo0->identifier;
     163           3 :           break;
     164          14 :         case IP_PROTOCOL_UDP:
     165             :         case IP_PROTOCOL_TCP:
     166          14 :           *lookup_sport = ((nat_tcp_udp_header_t *) l4_header)->dst_port;
     167          14 :           *lookup_dport = ((nat_tcp_udp_header_t *) l4_header)->src_port;
     168          14 :           break;
     169           0 :         default:
     170           0 :           return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
     171             :         }
     172             :     }
     173       22929 :   return 0;
     174             : }
     175             : 
     176             : always_inline int
     177       11742 : nat44_ed_tcp_is_established (nat44_ed_tcp_state_e state)
     178             : {
     179       11742 :   return state == NAT44_ED_TCP_STATE_ESTABLISHED ? 1 : 0;
     180             : }
     181             : 
     182             : always_inline u32
     183       61168 : nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
     184             : {
     185       61168 :   switch (s->proto)
     186             :     {
     187        6238 :     case IP_PROTOCOL_ICMP:
     188             :       /* fallthrough */
     189             :     case IP_PROTOCOL_ICMP6:
     190        6238 :       return sm->timeouts.icmp;
     191       43194 :     case IP_PROTOCOL_UDP:
     192       43194 :       return sm->timeouts.udp;
     193       11742 :     case IP_PROTOCOL_TCP:
     194             :       {
     195       11742 :         if (nat44_ed_tcp_is_established (s->tcp_state))
     196        5022 :           return sm->timeouts.tcp.established;
     197             :         else
     198        6720 :           return sm->timeouts.tcp.transitory;
     199             :       }
     200           0 :     default:
     201           0 :       return sm->timeouts.udp;
     202             :     }
     203             : 
     204             :   return 0;
     205             : }
     206             : 
     207             : static_always_inline u8
     208       28705 : nat44_ed_maximum_sessions_exceeded (snat_main_t *sm, u32 fib_index,
     209             :                                     u32 thread_index)
     210             : {
     211             :   u32 translations;
     212       28705 :   translations = pool_elts (sm->per_thread_data[thread_index].sessions);
     213       28704 :   if (vec_len (sm->max_translations_per_fib) <= fib_index)
     214          15 :     fib_index = 0;
     215       28703 :   return translations >= sm->max_translations_per_fib[fib_index];
     216             : }
     217             : 
     218             : static_always_inline int
     219       28693 : nat_ed_lru_insert (snat_main_per_thread_data_t *tsm, snat_session_t *s,
     220             :                    f64 now, u8 proto)
     221             : {
     222             :   dlist_elt_t *lru_list_elt;
     223       28693 :   pool_get (tsm->lru_pool, lru_list_elt);
     224       28693 :   s->lru_index = lru_list_elt - tsm->lru_pool;
     225       28693 :   switch (proto)
     226             :     {
     227       20212 :     case IP_PROTOCOL_UDP:
     228       20212 :       s->lru_head_index = tsm->udp_lru_head_index;
     229       20212 :       break;
     230        1895 :     case IP_PROTOCOL_TCP:
     231        1895 :       s->lru_head_index = tsm->tcp_trans_lru_head_index;
     232        1895 :       break;
     233        6584 :     case IP_PROTOCOL_ICMP:
     234        6584 :       s->lru_head_index = tsm->icmp_lru_head_index;
     235        6584 :       break;
     236           2 :     default:
     237           2 :       s->lru_head_index = tsm->unk_proto_lru_head_index;
     238           2 :       break;
     239             :     }
     240       28693 :   clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
     241       28692 :   lru_list_elt->value = s - tsm->sessions;
     242       28692 :   s->last_lru_update = now;
     243       28692 :   return 1;
     244             : }
     245             : 
     246             : static_always_inline void
     247      113497 : nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
     248             : {
     249      113497 :   init_ed_k (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32,
     250      113497 :              f->match.dport, f->match.fib_index, f->match.proto);
     251      113497 : }
     252             : 
     253             : static_always_inline void
     254       71587 : nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f,
     255             :                       u32 thread_idx, u32 session_idx)
     256             : {
     257       71587 :   init_ed_kv (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32,
     258       71587 :               f->match.dport, f->match.fib_index, f->match.proto, thread_idx,
     259             :               session_idx);
     260       71585 : }
     261             : 
     262             : static_always_inline int
     263       85297 : nat_ed_ses_i2o_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
     264             :                                   snat_session_t *s, int is_add)
     265             : {
     266       85297 :   snat_main_per_thread_data_t *tsm =
     267       85297 :     vec_elt_at_index (sm->per_thread_data, thread_idx);
     268             :   clib_bihash_kv_16_8_t kv;
     269       85297 :   if (0 == is_add)
     270             :     {
     271       56743 :       nat_6t_flow_to_ed_k (&kv, &s->i2o);
     272             :     }
     273             :   else
     274             :     {
     275       28554 :       nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
     276       28554 :       nat_6t_l3_l4_csum_calc (&s->i2o);
     277             :     }
     278             : 
     279       85297 :   ASSERT (thread_idx == s->thread_index);
     280       85297 :   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
     281             : }
     282             : 
     283             : static_always_inline int
     284       99782 : nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
     285             :                                   snat_session_t *s, int is_add)
     286             : {
     287       99782 :   snat_main_per_thread_data_t *tsm =
     288       99782 :     vec_elt_at_index (sm->per_thread_data, thread_idx);
     289             :   clib_bihash_kv_16_8_t kv;
     290       99782 :   if (0 == is_add)
     291             :     {
     292       56743 :       nat_6t_flow_to_ed_k (&kv, &s->o2i);
     293             :     }
     294             :   else
     295             :     {
     296       43039 :       nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
     297       43038 :       if (!(s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
     298             :         {
     299       42734 :           if (nat44_ed_sm_o2i_lookup (sm, s->o2i.match.daddr,
     300       42734 :                                       s->o2i.match.dport, 0,
     301       42734 :                                       s->o2i.match.proto))
     302             :             {
     303           1 :               return -1;
     304             :             }
     305             :         }
     306       43037 :       nat_6t_l3_l4_csum_calc (&s->o2i);
     307             :     }
     308       99780 :   ASSERT (thread_idx == s->thread_index);
     309       99780 :   return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
     310             : }
     311             : 
     312             : always_inline void
     313       28441 : nat_ed_session_delete (snat_main_t *sm, snat_session_t *ses, u32 thread_index,
     314             :                        int lru_delete
     315             :                        /* delete from global LRU list */)
     316             : {
     317       28441 :   snat_main_per_thread_data_t *tsm =
     318       28441 :     vec_elt_at_index (sm->per_thread_data, thread_index);
     319             : 
     320       28441 :   if (lru_delete)
     321             :     {
     322       23442 :       clib_dlist_remove (tsm->lru_pool, ses->lru_index);
     323             :     }
     324       28441 :   pool_put_index (tsm->lru_pool, ses->lru_index);
     325       28441 :   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, ses, 0))
     326       28441 :     nat_elog_warn (sm, "flow hash del failed");
     327       28441 :   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, ses, 0))
     328       28441 :     nat_elog_warn (sm, "flow hash del failed");
     329       28441 :   pool_put (tsm->sessions, ses);
     330       28441 :   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
     331       28441 :                            pool_elts (tsm->sessions));
     332       28441 : }
     333             : 
     334             : static_always_inline int
     335      128466 : nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now,
     336             :                             u32 head_index)
     337             : {
     338      128466 :   snat_session_t *s = NULL;
     339             :   dlist_elt_t *oldest_elt;
     340             :   f64 sess_timeout_time;
     341             :   u32 oldest_index;
     342      128466 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     343      128466 :   oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
     344      128460 :   if (~0 != oldest_index)
     345             :     {
     346       42892 :       oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
     347       42893 :       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
     348             : 
     349       42893 :       sess_timeout_time =
     350       42893 :         s->last_heard + (f64) nat44_session_get_timeout (sm, s);
     351       42893 :       if (now >= sess_timeout_time)
     352             :         {
     353        4999 :           nat44_ed_free_session_data (sm, s, thread_index, 0);
     354        4999 :           nat_ed_session_delete (sm, s, thread_index, 0);
     355        4999 :           return 1;
     356             :         }
     357             :       else
     358             :         {
     359       37894 :           clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
     360             :         }
     361             :     }
     362      123464 :   return 0;
     363             : }
     364             : 
     365             : static_always_inline int
     366       28698 : nat_lru_free_one (snat_main_t *sm, int thread_index, f64 now)
     367             : {
     368       28698 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     369       28698 :   int rc = 0;
     370             : #define _(p)                                                                  \
     371             :   if ((rc = nat_lru_free_one_with_head (sm, thread_index, now,                \
     372             :                                         tsm->p##_lru_head_index)))            \
     373             :     {                                                                         \
     374             :       return rc;                                                              \
     375             :     }
     376       28698 :   _ (tcp_trans);
     377       28695 :   _ (udp);
     378       23696 :   _ (unk_proto);
     379       23697 :   _ (icmp);
     380       23700 :   _ (tcp_estab);
     381             : #undef _
     382       23701 :   return 0;
     383             : }
     384             : 
     385             : static_always_inline snat_session_t *
     386       28692 : nat_ed_session_alloc (snat_main_t *sm, u32 thread_index, f64 now, u8 proto)
     387             : {
     388             :   snat_session_t *s;
     389       28692 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     390             : 
     391       28692 :   nat_lru_free_one (sm, thread_index, now);
     392             : 
     393       28694 :   pool_get (tsm->sessions, s);
     394       28693 :   clib_memset (s, 0, sizeof (*s));
     395             : 
     396       28693 :   nat_ed_lru_insert (tsm, s, now, proto);
     397             : 
     398       28692 :   s->ha_last_refreshed = now;
     399       28693 :   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
     400       28692 :                            pool_elts (tsm->sessions));
     401             : #if CLIB_ASSERT_ENABLE
     402       28693 :   s->thread_index = thread_index;
     403             : #endif
     404       28693 :   return s;
     405             : }
     406             : 
     407             : // slow path
     408             : static_always_inline void
     409       28554 : per_vrf_sessions_cleanup (u32 thread_index)
     410             : {
     411       28554 :   snat_main_t *sm = &snat_main;
     412       28554 :   snat_main_per_thread_data_t *tsm =
     413       28554 :     vec_elt_at_index (sm->per_thread_data, thread_index);
     414             :   per_vrf_sessions_t *per_vrf_sessions;
     415       28554 :   u32 *to_free = 0, *i;
     416             : 
     417       57015 :   pool_foreach (per_vrf_sessions, tsm->per_vrf_sessions_pool)
     418             :     {
     419       28461 :       if (per_vrf_sessions->expired && per_vrf_sessions->ses_count == 0)
     420           0 :         vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_pool);
     421             :     }
     422             : 
     423       28555 :   vec_foreach (i, to_free)
     424             :     {
     425           0 :       per_vrf_sessions = pool_elt_at_index (tsm->per_vrf_sessions_pool, *i);
     426           0 :       pool_put (tsm->per_vrf_sessions_pool, per_vrf_sessions);
     427             :     }
     428             : 
     429       28555 :   vec_free (to_free);
     430       28555 : }
     431             : 
     432             : // slow path
     433             : static_always_inline void
     434       28554 : per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index)
     435             : {
     436       28554 :   snat_main_t *sm = &snat_main;
     437       28554 :   snat_main_per_thread_data_t *tsm =
     438       28554 :     vec_elt_at_index (sm->per_thread_data, thread_index);
     439             :   per_vrf_sessions_t *per_vrf_sessions;
     440             : 
     441       28554 :   per_vrf_sessions_cleanup (thread_index);
     442             : 
     443             :   // s->per_vrf_sessions_index == ~0 ... reuse of old session
     444             : 
     445       28555 :   pool_foreach (per_vrf_sessions, tsm->per_vrf_sessions_pool)
     446             :     {
     447             :       // ignore already expired registrations
     448       28461 :       if (per_vrf_sessions->expired)
     449           0 :         continue;
     450             : 
     451       28461 :       if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
     452       28461 :           (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
     453             :         {
     454       28461 :           goto done;
     455             :         }
     456           0 :       if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
     457           0 :           (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
     458             :         {
     459           0 :           goto done;
     460             :         }
     461             :     }
     462             : 
     463             :   // create a new registration
     464          93 :   pool_get (tsm->per_vrf_sessions_pool, per_vrf_sessions);
     465          94 :   clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions));
     466          94 :   per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
     467          94 :   per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
     468             : 
     469       28555 : done:
     470       28555 :   s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_pool;
     471       28555 :   per_vrf_sessions->ses_count++;
     472       28555 : }
     473             : 
     474             : // fast path
     475             : static_always_inline void
     476       28302 : per_vrf_sessions_unregister_session (snat_session_t *s, u32 thread_index)
     477             : {
     478       28302 :   snat_main_t *sm = &snat_main;
     479             :   snat_main_per_thread_data_t *tsm;
     480             :   per_vrf_sessions_t *per_vrf_sessions;
     481             : 
     482       28302 :   ASSERT (s->per_vrf_sessions_index != ~0);
     483             : 
     484       28302 :   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
     485       28302 :   per_vrf_sessions =
     486       28302 :     pool_elt_at_index (tsm->per_vrf_sessions_pool, s->per_vrf_sessions_index);
     487             : 
     488       28302 :   ASSERT (per_vrf_sessions->ses_count != 0);
     489             : 
     490       28302 :   per_vrf_sessions->ses_count--;
     491       28302 :   s->per_vrf_sessions_index = ~0;
     492       28302 : }
     493             : 
     494             : // fast path
     495             : static_always_inline u8
     496        4960 : per_vrf_sessions_is_expired (snat_session_t *s, u32 thread_index)
     497             : {
     498        4960 :   snat_main_t *sm = &snat_main;
     499             :   snat_main_per_thread_data_t *tsm;
     500             :   per_vrf_sessions_t *per_vrf_sessions;
     501             : 
     502        4960 :   ASSERT (s->per_vrf_sessions_index != ~0);
     503             : 
     504        4960 :   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
     505        4959 :   per_vrf_sessions =
     506        4959 :     pool_elt_at_index (tsm->per_vrf_sessions_pool, s->per_vrf_sessions_index);
     507        4959 :   return per_vrf_sessions->expired;
     508             : }
     509             : 
     510             : static_always_inline void
     511       57211 : nat_6t_flow_init (nat_6t_flow_t *f, u32 thread_idx, ip4_address_t saddr,
     512             :                   u16 sport, ip4_address_t daddr, u16 dport, u32 fib_index,
     513             :                   u8 proto, u32 session_idx)
     514             : {
     515       57211 :   clib_memset (f, 0, sizeof (*f));
     516       57211 :   f->match.saddr = saddr;
     517       57211 :   f->match.sport = sport;
     518       57211 :   f->match.daddr = daddr;
     519       57211 :   f->match.dport = dport;
     520       57211 :   f->match.proto = proto;
     521       57211 :   f->match.fib_index = fib_index;
     522       57211 : }
     523             : 
     524             : static_always_inline void
     525       28554 : nat_6t_i2o_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
     526             :                       ip4_address_t saddr, u16 sport, ip4_address_t daddr,
     527             :                       u16 dport, u32 fib_index, u8 proto)
     528             : {
     529       28554 :   snat_main_per_thread_data_t *tsm =
     530       28554 :     vec_elt_at_index (sm->per_thread_data, thread_idx);
     531       28554 :   nat_6t_flow_init (&s->i2o, thread_idx, saddr, sport, daddr, dport, fib_index,
     532       28554 :                     proto, s - tsm->sessions);
     533       28554 : }
     534             : 
     535             : static_always_inline void
     536       28659 : nat_6t_o2i_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
     537             :                       ip4_address_t saddr, u16 sport, ip4_address_t daddr,
     538             :                       u16 dport, u32 fib_index, u8 proto)
     539             : {
     540       28659 :   snat_main_per_thread_data_t *tsm =
     541       28659 :     vec_elt_at_index (sm->per_thread_data, thread_idx);
     542       28659 :   nat_6t_flow_init (&s->o2i, thread_idx, saddr, sport, daddr, dport, fib_index,
     543       28659 :                     proto, s - tsm->sessions);
     544       28659 : }
     545             : 
     546             : static_always_inline int
     547       33814 : nat_6t_t_eq (nat_6t_t *t1, nat_6t_t *t2)
     548             : {
     549       33814 :   return t1->as_u64[0] == t2->as_u64[0] && t1->as_u64[1] == t2->as_u64[1];
     550             : }
     551             : 
     552             : static inline uword
     553          65 : nat_pre_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     554             :                         vlib_frame_t *frame, u32 def_next)
     555             : {
     556             :   u32 n_left_from, *from;
     557             : 
     558          65 :   from = vlib_frame_vector_args (frame);
     559          65 :   n_left_from = frame->n_vectors;
     560             : 
     561          65 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
     562          65 :   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
     563          65 :   vlib_get_buffers (vm, from, b, n_left_from);
     564             : 
     565         206 :   while (n_left_from >= 2)
     566             :     {
     567             :       u32 next0, next1;
     568             :       u32 arc_next0, arc_next1;
     569             :       vlib_buffer_t *b0, *b1;
     570             : 
     571         141 :       b0 = *b;
     572         141 :       b++;
     573         141 :       b1 = *b;
     574         141 :       b++;
     575             : 
     576             :       /* Prefetch next iteration. */
     577         141 :       if (PREDICT_TRUE (n_left_from >= 4))
     578             :         {
     579             :           vlib_buffer_t *p2, *p3;
     580             : 
     581         112 :           p2 = *b;
     582         112 :           p3 = *(b + 1);
     583             : 
     584         112 :           vlib_prefetch_buffer_header (p2, LOAD);
     585         112 :           vlib_prefetch_buffer_header (p3, LOAD);
     586             : 
     587         112 :           clib_prefetch_load (p2->data);
     588         112 :           clib_prefetch_load (p3->data);
     589             :         }
     590             : 
     591         141 :       next0 = def_next;
     592         141 :       next1 = def_next;
     593             : 
     594         141 :       vnet_feature_next (&arc_next0, b0);
     595         141 :       vnet_feature_next (&arc_next1, b1);
     596             : 
     597         141 :       vnet_buffer2 (b0)->nat.arc_next = arc_next0;
     598         141 :       vnet_buffer2 (b1)->nat.arc_next = arc_next1;
     599             : 
     600         141 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
     601             :         {
     602         141 :           if (b0->flags & VLIB_BUFFER_IS_TRACED)
     603             :             {
     604         141 :               nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
     605         141 :               t->next_index = next0;
     606         141 :               t->arc_next_index = arc_next0;
     607             :             }
     608         141 :           if (b1->flags & VLIB_BUFFER_IS_TRACED)
     609             :             {
     610         141 :               nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
     611         141 :               t->next_index = next1;
     612         141 :               t->arc_next_index = arc_next1;
     613             :             }
     614             :         }
     615             : 
     616         141 :       n_left_from -= 2;
     617         141 :       next[0] = next0;
     618         141 :       next[1] = next1;
     619         141 :       next += 2;
     620             :     }
     621             : 
     622         107 :   while (n_left_from > 0)
     623             :     {
     624             :       u32 next0;
     625             :       u32 arc_next0;
     626             :       vlib_buffer_t *b0;
     627             : 
     628          42 :       b0 = *b;
     629          42 :       b++;
     630             : 
     631          42 :       next0 = def_next;
     632          42 :       vnet_feature_next (&arc_next0, b0);
     633          42 :       vnet_buffer2 (b0)->nat.arc_next = arc_next0;
     634             : 
     635          42 :       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
     636             :                          (b0->flags & VLIB_BUFFER_IS_TRACED)))
     637             :         {
     638          42 :           nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
     639          42 :           t->next_index = next0;
     640          42 :           t->arc_next_index = arc_next0;
     641             :         }
     642             : 
     643          42 :       n_left_from--;
     644          42 :       next[0] = next0;
     645          42 :       next++;
     646             :     }
     647          65 :   vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
     648          65 :                                frame->n_vectors);
     649             : 
     650          65 :   return frame->n_vectors;
     651             : }
     652             : 
     653             : static_always_inline u16
     654       42708 : snat_random_port (u16 min, u16 max)
     655             : {
     656       42708 :   snat_main_t *sm = &snat_main;
     657             :   u32 rwide;
     658             :   u16 r;
     659             : 
     660       42708 :   rwide = random_u32 (&sm->random_seed);
     661       42708 :   r = rwide & 0xFFFF;
     662       42708 :   if (r >= min && r <= max)
     663       10585 :     return r;
     664             : 
     665       32123 :   return min + (rwide % (max - min + 1));
     666             : }
     667             : 
     668             : always_inline u8
     669       28355 : is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
     670             :                    u32 sw_if_index0, u32 ip4_addr)
     671             : {
     672       28355 :   snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
     673             :   u8 ip4_addr_exists;
     674             : 
     675       28355 :   if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
     676             :     {
     677          19 :       ip_lookup_main_t *lm = &sm->ip4_main->lookup_main;
     678             :       ip_interface_address_t *ia;
     679             :       ip4_address_t *a;
     680             : 
     681          19 :       rt->cached_sw_if_index = ~0;
     682          19 :       hash_free (rt->cached_presence_by_ip4_address);
     683             : 
     684          38 :       foreach_ip_interface_address (
     685             :         lm, ia, sw_if_index0, 1 /* honor unnumbered */, ({
     686             :           a = ip_interface_address_get_address (lm, ia);
     687             :           hash_set (rt->cached_presence_by_ip4_address, a->as_u32, 1);
     688             :           rt->cached_sw_if_index = sw_if_index0;
     689             :         }));
     690             : 
     691          19 :       if (rt->cached_sw_if_index == ~0)
     692           0 :         return 0;
     693             :     }
     694             : 
     695       28355 :   ip4_addr_exists = !!hash_get (rt->cached_presence_by_ip4_address, ip4_addr);
     696       28351 :   if (PREDICT_FALSE (ip4_addr_exists))
     697           0 :     return 1;
     698             :   else
     699       28351 :     return 0;
     700             : }
     701             : 
     702             : always_inline void
     703           2 : nat44_ed_session_reopen (u32 thread_index, snat_session_t *s)
     704             : {
     705           2 :   nat_syslog_nat44_sdel (0, s->in2out.fib_index, &s->in2out.addr,
     706           2 :                          s->in2out.port, &s->ext_host_nat_addr,
     707           2 :                          s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
     708           2 :                          &s->ext_host_addr, s->ext_host_port, s->proto,
     709           2 :                          nat44_ed_is_twice_nat_session (s));
     710             : 
     711           2 :   nat_ipfix_logging_nat44_ses_delete (
     712           2 :     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
     713           2 :     s->in2out.port, s->out2in.port, s->in2out.fib_index);
     714           2 :   nat_ipfix_logging_nat44_ses_create (
     715           2 :     thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
     716           2 :     s->in2out.port, s->out2in.port, s->in2out.fib_index);
     717             : 
     718           2 :   nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
     719           2 :                          s->in2out.port, &s->ext_host_nat_addr,
     720           2 :                          s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
     721           2 :                          &s->ext_host_addr, s->ext_host_port, s->proto, 0);
     722           2 :   s->total_pkts = 0;
     723           2 :   s->total_bytes = 0;
     724           2 : }
     725             : 
     726             : /*
     727             :  * "Some rise by SYN, and some by virtue FIN" - William Shakespeare
     728             :  * TCP state tracking patterned after RFC 7857 (and RFC 6146, which is
     729             :  * referenced by RFC 7857). In contrast to the state machine in RFC7857 we only
     730             :  * transition to ESTABLISHED state after seeing a full 3-way handshake (SYNs
     731             :  * and ACKs in both directions). RFC7857 as a means of protecting against
     732             :  * spurious RSTs closing a session, goes back to ESTABLISHED if a data packet
     733             :  * is received after the RST. This state machine will leave the state in
     734             :  * transitory if RST is seen. Our implementation also goes beyond by supporting
     735             :  * creation of a new session while old session is in transitory timeout after
     736             :  * seeing FIN packets from both sides.
     737             :  */
     738             : always_inline void
     739        3705 : nat44_set_tcp_session_state (snat_main_t *sm, f64 now, snat_session_t *ses,
     740             :                              u8 tcp_flags, u32 thread_index,
     741             :                              nat44_ed_dir_e dir)
     742             : {
     743        3705 :   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
     744        3705 :   u8 old_flags = ses->tcp_flags[dir];
     745        3705 :   ses->tcp_flags[dir] |=
     746        3705 :     tcp_flags & (TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK);
     747        3705 :   if (old_flags == ses->tcp_flags[dir])
     748         724 :     return;
     749             : 
     750        2981 :   u8 old_state = ses->tcp_state;
     751             : 
     752        2981 :   switch (old_state)
     753             :     {
     754        2946 :     case NAT44_ED_TCP_STATE_CLOSED:
     755             :       // ESTABLISHED when a SYN and ACK is seen from both sides
     756        2946 :       if ((ses->tcp_flags[NAT44_ED_DIR_I2O] &
     757        2946 :            ses->tcp_flags[NAT44_ED_DIR_O2I]) == (TCP_FLAG_SYN | TCP_FLAG_ACK))
     758             :         {
     759          14 :           ses->tcp_state = NAT44_ED_TCP_STATE_ESTABLISHED;
     760          14 :           ses->lru_head_index = tsm->tcp_estab_lru_head_index;
     761             :         }
     762        2946 :       break;
     763          11 :     case NAT44_ED_TCP_STATE_ESTABLISHED:
     764             :       // CLOSING when a FIN is seen from either side or session has been RST
     765          11 :       if ((ses->tcp_flags[dir] & TCP_FLAG_FIN) ||
     766           2 :           (ses->tcp_flags[dir] & TCP_FLAG_RST))
     767             :         {
     768          11 :           ses->tcp_state = NAT44_ED_TCP_STATE_CLOSING;
     769          11 :           ses->tcp_flags[NAT44_ED_DIR_I2O] = 0;
     770          11 :           ses->tcp_flags[NAT44_ED_DIR_O2I] = 0;
     771             :           // need to update last heard otherwise session might get
     772             :           // immediately timed out if it has been idle longer than
     773             :           // transitory timeout
     774          11 :           ses->last_heard = now;
     775          11 :           ses->lru_head_index = tsm->tcp_trans_lru_head_index;
     776             :         }
     777          11 :       break;
     778          24 :     case NAT44_ED_TCP_STATE_CLOSING:
     779             :       // Allow a transitory session to reopen
     780          24 :       if ((ses->tcp_flags[NAT44_ED_DIR_I2O] &
     781          24 :            ses->tcp_flags[NAT44_ED_DIR_O2I]) == (TCP_FLAG_SYN | TCP_FLAG_ACK))
     782             :         {
     783           2 :           nat44_ed_session_reopen (thread_index, ses);
     784           2 :           ses->tcp_state = NAT44_ED_TCP_STATE_ESTABLISHED;
     785           2 :           ses->lru_head_index = tsm->tcp_estab_lru_head_index;
     786             :         }
     787          24 :       break;
     788             :     }
     789        2981 :   if (old_state == ses->tcp_state)
     790        2954 :     return;
     791          27 :   ses->last_lru_update = now;
     792          27 :   clib_dlist_remove (tsm->lru_pool, ses->lru_index);
     793          27 :   clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
     794             : }
     795             : 
     796             : always_inline void
     797        1728 : nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
     798             :                                  u8 tcp_flags, u32 thread_index)
     799             : {
     800        1728 :   return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
     801             :                                       NAT44_ED_DIR_I2O);
     802             : }
     803             : 
     804             : always_inline void
     805        1977 : nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
     806             :                                  u8 tcp_flags, u32 thread_index)
     807             : {
     808        1977 :   return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
     809             :                                       NAT44_ED_DIR_O2I);
     810             : }
     811             : 
     812             : always_inline void
     813       33566 : nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes,
     814             :                                u32 thread_index)
     815             : {
     816             :   // regardless of TCP state, reset the timer if data packet is seen.
     817       33566 :   s->last_heard = now;
     818       33566 :   s->total_pkts++;
     819       33566 :   s->total_bytes += bytes;
     820       33566 : }
     821             : 
     822             : /** \brief Per-user LRU list maintenance */
     823             : always_inline void
     824       33566 : nat44_session_update_lru (snat_main_t *sm, snat_session_t *s, u32 thread_index)
     825             : {
     826             :   /* don't update too often - timeout is in magnitude of seconds anyway */
     827       33566 :   if (s->last_heard > s->last_lru_update + 1)
     828             :     {
     829        2862 :       clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
     830             :                          s->lru_index);
     831        2862 :       clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
     832             :                           s->lru_head_index, s->lru_index);
     833        2862 :       s->last_lru_update = s->last_heard;
     834             :     }
     835       33566 : }
     836             : 
     837             : static_always_inline int
     838       42435 : nat44_ed_is_unk_proto (u8 proto)
     839             : {
     840             :   static const int lookup_table[256] = {
     841             :     [IP_PROTOCOL_TCP] = 1,
     842             :     [IP_PROTOCOL_UDP] = 1,
     843             :     [IP_PROTOCOL_ICMP] = 1,
     844             :     [IP_PROTOCOL_ICMP6] = 1,
     845             :   };
     846             : 
     847       42435 :   return 1 - lookup_table[proto];
     848             : }
     849             : 
     850             : #endif /* __included_nat44_ed_inlines_h__ */
     851             : 
     852             : /*
     853             :  * fd.io coding-style-patch-verification: ON
     854             :  *
     855             :  * Local Variables:
     856             :  * eval: (c-set-style "gnu")
     857             :  * End:
     858             :  */

Generated by: LCOV version 1.14