LCOV - code coverage report
Current view: top level - plugins/nat/det44 - det44.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 64 69 92.8 %
Date: 2023-07-05 22:20:52 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * det44.h - deterministic NAT definitions
       3             :  *
       4             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : /**
      19             :  * @file
      20             :  * @brief Deterministic NAT (CGN) definitions
      21             :  */
      22             : 
      23             : #ifndef __included_det44_h__
      24             : #define __included_det44_h__
      25             : 
      26             : #include <vnet/vnet.h>
      27             : #include <vnet/ip/ip.h>
      28             : #include <vnet/ethernet/ethernet.h>
      29             : #include <vnet/ip/icmp46_packet.h>
      30             : #include <vnet/api_errno.h>
      31             : #include <vnet/fib/fib_source.h>
      32             : #include <vppinfra/dlist.h>
      33             : #include <vppinfra/error.h>
      34             : #include <vlibapi/api.h>
      35             : #include <vlib/log.h>
      36             : #include <vnet/fib/fib_table.h>
      37             : #include <vnet/fib/ip4_fib.h>
      38             : #include <vnet/ip/reass/ip4_sv_reass.h>
      39             : 
      40             : #include <nat/lib/lib.h>
      41             : #include <nat/lib/inlines.h>
      42             : #include <nat/lib/ipfix_logging.h>
      43             : #include <nat/lib/nat_proto.h>
      44             : 
      45             : /* Session state */
      46             : #define foreach_det44_session_state        \
      47             :   _(0, UNKNOWN, "unknown")                 \
      48             :   _(1, UDP_ACTIVE, "udp-active")           \
      49             :   _(2, TCP_SYN_SENT, "tcp-syn-sent")       \
      50             :   _(3, TCP_ESTABLISHED, "tcp-established") \
      51             :   _(4, TCP_FIN_WAIT, "tcp-fin-wait")       \
      52             :   _(5, TCP_CLOSE_WAIT, "tcp-close-wait")   \
      53             :   _(6, TCP_CLOSING, "tcp-closing")         \
      54             :   _(7, TCP_LAST_ACK, "tcp-last-ack")       \
      55             :   _(8, TCP_CLOSED, "tcp-closed")           \
      56             :   _(9, ICMP_ACTIVE, "icmp-active")
      57             : 
      58             : typedef enum
      59             : {
      60             : #define _(v, N, s) DET44_SESSION_##N = v,
      61             :   foreach_det44_session_state
      62             : #undef _
      63             : } det44_session_state_t;
      64             : 
      65             : #define DET44_SES_PER_USER 1000
      66             : 
      67             : typedef struct
      68             : {
      69             :   u16 identifier;
      70             :   u16 sequence;
      71             : } icmp_echo_header_t;
      72             : 
      73             : typedef struct
      74             : {
      75             :   u16 src_port, dst_port;
      76             : } tcp_udp_header_t;
      77             : 
      78             : typedef struct
      79             : {
      80             :   u32 cached_sw_if_index;
      81             :   u32 cached_ip4_address;
      82             : } det44_runtime_t;
      83             : 
      84             : /* deterministic session outside key */
      85             : typedef struct
      86             : {
      87             :   union
      88             :   {
      89             :     struct
      90             :     {
      91             :       ip4_address_t ext_host_addr;
      92             :       u16 ext_host_port;
      93             :       u16 out_port;
      94             :     };
      95             :     u64 as_u64;
      96             :   };
      97             : } snat_det_out_key_t;
      98             : 
      99             : typedef struct
     100             : {
     101             :   /* Inside network port */
     102             :   u16 in_port;
     103             :   /* Outside network address and port */
     104             :   snat_det_out_key_t out;
     105             :   /* Session state */
     106             :   u8 state;
     107             :   /* Expire timeout */
     108             :   u32 expire;
     109             : } snat_det_session_t;
     110             : 
     111             : typedef struct
     112             : {
     113             :   /* inside IP address range */
     114             :   ip4_address_t in_addr;
     115             :   u8 in_plen;
     116             :   /* outside IP address range */
     117             :   ip4_address_t out_addr;
     118             :   u8 out_plen;
     119             :   /* inside IP addresses / outside IP addresses */
     120             :   u32 sharing_ratio;
     121             :   /* number of ports available to internal host */
     122             :   u16 ports_per_host;
     123             :   /* session counter */
     124             :   u32 ses_num;
     125             :   /* vector of sessions */
     126             :   snat_det_session_t *sessions;
     127             : } snat_det_map_t;
     128             : 
     129             : typedef struct
     130             : {
     131             :   u32 sw_if_index;
     132             :   u8 flags;
     133             : } det44_interface_t;
     134             : 
     135             : typedef struct
     136             : {
     137             :   u32 outside_vrf_id;
     138             :   u32 inside_vrf_id;
     139             : } det44_config_t;
     140             : 
     141             : typedef struct
     142             : {
     143             :   u32 fib_index;
     144             :   u32 refcount;
     145             : } det44_fib_t;
     146             : 
     147             : typedef struct det44_main_s
     148             : {
     149             :   det44_config_t config;
     150             : 
     151             :   u32 outside_fib_index;
     152             :   u32 inside_fib_index;
     153             : 
     154             :   /* Vector of outside fibs */
     155             :   det44_fib_t *outside_fibs;
     156             : 
     157             :   fib_source_t fib_src_hi;
     158             :   fib_source_t fib_src_low;
     159             : 
     160             :   u32 out2in_node_index;
     161             :   u32 in2out_node_index;
     162             : 
     163             :   /* Deterministic NAT mappings */
     164             :   snat_det_map_t *det_maps;
     165             : 
     166             :   /* TCP MSS clamping */
     167             :   u16 mss_clamping;
     168             : 
     169             :   /* Protocol timeouts */
     170             :   nat_timeouts_t timeouts;
     171             : 
     172             :   /* Expire walk process node index */
     173             :   u32 expire_walk_node_index;
     174             : 
     175             :   u32 enabled;
     176             : 
     177             :   /* API message ID base */
     178             :   u16 msg_id_base;
     179             : 
     180             :   /* log class */
     181             :   vlib_log_class_t log_class;
     182             : 
     183             :   det44_interface_t *interfaces;
     184             : 
     185             :   /* convenience */
     186             :   ip4_main_t *ip4_main;
     187             :   /* required */
     188             :   vnet_main_t *vnet_main;
     189             : 
     190             : } det44_main_t;
     191             : 
     192             : extern det44_main_t det44_main;
     193             : 
     194             : /* logging */
     195             : #define det44_log_err(...) \
     196             :   vlib_log(VLIB_LOG_LEVEL_ERR, det44_main.log_class, __VA_ARGS__)
     197             : #define det44_log_warn(...) \
     198             :   vlib_log(VLIB_LOG_LEVEL_WARNING, det44_main.log_class, __VA_ARGS__)
     199             : #define det44_log_notice(...) \
     200             :   vlib_log(VLIB_LOG_LEVEL_NOTICE, det44_main.log_class, __VA_ARGS__)
     201             : #define det44_log_info(...) \
     202             :   vlib_log(VLIB_LOG_LEVEL_INFO, det44_main.log_class, __VA_ARGS__)
     203             : #define det44_log_debug(...)\
     204             :   vlib_log(VLIB_LOG_LEVEL_DEBUG, det44_main.log_class, __VA_ARGS__)
     205             : 
     206             : /* Deterministic NAT interface flags */
     207             : #define DET44_INTERFACE_FLAG_IS_INSIDE 1
     208             : #define DET44_INTERFACE_FLAG_IS_OUTSIDE 2
     209             : 
     210             : /** \brief Check if Deterministic NAT interface is inside.
     211             :     @param i Deterministic NAT interface
     212             :     @return 1 if inside interface
     213             : */
     214             : #define det44_interface_is_inside(i) i->flags & DET44_INTERFACE_FLAG_IS_INSIDE
     215             : 
     216             : /** \brief Check if Deterministic NAT interface is outside.
     217             :     @param i Deterministic NAT interface
     218             :     @return 1 if outside interface
     219             : */
     220             : #define det44_interface_is_outside(i) i->flags & DET44_INTERFACE_FLAG_IS_OUTSIDE
     221             : 
     222             : static_always_inline u8
     223         912 : plugin_enabled ()
     224             : {
     225         912 :   det44_main_t *dm = &det44_main;
     226         912 :   return dm->enabled;
     227             : }
     228             : 
     229             : extern vlib_node_registration_t det44_in2out_node;
     230             : extern vlib_node_registration_t det44_out2in_node;
     231             : 
     232             : int det44_plugin_enable (det44_config_t);
     233             : int det44_plugin_disable ();
     234             : 
     235             : int det44_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del);
     236             : 
     237             : int det44_set_timeouts (nat_timeouts_t * timeouts);
     238             : nat_timeouts_t det44_get_timeouts ();
     239             : void det44_reset_timeouts ();
     240             : 
     241             : /* format functions */
     242             : format_function_t format_det_map_ses;
     243             : 
     244             : int snat_det_add_map (ip4_address_t * in_addr, u8 in_plen,
     245             :                       ip4_address_t * out_addr, u8 out_plen, int is_add);
     246             : 
     247             : /* icmp session match functions */
     248             : u32 icmp_match_out2in_det (vlib_node_runtime_t * node,
     249             :                            u32 thread_index, vlib_buffer_t * b0,
     250             :                            ip4_header_t * ip0, ip4_address_t * addr,
     251             :                            u16 * port, u32 * fib_index,
     252             :                            nat_protocol_t * proto, void *d, void *e,
     253             :                            u8 * dont_translate);
     254             : u32 icmp_match_in2out_det (vlib_node_runtime_t * node,
     255             :                            u32 thread_index, vlib_buffer_t * b0,
     256             :                            ip4_header_t * ip0, ip4_address_t * addr,
     257             :                            u16 * port, u32 * fib_index,
     258             :                            nat_protocol_t * proto, void *d, void *e,
     259             :                            u8 * dont_translate);
     260             : u32 det44_icmp_in2out (vlib_buffer_t * b0, ip4_header_t * ip0,
     261             :                        icmp46_header_t * icmp0, u32 sw_if_index0,
     262             :                        u32 rx_fib_index0, vlib_node_runtime_t * node,
     263             :                        u32 next0, u32 thread_index, void *d, void *e);
     264             : u32 det44_icmp_out2in (vlib_buffer_t * b0, ip4_header_t * ip0,
     265             :                        icmp46_header_t * icmp0, u32 sw_if_index0,
     266             :                        u32 rx_fib_index0, vlib_node_runtime_t * node,
     267             :                        u32 next0, u32 thread_index, void *d, void *e);
     268             : 
     269             : static_always_inline int
     270          35 : is_addr_in_net (ip4_address_t * addr, ip4_address_t * net, u8 plen)
     271             : {
     272          35 :   if (net->as_u32 == (addr->as_u32 & ip4_main.fib_masks[plen]))
     273          35 :     return 1;
     274           0 :   return 0;
     275             : }
     276             : 
     277             : static_always_inline snat_det_map_t *
     278          21 : snat_det_map_by_user (ip4_address_t * user_addr)
     279             : {
     280          21 :   det44_main_t *dm = &det44_main;
     281             :   snat_det_map_t *mp;
     282             :   /* *INDENT-OFF* */
     283          21 :   pool_foreach (mp, dm->det_maps)
     284             :    {
     285          21 :     if (is_addr_in_net(user_addr, &mp->in_addr, mp->in_plen))
     286          21 :       return mp;
     287             :   }
     288             :   /* *INDENT-ON* */
     289           0 :   return 0;
     290             : }
     291             : 
     292             : static_always_inline snat_det_map_t *
     293          14 : snat_det_map_by_out (ip4_address_t * out_addr)
     294             : {
     295          14 :   det44_main_t *dm = &det44_main;
     296             :   snat_det_map_t *mp;
     297             :   /* *INDENT-OFF* */
     298          14 :   pool_foreach (mp, dm->det_maps)
     299             :    {
     300          14 :     if (is_addr_in_net(out_addr, &mp->out_addr, mp->out_plen))
     301          14 :       return mp;
     302             :   }
     303             :   /* *INDENT-ON* */
     304           0 :   return 0;
     305             : }
     306             : 
     307             : static_always_inline void
     308          19 : snat_det_forward (snat_det_map_t * dm, ip4_address_t * in_addr,
     309             :                   ip4_address_t * out_addr, u16 * lo_port)
     310             : {
     311             :   u32 in_offset, out_offset;
     312             : 
     313          19 :   in_offset = clib_net_to_host_u32 (in_addr->as_u32) -
     314          19 :     clib_net_to_host_u32 (dm->in_addr.as_u32);
     315          19 :   out_offset = in_offset / dm->sharing_ratio;
     316          19 :   out_addr->as_u32 =
     317          19 :     clib_host_to_net_u32 (clib_net_to_host_u32 (dm->out_addr.as_u32) +
     318             :                           out_offset);
     319          19 :   *lo_port = 1024 + dm->ports_per_host * (in_offset % dm->sharing_ratio);
     320          19 : }
     321             : 
     322             : static_always_inline void
     323          14 : snat_det_reverse (snat_det_map_t * dm, ip4_address_t * out_addr, u16 out_port,
     324             :                   ip4_address_t * in_addr)
     325             : {
     326             :   u32 in_offset1, in_offset2, out_offset;
     327             : 
     328          14 :   out_offset = clib_net_to_host_u32 (out_addr->as_u32) -
     329          14 :     clib_net_to_host_u32 (dm->out_addr.as_u32);
     330          14 :   in_offset1 = out_offset * dm->sharing_ratio;
     331          14 :   in_offset2 = (out_port - 1024) / dm->ports_per_host;
     332          14 :   in_addr->as_u32 =
     333          14 :     clib_host_to_net_u32 (clib_net_to_host_u32 (dm->in_addr.as_u32) +
     334             :                           in_offset1 + in_offset2);
     335          14 : }
     336             : 
     337             : static_always_inline u32
     338          53 : snat_det_user_ses_offset (ip4_address_t * addr, u8 plen)
     339             : {
     340          53 :   return (clib_net_to_host_u32 (addr->as_u32) & pow2_mask (32 - plen)) *
     341             :     DET44_SES_PER_USER;
     342             : }
     343             : 
     344             : static_always_inline snat_det_session_t *
     345          23 : snat_det_get_ses_by_out (snat_det_map_t * dm, ip4_address_t * in_addr,
     346             :                          u64 out_key)
     347             : {
     348             :   u32 user_offset;
     349             :   u16 i;
     350             : 
     351          23 :   user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen);
     352       10026 :   for (i = 0; i < DET44_SES_PER_USER; i++)
     353             :     {
     354       10016 :       if (dm->sessions[i + user_offset].out.as_u64 == out_key)
     355          13 :         return &dm->sessions[i + user_offset];
     356             :     }
     357             : 
     358          10 :   return 0;
     359             : }
     360             : 
     361             : static_always_inline snat_det_session_t *
     362          19 : snat_det_find_ses_by_in (snat_det_map_t * dm, ip4_address_t * in_addr,
     363             :                          u16 in_port, snat_det_out_key_t out_key)
     364             : {
     365             :   snat_det_session_t *ses;
     366             :   u32 user_offset;
     367             :   u16 i;
     368             : 
     369          19 :   user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen);
     370       10019 :   for (i = 0; i < DET44_SES_PER_USER; i++)
     371             :     {
     372       10009 :       ses = &dm->sessions[i + user_offset];
     373       10009 :       if (ses->in_port == in_port &&
     374           9 :           ses->out.ext_host_addr.as_u32 == out_key.ext_host_addr.as_u32 &&
     375           9 :           ses->out.ext_host_port == out_key.ext_host_port)
     376           9 :         return &dm->sessions[i + user_offset];
     377             :     }
     378             : 
     379          10 :   return 0;
     380             : }
     381             : 
     382             : static_always_inline snat_det_session_t *
     383          10 : snat_det_ses_create (u32 thread_index, snat_det_map_t * dm,
     384             :                      ip4_address_t * in_addr, u16 in_port,
     385             :                      snat_det_out_key_t * out)
     386             : {
     387             :   u32 user_offset;
     388             :   u16 i;
     389             : 
     390          10 :   user_offset = snat_det_user_ses_offset (in_addr, dm->in_plen);
     391             : 
     392          16 :   for (i = 0; i < DET44_SES_PER_USER; i++)
     393             :     {
     394          16 :       if (!dm->sessions[i + user_offset].in_port)
     395             :         {
     396          10 :           if (clib_atomic_bool_cmp_and_swap
     397             :               (&dm->sessions[i + user_offset].in_port, 0, in_port))
     398             :             {
     399          10 :               dm->sessions[i + user_offset].out.as_u64 = out->as_u64;
     400          10 :               dm->sessions[i + user_offset].state = DET44_SESSION_UNKNOWN;
     401          10 :               dm->sessions[i + user_offset].expire = 0;
     402          10 :               clib_atomic_add_fetch (&dm->ses_num, 1);
     403          10 :               return &dm->sessions[i + user_offset];
     404             :             }
     405             :         }
     406             :     }
     407             : 
     408           0 :   nat_ipfix_logging_max_entries_per_user (thread_index,
     409             :                                           DET44_SES_PER_USER,
     410             :                                           in_addr->as_u32);
     411           0 :   return 0;
     412             : }
     413             : 
     414             : static_always_inline void
     415           7 : snat_det_ses_close (snat_det_map_t * dm, snat_det_session_t * ses)
     416             : {
     417           7 :   if (clib_atomic_bool_cmp_and_swap (&ses->in_port, ses->in_port, 0))
     418             :     {
     419           7 :       ses->out.as_u64 = 0;
     420           7 :       clib_atomic_add_fetch (&dm->ses_num, -1);
     421             :     }
     422           7 : }
     423             : 
     424             : clib_error_t *det44_api_hookup (vlib_main_t * vm);
     425             : 
     426             : #endif /* __included_det44_h__ */
     427             : 
     428             : /*
     429             :  * fd.io coding-style-patch-verification: ON
     430             :  *
     431             :  * Local Variables:
     432             :  * eval: (c-set-style "gnu")
     433             :  * End:
     434             :  */

Generated by: LCOV version 1.14