diff options
author | Ole Troan <ot@cisco.com> | 2021-10-12 12:45:08 +0200 |
---|---|---|
committer | Ole Troan <ot@cisco.com> | 2021-10-12 12:45:56 +0200 |
commit | 23a15b34e410def81d4bb3e2c8f28f118b59dc5a (patch) | |
tree | 2ac28f040d1996487f03fac1c05b103a12ddeb0d | |
parent | 69b7599e4b061a8996205f0304232ede84cb70d4 (diff) |
Revert "nat: static mappings in flow hash"
This reverts commit 69b7599e4b061a8996205f0304232ede84cb70d4.
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
Change-Id: If531b122ae5a9f91c2fe6eaa0da69922a91f16d3
31 files changed, 1468 insertions, 1298 deletions
diff --git a/src/plugins/nat/det44/det44.h b/src/plugins/nat/det44/det44.h index 20dc8b1aec9..02b0fa7e81d 100644 --- a/src/plugins/nat/det44/det44.h +++ b/src/plugins/nat/det44/det44.h @@ -40,7 +40,6 @@ #include <nat/lib/lib.h> #include <nat/lib/inlines.h> #include <nat/lib/ipfix_logging.h> -#include <nat/lib/nat_proto.h> /* Session state */ #define foreach_det44_session_state \ diff --git a/src/plugins/nat/lib/alloc.h b/src/plugins/nat/lib/alloc.h index 0c302bf4cfb..a9a2c15fedc 100644 --- a/src/plugins/nat/lib/alloc.h +++ b/src/plugins/nat/lib/alloc.h @@ -21,7 +21,6 @@ #define included_nat_lib_alloc_h__ #include <vnet/ip/ip.h> -#include <nat/lib/nat_proto.h> typedef struct nat_ip4_pool_addr_s nat_ip4_pool_addr_t; typedef struct nat_ip4_addr_port_s nat_ip4_addr_port_t; diff --git a/src/plugins/nat/lib/inlines.h b/src/plugins/nat/lib/inlines.h index 46be64d36cf..fe1f7dd27bc 100644 --- a/src/plugins/nat/lib/inlines.h +++ b/src/plugins/nat/lib/inlines.h @@ -20,6 +20,37 @@ #include <vnet/ip/icmp46_packet.h> +always_inline nat_protocol_t +ip_proto_to_nat_proto (u8 ip_proto) +{ + static const nat_protocol_t lookup_table[256] = { + [IP_PROTOCOL_TCP] = NAT_PROTOCOL_TCP, + [IP_PROTOCOL_UDP] = NAT_PROTOCOL_UDP, + [IP_PROTOCOL_ICMP] = NAT_PROTOCOL_ICMP, + [IP_PROTOCOL_ICMP6] = NAT_PROTOCOL_ICMP, + }; + + return lookup_table[ip_proto]; +} + +static_always_inline u8 +nat_proto_to_ip_proto (nat_protocol_t nat_proto) +{ + ASSERT (nat_proto <= NAT_PROTOCOL_ICMP); + + static const u8 lookup_table[256] = { + [NAT_PROTOCOL_OTHER] = ~0, + [NAT_PROTOCOL_TCP] = IP_PROTOCOL_TCP, + [NAT_PROTOCOL_UDP] = IP_PROTOCOL_UDP, + [NAT_PROTOCOL_ICMP] = IP_PROTOCOL_ICMP, + }; + + ASSERT (NAT_PROTOCOL_OTHER == nat_proto || NAT_PROTOCOL_TCP == nat_proto + || NAT_PROTOCOL_UDP == nat_proto || NAT_PROTOCOL_ICMP == nat_proto); + + return lookup_table[nat_proto]; +} + static_always_inline u8 icmp_type_is_error_message (u8 icmp_type) { diff --git a/src/plugins/nat/lib/ipfix_logging.c b/src/plugins/nat/lib/ipfix_logging.c index 27a0b92ae71..6e5e4b6c750 100644 --- a/src/plugins/nat/lib/ipfix_logging.c +++ b/src/plugins/nat/lib/ipfix_logging.c @@ -51,7 +51,7 @@ typedef struct u8 nat_event; u32 src_ip; u32 nat_src_ip; - ip_protocol_t proto; + nat_protocol_t nat_proto; u16 src_port; u16 nat_src_port; u32 vrf_id; @@ -577,8 +577,9 @@ nat_ipfix_send (flow_report_main_t *frm, vlib_frame_t *f, vlib_buffer_t *b0, static void nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip, - u32 nat_src_ip, ip_protocol_t proto, u16 src_port, - u16 nat_src_port, u32 fib_index, int do_flush) + u32 nat_src_ip, nat_protocol_t nat_proto, + u16 src_port, u16 nat_src_port, u32 fib_index, + int do_flush) { nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index]; @@ -589,9 +590,12 @@ nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip, u32 offset; vlib_main_t *vm = vlib_get_main (); u64 now; + u8 proto; u16 template_id; u32 vrf_id; + proto = nat_proto_to_ip_proto (nat_proto); + now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -1303,34 +1307,54 @@ nat_ipfix_flush_from_main (void) /** * @brief Generate NAT44 session create event + * + * @param thread_index thread index + * @param src_ip source IPv4 address + * @param nat_src_ip transaltes source IPv4 address + * @param nat_proto NAT transport protocol + * @param src_port source port + * @param nat_src_port translated source port + * @param vrf_id VRF ID */ void -nat_ipfix_logging_nat44_ses_create (u32 thread_index, u32 src_ip, - u32 nat_src_ip, ip_protocol_t proto, - u16 src_port, u16 nat_src_port, - u32 fib_index) +nat_ipfix_logging_nat44_ses_create (u32 thread_index, + u32 src_ip, + u32 nat_src_ip, + nat_protocol_t nat_proto, + u16 src_port, + u16 nat_src_port, u32 fib_index) { skip_if_disabled (); nat_ipfix_logging_nat44_ses (thread_index, NAT44_SESSION_CREATE, src_ip, - nat_src_ip, proto, src_port, nat_src_port, - fib_index, 0); + nat_src_ip, nat_proto, src_port, nat_src_port, + fib_index, 0); } /** * @brief Generate NAT44 session delete event + * + * @param thread_index thread index + * @param src_ip source IPv4 address + * @param nat_src_ip transaltes source IPv4 address + * @param nat_proto NAT transport protocol + * @param src_port source port + * @param nat_src_port translated source port + * @param vrf_id VRF ID */ void -nat_ipfix_logging_nat44_ses_delete (u32 thread_index, u32 src_ip, - u32 nat_src_ip, ip_protocol_t proto, - u16 src_port, u16 nat_src_port, - u32 fib_index) +nat_ipfix_logging_nat44_ses_delete (u32 thread_index, + u32 src_ip, + u32 nat_src_ip, + nat_protocol_t nat_proto, + u16 src_port, + u16 nat_src_port, u32 fib_index) { skip_if_disabled (); nat_ipfix_logging_nat44_ses (thread_index, NAT44_SESSION_DELETE, src_ip, - nat_src_ip, proto, src_port, nat_src_port, - fib_index, 0); + nat_src_ip, nat_proto, src_port, nat_src_port, + fib_index, 0); } /** diff --git a/src/plugins/nat/lib/ipfix_logging.h b/src/plugins/nat/lib/ipfix_logging.h index 0b8f568e1b1..0b2357a2604 100644 --- a/src/plugins/nat/lib/ipfix_logging.h +++ b/src/plugins/nat/lib/ipfix_logging.h @@ -117,13 +117,15 @@ int nat_ipfix_logging_enabled (); void nat_ipfix_logging_init (vlib_main_t * vm); int nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port); void nat_ipfix_logging_nat44_ses_create (u32 thread_index, u32 src_ip, - u32 nat_src_ip, ip_protocol_t proto, - u16 src_port, u16 nat_src_port, - u32 fib_index); + u32 nat_src_ip, + nat_protocol_t nat_proto, + u16 src_port, u16 nat_src_port, + u32 fib_index); void nat_ipfix_logging_nat44_ses_delete (u32 thread_index, u32 src_ip, - u32 nat_src_ip, ip_protocol_t proto, - u16 src_port, u16 nat_src_port, - u32 fib_index); + u32 nat_src_ip, + nat_protocol_t nat_proto, + u16 src_port, u16 nat_src_port, + u32 fib_index); void nat_ipfix_logging_addresses_exhausted(u32 thread_index, u32 pool_id); void nat_ipfix_logging_max_entries_per_user(u32 thread_index, u32 limit, u32 src_ip); diff --git a/src/plugins/nat/lib/lib.c b/src/plugins/nat/lib/lib.c index 30bafac73c0..d2def2cc480 100644 --- a/src/plugins/nat/lib/lib.c +++ b/src/plugins/nat/lib/lib.c @@ -14,7 +14,6 @@ */ #include <nat/lib/lib.h> -#include <nat/lib/nat_proto.h> uword unformat_nat_protocol (unformat_input_t *input, va_list *args) diff --git a/src/plugins/nat/lib/lib.h b/src/plugins/nat/lib/lib.h index cea9ed71c8c..b0b5229b337 100644 --- a/src/plugins/nat/lib/lib.h +++ b/src/plugins/nat/lib/lib.h @@ -54,6 +54,19 @@ typedef enum #undef _ } nat_error_t; +#define foreach_nat_protocol \ + _ (OTHER, 0, other, "other") \ + _ (UDP, 1, udp, "udp") \ + _ (TCP, 2, tcp, "tcp") \ + _ (ICMP, 3, icmp, "icmp") + +typedef enum +{ +#define _(N, i, n, s) NAT_PROTOCOL_##N = i, + foreach_nat_protocol +#undef _ +} nat_protocol_t; + /* default protocol timeouts */ #define NAT_UDP_TIMEOUT 300 #define NAT_TCP_TRANSITORY_TIMEOUT 240 @@ -83,6 +96,29 @@ nat_reset_timeouts (nat_timeouts_t * timeouts) } static_always_inline u32 +nat_session_get_timeout (nat_timeouts_t *timeouts, nat_protocol_t proto, + u8 state) +{ + switch (proto) + { + case NAT_PROTOCOL_ICMP: + return timeouts->icmp; + case NAT_PROTOCOL_UDP: + return timeouts->udp; + case NAT_PROTOCOL_TCP: + { + if (state) + return timeouts->tcp.transitory; + else + return timeouts->tcp.established; + } + default: + return timeouts->udp; + } + return 0; +} + +static_always_inline u32 nat_calc_bihash_buckets (u32 n_elts) { n_elts = n_elts / 2.5; @@ -102,6 +138,10 @@ nat_calc_bihash_buckets (u32 n_elts) return lower_pow2; } +u8 *format_nat_protocol (u8 *s, va_list *args); + +uword unformat_nat_protocol (unformat_input_t *input, va_list *args); + #endif /* included_nat_lib_h__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/lib/nat_proto.h b/src/plugins/nat/lib/nat_proto.h deleted file mode 100644 index 9b20d9a71d1..00000000000 --- a/src/plugins/nat/lib/nat_proto.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef included_nat_proto_h__ -#define included_nat_proto_h__ - -#include <vnet/ip/ip.h> - -#define foreach_nat_protocol \ - _ (OTHER, 0, other, "other") \ - _ (UDP, 1, udp, "udp") \ - _ (TCP, 2, tcp, "tcp") \ - _ (ICMP, 3, icmp, "icmp") - -typedef enum -{ -#define _(N, i, n, s) NAT_PROTOCOL_##N = i, - foreach_nat_protocol -#undef _ -} nat_protocol_t; - -always_inline nat_protocol_t -ip_proto_to_nat_proto (ip_protocol_t ip_proto) -{ - static const nat_protocol_t lookup_table[256] = { - [IP_PROTOCOL_TCP] = NAT_PROTOCOL_TCP, - [IP_PROTOCOL_UDP] = NAT_PROTOCOL_UDP, - [IP_PROTOCOL_ICMP] = NAT_PROTOCOL_ICMP, - [IP_PROTOCOL_ICMP6] = NAT_PROTOCOL_ICMP, - }; - - return lookup_table[ip_proto]; -} - -static_always_inline ip_protocol_t -nat_proto_to_ip_proto (nat_protocol_t nat_proto) -{ - ASSERT (nat_proto <= NAT_PROTOCOL_ICMP); - - static const u8 lookup_table[256] = { - [NAT_PROTOCOL_OTHER] = ~0, - [NAT_PROTOCOL_TCP] = IP_PROTOCOL_TCP, - [NAT_PROTOCOL_UDP] = IP_PROTOCOL_UDP, - [NAT_PROTOCOL_ICMP] = IP_PROTOCOL_ICMP, - }; - - ASSERT (NAT_PROTOCOL_OTHER == nat_proto || NAT_PROTOCOL_TCP == nat_proto || - NAT_PROTOCOL_UDP == nat_proto || NAT_PROTOCOL_ICMP == nat_proto); - - return lookup_table[nat_proto]; -} - -u8 *format_nat_protocol (u8 *s, va_list *args); - -uword unformat_nat_protocol (unformat_input_t *input, va_list *args); - -#endif /* included_nat_proto_h__ */ -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/lib/nat_syslog.c b/src/plugins/nat/lib/nat_syslog.c index 98777ebf280..2c395bf7fd8 100644 --- a/src/plugins/nat/lib/nat_syslog.c +++ b/src/plugins/nat/lib/nat_syslog.c @@ -23,7 +23,38 @@ #include <nat/lib/nat_syslog.h> #include <nat/lib/inlines.h> -#include <nat/lib/nat_syslog_constants.h> +#define NAT_FACILITY SYSLOG_FACILITY_LOCAL0 + +#define NAT_APPNAME "NAT" + +#define SADD_SDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL +#define APMADD_APMDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL + +#define SADD_MSGID "SADD" +#define SDEL_MSGID "SDEL" +#define APMADD_MSGID "APMADD" +#define APMDEL_MSGID "APMDEL" + +#define NSESS_SDID "nsess" +#define NAPMAP_SDID "napmap" + +#define SSUBIX_SDPARAM_NAME "SSUBIX" +#define SVLAN_SDPARAM_NAME "SVLAN" +#define IATYP_SDPARAM_NAME "IATYP" +#define ISADDR_SDPARAM_NAME "ISADDR" +#define ISPORT_SDPARAM_NAME "ISPORT" +#define IDADDR_SDPARAM_NAME "IDADDR" +#define IDPORT_SDPARAM_NAME "IDPORT" +#define XATYP_SDPARAM_NAME "XATYP" +#define XSADDR_SDPARAM_NAME "XSADDR" +#define XSPORT_SDPARAM_NAME "XSPORT" +#define XDADDR_SDPARAM_NAME "XDADDR" +#define XDPORT_SDPARAM_NAME "XDPORT" +#define PROTO_SDPARAM_NAME "PROTO" +#define SV6ENC_SDPARAM_NAME "SV6ENC" + +#define IATYP_IPV4 "IPv4" +#define IATYP_IPV6 "IPv6" static inline void nat_syslog_nat44_apmap (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, @@ -111,6 +142,82 @@ nat_syslog_dslite_apmdel (u32 ssubix, ip6_address_t * sv6enc, } static inline void +nat_syslog_nat44_sess (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, + u16 isport, ip4_address_t * xsaddr, u16 xsport, + ip4_address_t * idaddr, u16 idport, + ip4_address_t * xdaddr, u16 xdport, + nat_protocol_t proto, u8 is_add, u8 is_twicenat) +{ + syslog_msg_t syslog_msg; + fib_table_t *fib; + + if (!syslog_is_enabled ()) + return; + + if (syslog_severity_filter_block (SADD_SDEL_SEVERITY)) + return; + + fib = fib_table_get (sfibix, FIB_PROTOCOL_IP4); + + syslog_msg_init (&syslog_msg, NAT_FACILITY, SADD_SDEL_SEVERITY, NAT_APPNAME, + is_add ? SADD_MSGID : SDEL_MSGID); + + syslog_msg_sd_init (&syslog_msg, NSESS_SDID); + syslog_msg_add_sd_param (&syslog_msg, SSUBIX_SDPARAM_NAME, "%d", ssubix); + syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d", + fib->ft_table_id); + syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV4); + syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U", + format_ip4_address, isaddr); + syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d", + clib_net_to_host_u16 (isport)); + syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4); + syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U", + format_ip4_address, xsaddr); + syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d", + clib_net_to_host_u16 (xsport)); + syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d", + nat_proto_to_ip_proto (proto)); + syslog_msg_add_sd_param (&syslog_msg, XDADDR_SDPARAM_NAME, "%U", + format_ip4_address, xdaddr); + syslog_msg_add_sd_param (&syslog_msg, XDPORT_SDPARAM_NAME, "%d", + clib_net_to_host_u16 (xdport)); + if (is_twicenat) + { + syslog_msg_add_sd_param (&syslog_msg, IDADDR_SDPARAM_NAME, "%U", + format_ip4_address, idaddr); + syslog_msg_add_sd_param (&syslog_msg, IDPORT_SDPARAM_NAME, "%d", + clib_net_to_host_u16 (idport)); + } + + syslog_msg_send (&syslog_msg); +} + +void +nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, + u16 isport, ip4_address_t * idaddr, u16 idport, + ip4_address_t * xsaddr, u16 xsport, + ip4_address_t * xdaddr, u16 xdport, + nat_protocol_t proto, u8 is_twicenat) +{ + nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport, + idaddr, idport, xdaddr, xdport, proto, 1, + is_twicenat); +} + +void +nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, + u16 isport, ip4_address_t * idaddr, u16 idport, + ip4_address_t * xsaddr, u16 xsport, + ip4_address_t * xdaddr, u16 xdport, + nat_protocol_t proto, u8 is_twicenat) +{ + nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport, + idaddr, idport, xdaddr, xdport, proto, 0, + is_twicenat); +} + +static inline void nat_syslog_nat64_sess (u32 sfibix, ip6_address_t * isaddr, u16 isport, ip4_address_t * xsaddr, u16 xsport, ip4_address_t * xdaddr, u16 xdport, diff --git a/src/plugins/nat/lib/nat_syslog.h b/src/plugins/nat/lib/nat_syslog.h index f929bf310b4..9721664cf54 100644 --- a/src/plugins/nat/lib/nat_syslog.h +++ b/src/plugins/nat/lib/nat_syslog.h @@ -20,7 +20,6 @@ #define __included_nat_syslog_h__ #include <nat/lib/lib.h> -#include <nat/lib/nat_proto.h> void nat_syslog_nat44_apmadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, u16 isport, ip4_address_t * xsaddr, u16 xsport, @@ -42,6 +41,18 @@ nat_syslog_dslite_apmdel (u32 ssubix, ip6_address_t * sv6enc, ip4_address_t * xsaddr, u16 xsport, nat_protocol_t proto); +void nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, + u16 isport, ip4_address_t * idaddr, u16 idport, + ip4_address_t * xsaddr, u16 xsport, + ip4_address_t * xdaddr, u16 xdport, + nat_protocol_t proto, u8 is_twicenat); + +void nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr, + u16 isport, ip4_address_t * idaddr, u16 idport, + ip4_address_t * xsaddr, u16 xsport, + ip4_address_t * xdaddr, u16 xdport, + nat_protocol_t proto, u8 is_twicenat); + void nat_syslog_nat64_sadd (u32 sfibix, ip6_address_t * isaddr, u16 isport, ip4_address_t * xsaddr, u16 xsport, ip4_address_t * xdaddr, u16 xdport, diff --git a/src/plugins/nat/lib/nat_syslog_constants.h b/src/plugins/nat/lib/nat_syslog_constants.h deleted file mode 100644 index eeea7d2654e..00000000000 --- a/src/plugins/nat/lib/nat_syslog_constants.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @file - * @brief NAT syslog logging constants - */ -#ifndef __included_nat_syslog_constants_h__ -#define __included_nat_syslog_constants_h__ - -#define NAT_FACILITY SYSLOG_FACILITY_LOCAL0 - -#define NAT_APPNAME "NAT" - -#define SADD_SDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL -#define APMADD_APMDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL - -#define SADD_MSGID "SADD" -#define SDEL_MSGID "SDEL" -#define APMADD_MSGID "APMADD" -#define APMDEL_MSGID "APMDEL" - -#define NSESS_SDID "nsess" -#define NAPMAP_SDID "napmap" - -#define SSUBIX_SDPARAM_NAME "SSUBIX" -#define SVLAN_SDPARAM_NAME "SVLAN" -#define IATYP_SDPARAM_NAME "IATYP" -#define ISADDR_SDPARAM_NAME "ISADDR" -#define ISPORT_SDPARAM_NAME "ISPORT" -#define IDADDR_SDPARAM_NAME "IDADDR" -#define IDPORT_SDPARAM_NAME "IDPORT" -#define XATYP_SDPARAM_NAME "XATYP" -#define XSADDR_SDPARAM_NAME "XSADDR" -#define XSPORT_SDPARAM_NAME "XSPORT" -#define XDADDR_SDPARAM_NAME "XDADDR" -#define XDPORT_SDPARAM_NAME "XDPORT" -#define PROTO_SDPARAM_NAME "PROTO" -#define SV6ENC_SDPARAM_NAME "SV6ENC" - -#define IATYP_IPV4 "IPv4" -#define IATYP_IPV6 "IPv6" - -#endif /* __included_nat_syslog_constants_h__ */ -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/nat44-ed/nat44_ed.c b/src/plugins/nat/nat44-ed/nat44_ed.c index d639392019b..a11043682b9 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.c +++ b/src/plugins/nat/nat44-ed/nat44_ed.c @@ -28,11 +28,9 @@ #include <vppinfra/bihash_16_8.h> #include <nat/lib/log.h> +#include <nat/lib/nat_syslog.h> #include <nat/lib/nat_inlines.h> #include <nat/lib/ipfix_logging.h> -#include <vnet/syslog/syslog.h> -#include <nat/lib/nat_syslog_constants.h> -#include <nat/lib/nat_syslog.h> #include <nat/nat44-ed/nat44_ed.h> #include <nat/nat44-ed/nat44_ed_affinity.h> @@ -185,6 +183,29 @@ static void nat44_ed_db_free (); u32 nat_calc_bihash_buckets (u32 n_elts); u8 * +format_session_kvp (u8 * s, va_list * args) +{ + clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *); + + s = format (s, "%U thread-index %llu session-index %llu", format_snat_key, + v->key, nat_value_get_thread_index (v), + nat_value_get_session_index (v)); + + return s; +} + +u8 * +format_static_mapping_kvp (u8 * s, va_list * args) +{ + clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *); + + s = format (s, "%U static-mapping-index %llu", + format_snat_key, v->key, v->value); + + return s; +} + +u8 * format_ed_session_kvp (u8 * s, va_list * args) { clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *); @@ -206,81 +227,59 @@ format_ed_session_kvp (u8 * s, va_list * args) return s; } -static_always_inline int -nat44_ed_sm_i2o_add (snat_main_t *sm, snat_static_mapping_t *m, - ip4_address_t addr, u16 port, u32 fib_index, u8 proto) +void +nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, + u8 is_ha) { - ASSERT (!pool_is_free (sm->static_mappings, m)); - clib_bihash_kv_16_8_t kv; - nat44_ed_sm_init_i2o_kv (&kv, addr.as_u32, port, fib_index, proto, - m - sm->static_mappings); - return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, 1 /*is_add*/); -} + per_vrf_sessions_unregister_session (s, thread_index); -static_always_inline int -nat44_ed_sm_i2o_del (snat_main_t *sm, ip4_address_t addr, u16 port, - u32 fib_index, u8 proto) -{ - clib_bihash_kv_16_8_t kv; - nat44_ed_sm_init_i2o_k (&kv, addr.as_u32, port, fib_index, proto); - return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, 0 /*is_add*/); -} + if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 0)) + nat_elog_warn (sm, "flow hash del failed"); -static_always_inline int -nat44_ed_sm_o2i_add (snat_main_t *sm, snat_static_mapping_t *m, - ip4_address_t addr, u16 port, u32 fib_index, u8 proto) -{ - ASSERT (!pool_is_free (sm->static_mappings, m)); - clib_bihash_kv_16_8_t kv; - nat44_ed_sm_init_o2i_kv (&kv, addr.as_u32, port, fib_index, proto, - m - sm->static_mappings); - return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, 1 /*is_add*/); -} + if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0)) + nat_elog_warn (sm, "flow hash del failed"); -static_always_inline int -nat44_ed_sm_o2i_del (snat_main_t *sm, ip4_address_t addr, u16 port, - u32 fib_index, u8 proto) -{ - clib_bihash_kv_16_8_t kv; - nat44_ed_sm_init_o2i_k (&kv, addr.as_u32, port, fib_index, proto); - return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, 0 /*is_add*/); -} + if (na44_ed_is_fwd_bypass_session (s)) + { + return; + } -void -nat44_ed_free_session_data (snat_main_t *sm, snat_session_t *s, - u32 thread_index, u8 is_ha) -{ - per_vrf_sessions_unregister_session (s, thread_index); + if (nat44_ed_is_affinity_session (s)) + nat_affinity_unlock (s->ext_host_addr, s->out2in.addr, s->nat_proto, + s->out2in.port); - if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 0)) - nat_elog_warn (sm, "flow hash del failed"); + if (!is_ha) + nat_syslog_nat44_sdel ( + 0, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, + &s->ext_host_nat_addr, s->ext_host_nat_port, &s->out2in.addr, + s->out2in.port, &s->ext_host_addr, s->ext_host_port, s->nat_proto, + nat44_ed_is_twice_nat_session (s)); - if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0)) - nat_elog_warn (sm, "flow hash del failed"); + if (snat_is_unk_proto_session (s)) + return; - if (na44_ed_is_fwd_bypass_session (s)) - { - return; - } + if (!is_ha) + { + /* log NAT event */ + nat_ipfix_logging_nat44_ses_delete ( + thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, + s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index); + } - if (nat44_ed_is_affinity_session (s)) - nat_affinity_unlock (s->ext_host_addr, s->out2in.addr, s->proto, - s->out2in.port); + /* Twice NAT address and port for external host */ + if (nat44_ed_is_twice_nat_session (s)) + { + snat_free_outside_address_and_port ( + sm->twice_nat_addresses, thread_index, &s->ext_host_nat_addr, + s->ext_host_nat_port, s->nat_proto); + } - if (!is_ha) - nat_syslog_nat44_sdel (0, s->in2out.fib_index, &s->in2out.addr, - s->in2out.port, &s->ext_host_nat_addr, - s->ext_host_nat_port, &s->out2in.addr, - s->out2in.port, &s->ext_host_addr, s->ext_host_port, - s->proto, nat44_ed_is_twice_nat_session (s)); + if (nat44_ed_is_session_static (s)) + return; - if (!is_ha) - { - /* log NAT event */ - nat_ipfix_logging_nat44_ses_delete ( - thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto, - s->in2out.port, s->out2in.port, s->in2out.fib_index); - } + snat_free_outside_address_and_port (sm->addresses, thread_index, + &s->out2in.addr, s->out2in.port, + s->nat_proto); } static int @@ -389,6 +388,7 @@ int nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat) { snat_main_t *sm = &snat_main; + vlib_thread_main_t *tm = vlib_get_thread_main (); snat_address_t *ap, *addresses; addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses; @@ -426,6 +426,16 @@ nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat) FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); } +#define _(N, i, n, s) \ + clib_memset (ap->busy_##n##_port_refcounts, 0, \ + sizeof (ap->busy_##n##_port_refcounts)); \ + ap->busy_##n##_ports = 0; \ + ap->busy_##n##_ports_per_thread = 0; \ + vec_validate_init_empty (ap->busy_##n##_ports_per_thread, \ + tm->n_vlib_mains - 1, 0); + foreach_nat_protocol +#undef _ + if (!twice_nat) { // if we don't have enabled interface we don't add address @@ -470,8 +480,7 @@ nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat) { nat44_ed_del_static_mapping (m->local_addr, m->external_addr, m->local_port, m->external_port, - ip_proto_to_nat_proto (m->proto), - m->vrf_id, ~0, m->flags); + m->proto, m->vrf_id, ~0, m->flags); } } } @@ -492,25 +501,32 @@ nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat) } // delete sessions using address - vec_foreach (tsm, sm->per_thread_data) + if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) { - pool_foreach (ses, tsm->sessions) + vec_foreach (tsm, sm->per_thread_data) { - if (ses->out2in.addr.as_u32 == addr.as_u32) + pool_foreach (ses, tsm->sessions) { - nat44_ed_free_session_data (sm, ses, tsm - sm->per_thread_data, - 0); - vec_add1 (ses_to_be_removed, ses - tsm->sessions); + if (ses->out2in.addr.as_u32 == addr.as_u32) + { + nat_free_session_data (sm, ses, tsm - sm->per_thread_data, + 0); + vec_add1 (ses_to_be_removed, ses - tsm->sessions); + } } + vec_foreach (ses_index, ses_to_be_removed) + { + ses = pool_elt_at_index (tsm->sessions, ses_index[0]); + nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1); + } + vec_free (ses_to_be_removed); } - vec_foreach (ses_index, ses_to_be_removed) - { - ses = pool_elt_at_index (tsm->sessions, ses_index[0]); - nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1); - } - vec_free (ses_to_be_removed); } +#define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread); + foreach_nat_protocol +#undef _ + if (!twice_nat) { vec_del1 (sm->addresses, j); @@ -553,17 +569,18 @@ nat_ed_static_mapping_del_sessions (snat_main_t * sm, } if (!addr_only) { - if ((s->out2in.addr.as_u32 != e_addr.as_u32) || - s->out2in.port != e_port || s->in2out.port != l_port || - s->proto != protocol) - continue; + if ((s->out2in.addr.as_u32 != e_addr.as_u32) || + s->out2in.port != e_port || + s->in2out.port != l_port || + s->nat_proto != protocol) + continue; } if (nat44_ed_is_lb_session (s)) continue; if (!nat44_ed_is_session_static (s)) continue; - nat44_ed_free_session_data (sm, s, tsm - sm->per_thread_data, 0); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); vec_add1 (indexes_to_free, s - tsm->sessions); if (!addr_only) break; @@ -577,41 +594,89 @@ nat_ed_static_mapping_del_sessions (snat_main_t * sm, vec_free (indexes_to_free); } -static_always_inline snat_static_mapping_t * -nat44_ed_sm_lookup (snat_main_t *sm, clib_bihash_kv_16_8_t *kv) +int +nat44_ed_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto) { - clib_bihash_kv_16_8_t v; - int rc = clib_bihash_search_16_8 (&sm->flow_hash, kv, &v); - if (!rc) + u32 ti = get_thread_idx_by_port (port); + snat_main_t *sm = &snat_main; + snat_address_t *a = 0; + int i; + + for (i = 0; i < vec_len (sm->addresses); i++) { - ASSERT (0 == ed_value_get_thread_index (&v)); - return pool_elt_at_index (sm->static_mappings, - ed_value_get_session_index (&v)); + a = sm->addresses + i; + + if (a->addr.as_u32 != addr.as_u32) + continue; + + switch (proto) + { +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + if (a->busy_##n##_port_refcounts[port]) \ + goto done; \ + ++a->busy_##n##_port_refcounts[port]; \ + if (port > 1024) \ + { \ + a->busy_##n##_ports++; \ + a->busy_##n##_ports_per_thread[ti]++; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + goto done; + } + + return 0; } - return NULL; -} -snat_static_mapping_t * -nat44_ed_sm_o2i_lookup (snat_main_t *sm, ip4_address_t addr, u16 port, - u32 fib_index, u8 proto) -{ - clib_bihash_kv_16_8_t kv; - nat44_ed_sm_init_o2i_k (&kv, addr.as_u32, port, fib_index, proto); - return nat44_ed_sm_lookup (sm, &kv); +done: + return 1; } -snat_static_mapping_t * -nat44_ed_sm_i2o_lookup (snat_main_t *sm, ip4_address_t addr, u16 port, - u32 fib_index, u8 proto) +int +nat44_ed_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto) { - clib_bihash_kv_16_8_t kv; - nat44_ed_sm_init_i2o_k (&kv, addr.as_u32, port, fib_index, proto); - return nat44_ed_sm_lookup (sm, &kv); + u32 ti = get_thread_idx_by_port (port); + snat_main_t *sm = &snat_main; + snat_address_t *a = 0; + int i; + + for (i = 0; i < vec_len (sm->addresses); i++) + { + a = sm->addresses + i; + + if (a->addr.as_u32 != addr.as_u32) + continue; + + switch (proto) + { +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + --a->busy_##n##_port_refcounts[port]; \ + if (port > 1024) \ + { \ + a->busy_##n##_ports--; \ + a->busy_##n##_ports_per_thread[ti]--; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + goto done; + } + + return 0; + } + +done: + return 1; } void nat44_ed_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, - ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, ip4_address_t pool_addr, u8 *tag) { snat_static_map_resolve_t *rp; @@ -631,7 +696,7 @@ nat44_ed_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, int nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, - ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, int *out) { snat_static_map_resolve_t *rp; @@ -681,7 +746,7 @@ nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, int nat44_ed_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, - ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags) { snat_main_t *sm = &snat_main; @@ -714,24 +779,14 @@ nat44_ed_validate_sm_input (u32 flags) return 0; } -snat_address_t * -nat44_ed_addr_lookup (snat_main_t *sm, u32 addr) -{ - for (int i = 0; i < vec_len (sm->addresses); ++i) - { - if (sm->addresses[i].addr.as_u32 == addr) - return &sm->addresses[i]; - } - return NULL; -} - int nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, ip_protocol_t proto, + u16 l_port, u16 e_port, nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, ip4_address_t pool_addr, u8 *tag) { snat_main_t *sm = &snat_main; + clib_bihash_kv_8_8_t kv, value; nat44_lb_addr_port_t *local; snat_static_mapping_t *m; u32 fib_index = ~0; @@ -785,9 +840,12 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, l_addr.as_u32 = e_addr.as_u32; } - m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); - if (m) + // fib index 0 + init_nat_k (&kv, e_addr, e_port, 0, proto); + + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) { + m = pool_elt_at_index (sm->static_mappings, value.value); if (!is_sm_identity_nat (m->flags)) { return VNET_API_ERROR_VALUE_EXIST; @@ -809,8 +867,9 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, local->fib_index = fib_table_find_or_create_and_lock ( FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); - nat44_ed_sm_i2o_add (sm, m, m->local_addr, m->local_port, - local->fib_index, m->proto); + init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index, + m->proto, 0, m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); return 0; } @@ -832,7 +891,8 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, // identity nat supports multiple records in local mapping if (!(is_sm_out2in_only (flags) || is_sm_identity_nat (flags))) { - if (nat44_ed_sm_i2o_lookup (sm, l_addr, l_port, fib_index, proto)) + init_nat_k (&kv, l_addr, l_port, fib_index, proto); + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value)) { return VNET_API_ERROR_VALUE_EXIST; } @@ -841,7 +901,7 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) || sm->static_mapping_only)) { - if (!nat44_ed_addr_lookup (sm, e_addr.as_u32)) + if (nat44_ed_reserve_port (e_addr, e_port, proto)) { // remove resolve record if (is_sm_switch_address (flags) && !is_sm_identity_nat (flags)) @@ -895,11 +955,14 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (!is_sm_out2in_only (flags)) { - nat44_ed_sm_i2o_add (sm, m, m->local_addr, m->local_port, fib_index, - m->proto); + init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0, + m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); } - nat44_ed_sm_o2i_add (sm, m, m->external_addr, m->external_port, 0, m->proto); + init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0, + m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1); if (sm->num_workers > 1) { @@ -918,12 +981,13 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, int nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, ip_protocol_t proto, + u16 l_port, u16 e_port, nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags) { snat_main_per_thread_data_t *tsm; snat_main_t *sm = &snat_main; + clib_bihash_kv_8_8_t kv, value; nat44_lb_addr_port_t *local; snat_static_mapping_t *m; u32 fib_index = ~0; @@ -975,9 +1039,9 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, } // fib index 0 - m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); + init_nat_k (&kv, e_addr, e_port, 0, proto); - if (!m) + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) { if (is_sm_switch_address (flags)) { @@ -986,6 +1050,8 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, return VNET_API_ERROR_NO_SUCH_ENTRY; } + m = pool_elt_at_index (sm->static_mappings, value.value); + if (is_sm_identity_nat (flags)) { u8 failure = 1; @@ -1019,7 +1085,7 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) || sm->static_mapping_only)) { - if (!nat44_ed_addr_lookup (sm, e_addr.as_u32)) + if (nat44_ed_free_port (e_addr, e_port, proto)) { return VNET_API_ERROR_INVALID_VALUE; } @@ -1027,7 +1093,8 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (!is_sm_out2in_only (flags)) { - nat44_ed_sm_i2o_del (sm, l_addr, l_port, fib_index, proto); + init_nat_k (&kv, l_addr, l_port, fib_index, proto); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0); } if (!sm->static_mapping_only || sm->static_mapping_connection_tracking) @@ -1049,7 +1116,8 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, { // this is last record remove all required stuff // fib_index 0 - nat44_ed_sm_o2i_del (sm, e_addr, e_port, 0, proto); + init_nat_k (&kv, e_addr, e_port, 0, proto); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0); vec_free (m->tag); vec_free (m->workers); @@ -1066,17 +1134,17 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, int nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, - ip_protocol_t proto, + nat_protocol_t proto, nat44_lb_addr_port_t *locals, u32 flags, u8 *tag, u32 affinity) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; + clib_bihash_kv_8_8_t kv, value; snat_address_t *a = 0; nat44_lb_addr_port_t *local; uword *bitmap = 0; - int rc = 0; int i; @@ -1085,7 +1153,15 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, return VNET_API_ERROR_UNSUPPORTED; } - m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); + init_nat_k (&kv, e_addr, e_port, 0, proto); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) + { + m = 0; + } + else + { + m = pool_elt_at_index (sm->static_mappings, value.value); + } if (m) { @@ -1105,11 +1181,25 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, { if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) { - /* External port must be unused */ a = sm->addresses + i; - if (nat44_ed_sm_o2i_lookup (sm, a->addr, e_port, 0, proto)) + /* External port must be unused */ + switch (proto) { - return VNET_API_ERROR_VALUE_EXIST; +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + if (a->busy_##n##_port_refcounts[e_port]) \ + return VNET_API_ERROR_INVALID_VALUE; \ + ++a->busy_##n##_port_refcounts[e_port]; \ + if (e_port > 1024) \ + { \ + a->busy_##n##_ports++; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]++; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + return VNET_API_ERROR_INVALID_VALUE_2; } break; } @@ -1138,10 +1228,11 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, else m->affinity_per_service_list_head_index = ~0; - if (nat44_ed_sm_o2i_add (sm, m, m->external_addr, m->external_port, 0, - m->proto)) + init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0, + m - sm->static_mappings); + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1)) { - nat_elog_err (sm, "sm o2i key add failed"); + nat_elog_err (sm, "static_mapping_by_external key add failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1151,16 +1242,10 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, FIB_PROTOCOL_IP4, locals[i].vrf_id, sm->fib_src_low); if (!is_sm_out2in_only (flags)) { - if (nat44_ed_sm_o2i_add (sm, m, e_addr, e_port, 0, proto)) - { - nat_elog_err (sm, "sm o2i key add failed"); - rc = VNET_API_ERROR_UNSPECIFIED; - // here we continue with add operation so that it can be safely - // reversed in delete path - otherwise we'd have to track what - // we've done and deal with partial cleanups and since bihash - // adds are (extremely improbable) the only points of failure, - // it's easier to just do it this way - } + init_nat_kv (&kv, locals[i].addr, locals[i].port, + locals[i].fib_index, m->proto, 0, + m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); } locals[i].prefix = (i == 0) ? locals[i].probability : @@ -1187,36 +1272,72 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, } } - return rc; + return 0; } int nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, - ip_protocol_t proto, u32 flags) + nat_protocol_t proto, u32 flags) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; + clib_bihash_kv_8_8_t kv, value; + snat_address_t *a = 0; nat44_lb_addr_port_t *local; snat_main_per_thread_data_t *tsm; snat_session_t *s; + int i; if (!sm->enabled) { return VNET_API_ERROR_UNSUPPORTED; } - m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); + init_nat_k (&kv, e_addr, e_port, 0, proto); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) + m = 0; + else + m = pool_elt_at_index (sm->static_mappings, value.value); + if (!m) return VNET_API_ERROR_NO_SUCH_ENTRY; if (!is_sm_lb (m->flags)) return VNET_API_ERROR_INVALID_VALUE; - if (nat44_ed_sm_o2i_del (sm, m->external_addr, m->external_port, 0, - m->proto)) + if (!(sm->static_mapping_only || is_sm_out2in_only (flags))) { - nat_elog_err (sm, "sm o2i key del failed"); + for (i = 0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) + { + a = sm->addresses + i; + switch (proto) + { +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + --a->busy_##n##_port_refcounts[e_port]; \ + if (e_port > 1024) \ + { \ + a->busy_##n##_ports--; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + return VNET_API_ERROR_INVALID_VALUE_2; + } + break; + } + } + } + + init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto); + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0)) + { + nat_elog_err (sm, "static_mapping_by_external key del failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1225,10 +1346,11 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); if (!is_sm_out2in_only (flags)) { - if (nat44_ed_sm_i2o_del (sm, local->addr, local->port, - local->fib_index, m->proto)) + init_nat_k (&kv, local->addr, local->port, local->fib_index, + m->proto); + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0)) { - nat_elog_err (sm, "sm i2o key del failed"); + nat_elog_err (sm, "static_mapping_by_local key del failed"); return VNET_API_ERROR_UNSPECIFIED; } } @@ -1255,7 +1377,7 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, s->in2out.port != local->port) continue; - nat44_ed_free_session_data (sm, s, tsm - sm->per_thread_data, 0); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1); } } @@ -1276,11 +1398,12 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, int nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, ip4_address_t l_addr, u16 l_port, - ip_protocol_t proto, u32 vrf_id, + nat_protocol_t proto, u32 vrf_id, u8 probability, u8 is_add) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m = 0; + clib_bihash_kv_8_8_t kv, value; nat44_lb_addr_port_t *local, *prev_local, *match_local = 0; snat_main_per_thread_data_t *tsm; snat_session_t *s; @@ -1293,7 +1416,9 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, return VNET_API_ERROR_UNSUPPORTED; } - m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); + init_nat_k (&kv, e_addr, e_port, 0, proto); + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) + m = pool_elt_at_index (sm->static_mappings, value.value); if (!m) { @@ -1334,13 +1459,10 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, if (!is_sm_out2in_only (m->flags)) { - if (nat44_ed_sm_i2o_add (sm, m, l_addr, l_port, local->fib_index, - proto)) - { - nat_elog_err (sm, "sm i2o key add failed"); - pool_put (m->locals, local); - return VNET_API_ERROR_UNSPECIFIED; - } + init_nat_kv (&kv, l_addr, l_port, local->fib_index, proto, 0, + m - sm->static_mappings); + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1)) + nat_elog_err (sm, "static_mapping_by_local key add failed"); } } else @@ -1356,9 +1478,9 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, if (!is_sm_out2in_only (m->flags)) { - if (nat44_ed_sm_i2o_del (sm, l_addr, l_port, match_local->fib_index, - proto)) - nat_elog_err (sm, "sm i2o key del failed"); + init_nat_k (&kv, l_addr, l_port, match_local->fib_index, proto); + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0)) + nat_elog_err (sm, "static_mapping_by_local key del failed"); } if (sm->num_workers > 1) @@ -1382,7 +1504,7 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, s->in2out.port != match_local->port) continue; - nat44_ed_free_session_data (sm, s, tsm - sm->per_thread_data, 0); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1); } @@ -2041,8 +2163,8 @@ test_key_calc_split () u32 thread_index = 3000000001; u32 session_index = 3000000221; clib_bihash_kv_16_8_t kv; - init_ed_kv (&kv, l_addr.as_u32, l_port, r_addr.as_u32, r_port, fib_index, - proto, thread_index, session_index); + init_ed_kv (&kv, l_addr, l_port, r_addr, r_port, fib_index, proto, + thread_index, session_index); ip4_address_t l_addr2; ip4_address_t r_addr2; clib_memset (&l_addr2, 0, sizeof (l_addr2)); @@ -2061,6 +2183,16 @@ test_key_calc_split () ASSERT (fib_index == fib_index2); ASSERT (thread_index == ed_value_get_thread_index (&kv)); ASSERT (session_index == ed_value_get_session_index (&kv)); + + fib_index = 7001; + proto = 5; + nat_protocol_t proto3 = ~0; + u64 key = calc_nat_key (l_addr, l_port, fib_index, proto); + split_nat_key (key, &l_addr2, &l_port2, &fib_index2, &proto3); + ASSERT (l_addr.as_u32 == l_addr2.as_u32); + ASSERT (l_port == l_port2); + ASSERT (proto == proto3); + ASSERT (fib_index == fib_index2); } static clib_error_t * @@ -2309,6 +2441,14 @@ nat44_plugin_enable (nat44_config_t c) void nat44_addresses_free (snat_address_t ** addresses) { + snat_address_t *ap; + vec_foreach (ap, *addresses) + { + #define _(N, i, n, s) \ + vec_free (ap->busy_##n##_ports_per_thread); + foreach_nat_protocol + #undef _ + } vec_free (*addresses); *addresses = 0; } @@ -2408,7 +2548,7 @@ nat44_ed_forwarding_enable_disable (u8 is_enable) vec_foreach (ses_index, ses_to_be_removed) { s = pool_elt_at_index (tsm->sessions, ses_index[0]); - nat44_ed_free_session_data (sm, s, tsm - sm->per_thread_data, 0); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1); } @@ -2416,87 +2556,87 @@ nat44_ed_forwarding_enable_disable (u8 is_enable) } } -static_always_inline snat_static_mapping_t * -nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, - u32 match_fib_index, ip_protocol_t match_protocol, - int by_external) +void +snat_free_outside_address_and_port (snat_address_t *addresses, + u32 thread_index, ip4_address_t *addr, + u16 port, nat_protocol_t protocol) { - snat_static_mapping_t *m; - if (!by_external) - { - m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, match_fib_index, - match_protocol); - if (m) - return m; + snat_main_t *sm = &snat_main; + snat_address_t *a; + u32 address_index; + u16 port_host_byte_order = clib_net_to_host_u16 (port); - /* Try address only mapping */ - m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, match_fib_index, 0); - if (m) - return m; + for (address_index = 0; address_index < vec_len (addresses); + address_index++) + { + if (addresses[address_index].addr.as_u32 == addr->as_u32) + break; + } - if (sm->inside_fib_index != match_fib_index) - { - m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, - sm->inside_fib_index, match_protocol); - if (m) - return m; + ASSERT (address_index < vec_len (addresses)); - /* Try address only mapping */ - m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->inside_fib_index, - 0); - if (m) - return m; - } - if (sm->outside_fib_index != match_fib_index) - { - m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, - sm->outside_fib_index, match_protocol); - if (m) - return m; + a = addresses + address_index; - /* Try address only mapping */ - m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->outside_fib_index, - 0); - if (m) - return m; - } - } - else + switch (protocol) { - m = - nat44_ed_sm_o2i_lookup (sm, match_addr, match_port, 0, match_protocol); - if (m) - return m; - - /* Try address only mapping */ - m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0); - if (m) - return m; +#define _(N, i, n, s) \ + case NAT_PROTOCOL_##N: \ + ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \ + --a->busy_##n##_port_refcounts[port_host_byte_order]; \ + a->busy_##n##_ports--; \ + a->busy_##n##_ports_per_thread[thread_index]--; \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + return; } - return 0; } int snat_static_mapping_match (vlib_main_t *vm, snat_main_t *sm, ip4_address_t match_addr, u16 match_port, - u32 match_fib_index, ip_protocol_t match_protocol, + u32 match_fib_index, nat_protocol_t match_protocol, ip4_address_t *mapping_addr, u16 *mapping_port, - u32 *mapping_fib_index, int by_external, + u32 *mapping_fib_index, u8 by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat, snat_static_mapping_t **out) { + clib_bihash_kv_8_8_t kv, value; + clib_bihash_8_8_t *mapping_hash; snat_static_mapping_t *m; u32 rand, lo = 0, hi, mid, *tmp = 0, i; nat44_lb_addr_port_t *local; u8 backend_index; - m = nat44_ed_sm_match (sm, match_addr, match_port, match_fib_index, - match_protocol, by_external); - if (!m) + if (!by_external) { - return 1; + mapping_hash = &sm->static_mapping_by_local; + init_nat_k (&kv, match_addr, match_port, match_fib_index, + match_protocol); + if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) + { + /* Try address only mapping */ + init_nat_k (&kv, match_addr, 0, match_fib_index, 0); + if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) + return 1; + } } + else + { + mapping_hash = &sm->static_mapping_by_external; + init_nat_k (&kv, match_addr, match_port, 0, match_protocol); + if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) + { + /* Try address only mapping */ + init_nat_k (&kv, match_addr, 0, 0, 0); + if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) + return 1; + } + } + + m = pool_elt_at_index (sm->static_mappings, value.value); if (by_external) { @@ -2674,9 +2814,8 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, b, ip, &lookup_saddr, &lookup_sport, &lookup_daddr, &lookup_dport, &lookup_protocol)) { - init_ed_k (&kv16, lookup_saddr.as_u32, lookup_sport, - lookup_daddr.as_u32, lookup_dport, rx_fib_index, - lookup_protocol); + init_ed_k (&kv16, lookup_saddr, lookup_sport, lookup_daddr, + lookup_dport, rx_fib_index, lookup_protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)) { next_worker_index = ed_value_get_thread_index (&value16); @@ -2687,10 +2826,9 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, } } - init_ed_k (&kv16, ip->src_address.as_u32, - vnet_buffer (b)->ip.reass.l4_src_port, ip->dst_address.as_u32, - vnet_buffer (b)->ip.reass.l4_dst_port, fib_index, - ip->protocol); + init_ed_k (&kv16, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port, + ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, + fib_index, ip->protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)) { @@ -2701,10 +2839,9 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, } // dst NAT - init_ed_k (&kv16, ip->dst_address.as_u32, - vnet_buffer (b)->ip.reass.l4_dst_port, ip->src_address.as_u32, - vnet_buffer (b)->ip.reass.l4_src_port, rx_fib_index, - ip->protocol); + init_ed_k (&kv16, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, + ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port, + rx_fib_index, ip->protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)) { next_worker_index = ed_value_get_thread_index (&value16); @@ -2746,16 +2883,17 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u8 is_output) { snat_main_t *sm = &snat_main; + clib_bihash_kv_8_8_t kv, value; clib_bihash_kv_16_8_t kv16, value16; - u8 proto, next_worker_index = 0; + u32 proto, next_worker_index = 0; u16 port; snat_static_mapping_t *m; u32 hash; - proto = ip->protocol; + proto = ip_proto_to_nat_proto (ip->protocol); - if (PREDICT_FALSE (IP_PROTOCOL_ICMP == proto)) + if (PREDICT_FALSE (proto == NAT_PROTOCOL_ICMP)) { ip4_address_t lookup_saddr, lookup_daddr; u16 lookup_sport, lookup_dport; @@ -2764,9 +2902,8 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, b, ip, &lookup_saddr, &lookup_sport, &lookup_daddr, &lookup_dport, &lookup_protocol)) { - init_ed_k (&kv16, lookup_saddr.as_u32, lookup_sport, - lookup_daddr.as_u32, lookup_dport, rx_fib_index, - lookup_protocol); + init_ed_k (&kv16, lookup_saddr, lookup_sport, lookup_daddr, + lookup_dport, rx_fib_index, lookup_protocol); if (PREDICT_TRUE ( !clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16))) { @@ -2780,10 +2917,9 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, } } - init_ed_k (&kv16, ip->src_address.as_u32, - vnet_buffer (b)->ip.reass.l4_src_port, ip->dst_address.as_u32, - vnet_buffer (b)->ip.reass.l4_dst_port, rx_fib_index, - ip->protocol); + init_ed_k (&kv16, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port, + ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, + rx_fib_index, ip->protocol); if (PREDICT_TRUE ( !clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16))) @@ -2801,18 +2937,18 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, /* first try static mappings without port */ if (PREDICT_FALSE (pool_elts (sm->static_mappings))) { - m = nat44_ed_sm_o2i_lookup (sm, ip->dst_address, 0, 0, proto); - if (m) + init_nat_k (&kv, ip->dst_address, 0, 0, 0); + if (!clib_bihash_search_8_8 + (&sm->static_mapping_by_external, &kv, &value)) { - { - next_worker_index = m->workers[0]; - goto done; - } + m = pool_elt_at_index (sm->static_mappings, value.value); + next_worker_index = m->workers[0]; + goto done; } } /* unknown protocol */ - if (PREDICT_FALSE (nat44_ed_is_unk_proto (proto))) + if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER)) { /* use current thread */ next_worker_index = vlib_get_thread_index (); @@ -2833,18 +2969,17 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, { /* if error message, then it's not fragmented and we can access it */ ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1); - proto = inner_ip->protocol; + proto = ip_proto_to_nat_proto (inner_ip->protocol); void *l4_header = ip4_next_header (inner_ip); switch (proto) { - case IP_PROTOCOL_ICMP: + case NAT_PROTOCOL_ICMP: icmp = (icmp46_header_t *) l4_header; echo = (icmp_echo_header_t *) (icmp + 1); port = echo->identifier; break; - case IP_PROTOCOL_UDP: - /* breakthrough */ - case IP_PROTOCOL_TCP: + case NAT_PROTOCOL_UDP: + case NAT_PROTOCOL_TCP: port = ((tcp_udp_header_t *) l4_header)->src_port; break; default: @@ -2857,9 +2992,11 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, /* try static mappings with port */ if (PREDICT_FALSE (pool_elts (sm->static_mappings))) { - m = nat44_ed_sm_o2i_lookup (sm, ip->dst_address, port, 0, proto); - if (m) + init_nat_k (&kv, ip->dst_address, port, 0, proto); + if (!clib_bihash_search_8_8 + (&sm->static_mapping_by_external, &kv, &value)) { + m = pool_elt_at_index (sm->static_mappings, value.value); if (!is_sm_lb (m->flags)) { next_worker_index = m->workers[0]; @@ -2989,9 +3126,23 @@ nat44_ed_db_init (u32 translations, u32 translation_buckets) { snat_main_t *sm = &snat_main; snat_main_per_thread_data_t *tsm; + u32 static_mapping_buckets = 1024; + u32 static_mapping_memory_size = 64 << 20; reinit_ed_flow_hash (); + clib_bihash_init_8_8 (&sm->static_mapping_by_local, + "static_mapping_by_local", static_mapping_buckets, + static_mapping_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local, + format_static_mapping_kvp); + + clib_bihash_init_8_8 (&sm->static_mapping_by_external, + "static_mapping_by_external", static_mapping_buckets, + static_mapping_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external, + format_static_mapping_kvp); + if (sm->pat) { vec_foreach (tsm, sm->per_thread_data) @@ -3018,6 +3169,8 @@ nat44_ed_db_free () pool_free (sm->static_mappings); clib_bihash_free_16_8 (&sm->flow_hash); + clib_bihash_free_8_8 (&sm->static_mapping_by_local); + clib_bihash_free_8_8 (&sm->static_mapping_by_external); if (sm->pat) { @@ -3054,6 +3207,7 @@ nat44_ed_add_del_static_mapping_addr_only_cb ( ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete) { + clib_bihash_kv_8_8_t kv, value; snat_static_map_resolve_t *rp; snat_main_t *sm = &snat_main; snat_static_mapping_t *m; @@ -3079,8 +3233,17 @@ nat44_ed_add_del_static_mapping_addr_only_cb ( return; } - m = nat44_ed_sm_o2i_lookup (sm, *address, rp->addr_only ? 0 : rp->e_port, 0, - rp->proto); + init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port, + sm->outside_fib_index, rp->addr_only ? 0 : rp->proto); + + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) + { + m = 0; + } + else + { + m = pool_elt_at_index (sm->static_mappings, value.value); + } if (is_delete) { @@ -3323,8 +3486,7 @@ nat44_ed_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, else tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - init_ed_k (&kv, addr->as_u32, port, eh_addr->as_u32, eh_port, fib_index, - proto); + init_ed_k (&kv, *addr, port, *eh_addr, eh_port, fib_index, proto); if (clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) { return VNET_API_ERROR_NO_SUCH_ENTRY; @@ -3333,7 +3495,7 @@ nat44_ed_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, if (pool_is_free_index (tsm->sessions, ed_value_get_session_index (&value))) return VNET_API_ERROR_UNSPECIFIED; s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value)); - nat44_ed_free_session_data (sm, s, tsm - sm->per_thread_data, 0); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1); return 0; } @@ -3439,13 +3601,13 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, static_always_inline void nat_6t_flow_ip4_translate (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, + nat_6t_flow_t *f, nat_protocol_t proto, int is_icmp_inner_ip4, int skip_saddr_rewrite) { udp_header_t *udp = ip4_next_header (ip); tcp_header_t *tcp = (tcp_header_t *) udp; - if ((IP_PROTOCOL_TCP == proto || IP_PROTOCOL_UDP == proto) && + if ((NAT_PROTOCOL_TCP == proto || NAT_PROTOCOL_UDP == proto) && !vnet_buffer (b)->ip.reass.is_non_first_fragment) { if (!is_icmp_inner_ip4) @@ -3463,7 +3625,7 @@ nat_6t_flow_ip4_translate (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, udp->dst_port = f->rewrite.sport; } - if (IP_PROTOCOL_TCP == proto) + if (NAT_PROTOCOL_TCP == proto) { ip_csum_t tcp_sum = tcp->checksum; tcp_sum = ip_csum_sub_even (tcp_sum, f->l3_csum_delta); @@ -3471,7 +3633,7 @@ nat_6t_flow_ip4_translate (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, mss_clamping (sm->mss_clamping, tcp, &tcp_sum); tcp->checksum = ip_csum_fold (tcp_sum); } - else if (IP_PROTOCOL_UDP == proto && udp->checksum) + else if (proto == NAT_PROTOCOL_UDP && udp->checksum) { ip_csum_t udp_sum = udp->checksum; udp_sum = ip_csum_sub_even (udp_sum, f->l3_csum_delta); @@ -3569,7 +3731,8 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, return NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT; } - ip_protocol_t inner_proto = inner_ip->protocol; + nat_protocol_t inner_proto = + ip_proto_to_nat_proto (inner_ip->protocol); ip_csum_t old_icmp_sum = icmp->checksum; ip_csum_t old_inner_ip_sum = inner_ip->checksum; @@ -3581,7 +3744,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, switch (inner_proto) { - case IP_PROTOCOL_UDP: + case NAT_PROTOCOL_UDP: udp = (udp_header_t *) (inner_ip + 1); if (!it_fits (vm, b, udp, sizeof (*udp))) { @@ -3602,7 +3765,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, new_icmp_sum = ip_csum_fold (new_icmp_sum); icmp->checksum = new_icmp_sum; break; - case IP_PROTOCOL_TCP: + case NAT_PROTOCOL_TCP: tcp = (tcp_header_t *) (inner_ip + 1); if (!it_fits (vm, b, tcp, sizeof (*tcp))) { @@ -3623,7 +3786,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, new_icmp_sum = ip_csum_fold (new_icmp_sum); icmp->checksum = new_icmp_sum; break; - case IP_PROTOCOL_ICMP: + case NAT_PROTOCOL_ICMP: if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) { icmp46_header_t *inner_icmp = ip4_next_header (inner_ip); @@ -3662,7 +3825,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, static_always_inline nat_translation_error_e nat_6t_flow_buf_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, nat_6t_flow_t *f, - ip_protocol_t proto, int is_output_feature, + nat_protocol_t proto, int is_output_feature, int is_i2o) { if (!is_output_feature && f->ops & NAT_FLOW_OP_TXFIB_REWRITE) @@ -3670,7 +3833,7 @@ nat_6t_flow_buf_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, vnet_buffer (b)->sw_if_index[VLIB_TX] = f->rewrite.fib_index; } - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == proto) { if (ip->src_address.as_u32 != f->rewrite.saddr.as_u32) { @@ -3698,7 +3861,7 @@ nat_6t_flow_buf_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, nat_translation_error_e nat_6t_flow_buf_translate_i2o (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, + nat_6t_flow_t *f, nat_protocol_t proto, int is_output_feature) { return nat_6t_flow_buf_translate (vm, sm, b, ip, f, proto, is_output_feature, @@ -3708,7 +3871,7 @@ nat_6t_flow_buf_translate_i2o (vlib_main_t *vm, snat_main_t *sm, nat_translation_error_e nat_6t_flow_buf_translate_o2i (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, + nat_6t_flow_t *f, nat_protocol_t proto, int is_output_feature) { return nat_6t_flow_buf_translate (vm, sm, b, ip, f, proto, is_output_feature, @@ -3818,81 +3981,6 @@ format_nat_6t_flow (u8 *s, va_list *args) return s; } -static inline void -nat_syslog_nat44_sess (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, - u16 isport, ip4_address_t *xsaddr, u16 xsport, - ip4_address_t *idaddr, u16 idport, - ip4_address_t *xdaddr, u16 xdport, u8 proto, u8 is_add, - u8 is_twicenat) -{ - syslog_msg_t syslog_msg; - fib_table_t *fib; - - if (!syslog_is_enabled ()) - return; - - if (syslog_severity_filter_block (SADD_SDEL_SEVERITY)) - return; - - fib = fib_table_get (sfibix, FIB_PROTOCOL_IP4); - - syslog_msg_init (&syslog_msg, NAT_FACILITY, SADD_SDEL_SEVERITY, NAT_APPNAME, - is_add ? SADD_MSGID : SDEL_MSGID); - - syslog_msg_sd_init (&syslog_msg, NSESS_SDID); - syslog_msg_add_sd_param (&syslog_msg, SSUBIX_SDPARAM_NAME, "%d", ssubix); - syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d", - fib->ft_table_id); - syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV4); - syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U", - format_ip4_address, isaddr); - syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d", - clib_net_to_host_u16 (isport)); - syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4); - syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U", - format_ip4_address, xsaddr); - syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d", - clib_net_to_host_u16 (xsport)); - syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d", proto); - syslog_msg_add_sd_param (&syslog_msg, XDADDR_SDPARAM_NAME, "%U", - format_ip4_address, xdaddr); - syslog_msg_add_sd_param (&syslog_msg, XDPORT_SDPARAM_NAME, "%d", - clib_net_to_host_u16 (xdport)); - if (is_twicenat) - { - syslog_msg_add_sd_param (&syslog_msg, IDADDR_SDPARAM_NAME, "%U", - format_ip4_address, idaddr); - syslog_msg_add_sd_param (&syslog_msg, IDPORT_SDPARAM_NAME, "%d", - clib_net_to_host_u16 (idport)); - } - - syslog_msg_send (&syslog_msg); -} - -void -nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, - u16 isport, ip4_address_t *idaddr, u16 idport, - ip4_address_t *xsaddr, u16 xsport, - ip4_address_t *xdaddr, u16 xdport, u8 proto, - u8 is_twicenat) -{ - nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport, - idaddr, idport, xdaddr, xdport, proto, 1, - is_twicenat); -} - -void -nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, - u16 isport, ip4_address_t *idaddr, u16 idport, - ip4_address_t *xsaddr, u16 xsport, - ip4_address_t *xdaddr, u16 xdport, u8 proto, - u8 is_twicenat) -{ - nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport, - idaddr, idport, xdaddr, xdport, proto, 0, - is_twicenat); -} - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/nat/nat44-ed/nat44_ed.h b/src/plugins/nat/nat44-ed/nat44_ed.h index 4665f7c0966..e2f5810f9b0 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.h +++ b/src/plugins/nat/nat44-ed/nat44_ed.h @@ -39,11 +39,6 @@ /* default number of worker handoff frame queue elements */ #define NAT_FQ_NELTS_DEFAULT 64 -/* number of attempts to get a port for ED overloading algorithm, if rolling - * a dice this many times doesn't produce a free port, it's treated - * as if there were no free ports available to conserve resources */ -#define ED_PORT_ALLOC_ATTEMPTS (10) - /* NAT buffer flags */ #define SNAT_FLAG_HAIRPINNING (1 << 0) @@ -177,6 +172,7 @@ typedef enum /* Session flags */ #define SNAT_SESSION_FLAG_STATIC_MAPPING (1 << 0) +#define SNAT_SESSION_FLAG_UNKNOWN_PROTO (1 << 1) #define SNAT_SESSION_FLAG_LOAD_BALANCING (1 << 2) #define SNAT_SESSION_FLAG_TWICE_NAT (1 << 3) #define SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT (1 << 4) @@ -312,7 +308,7 @@ typedef CLIB_PACKED(struct u16 port; } in2out; - ip_protocol_t proto; + nat_protocol_t nat_proto; nat_6t_flow_t i2o; nat_6t_flow_t o2i; @@ -360,6 +356,12 @@ typedef struct { ip4_address_t addr; u32 fib_index; +#define _(N, i, n, s) \ + u32 busy_##n##_ports; \ + u32 * busy_##n##_ports_per_thread; \ + u32 busy_##n##_port_refcounts[65535]; + foreach_nat_protocol +#undef _ } snat_address_t; typedef struct @@ -424,7 +426,7 @@ typedef struct u32 vrf_id; u32 fib_index; /* protocol */ - ip_protocol_t proto; + nat_protocol_t proto; /* 0 = disabled, otherwise client IP affinity sticky time in seconds */ u32 affinity; /* worker threads used by backends/local host */ @@ -453,7 +455,7 @@ typedef struct u16 e_port; u32 sw_if_index; u32 vrf_id; - ip_protocol_t proto; + nat_protocol_t proto; u32 flags; int addr_only; int twice_nat; @@ -498,10 +500,15 @@ u32 nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, /* Return worker thread index for given packet */ /* NAT address and port allocation function */ -typedef int (nat_alloc_out_addr_and_port_function_t) ( - snat_address_t *addresses, u32 fib_index, u32 thread_index, - ip_protocol_t proto, ip4_address_t *addr, u16 *port, u16 port_per_thread, - u32 snat_thread_index); +typedef int (nat_alloc_out_addr_and_port_function_t) (snat_address_t * + addresses, + u32 fib_index, + u32 thread_index, + nat_protocol_t proto, + ip4_address_t * addr, + u16 * port, + u16 port_per_thread, + u32 snat_thread_index); typedef struct snat_main_s { @@ -514,6 +521,12 @@ typedef struct snat_main_s /* Per thread data */ snat_main_per_thread_data_t *per_thread_data; + /* Find a static mapping by local */ + clib_bihash_8_8_t static_mapping_by_local; + + /* Find a static mapping by external */ + clib_bihash_8_8_t static_mapping_by_external; + /* Static mapping pool */ snat_static_mapping_t *static_mappings; @@ -702,8 +715,12 @@ extern fib_source_t nat_fib_src_low; format_function_t format_snat_static_mapping; format_function_t format_snat_static_map_to_resolve; format_function_t format_snat_session; +format_function_t format_snat_key; format_function_t format_static_mapping_key; +format_function_t format_nat_protocol; format_function_t format_nat_addr_and_port_alloc_alg; +/* unformat functions */ +unformat_function_t unformat_nat_protocol; /** \brief Check if SNAT session is created from static mapping. @param s SNAT session @@ -715,6 +732,16 @@ nat44_ed_is_session_static (snat_session_t *s) return s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING; } +/** \brief Check if SNAT session for unknown protocol. + @param s SNAT session + @return true if SNAT session for unknown protocol otherwise 0 +*/ +always_inline bool +snat_is_unk_proto_session (snat_session_t *s) +{ + return s->flags & SNAT_SESSION_FLAG_UNKNOWN_PROTO; +} + /** \brief Check if NAT session is twice NAT. @param s NAT session @return true if NAT session is twice NAT @@ -883,25 +910,25 @@ int nat44_ed_add_interface_address (u32 sw_if_index, u8 twice_nat); int nat44_ed_del_interface_address (u32 sw_if_index, u8 twice_nat); int nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, ip_protocol_t proto, + u16 l_port, u16 e_port, nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, ip4_address_t pool_addr, u8 *tag); int nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, ip_protocol_t proto, + u16 l_port, u16 e_port, nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags); int nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, - ip_protocol_t proto, + nat_protocol_t proto, nat44_lb_addr_port_t *locals, u32 flags, u8 *tag, u32 affinity); int nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, - ip_protocol_t proto, u32 flags); + nat_protocol_t proto, u32 flags); int nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, ip4_address_t l_addr, u16 l_port, - ip_protocol_t proto, u32 vrf_id, + nat_protocol_t proto, u32 vrf_id, u8 probability, u8 is_add); /** @@ -920,8 +947,16 @@ int nat44_ed_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 vrf_id, int is_in); -void nat44_ed_free_session_data (snat_main_t *sm, snat_session_t *s, - u32 thread_index, u8 is_ha); +/** + * @brief Free NAT44 session data (lookup keys, external address port) + * + * @param sm snat global configuration data + * @param s NAT session + * @param thread_index thread index + * @param is_ha is HA event + */ +void nat_free_session_data (snat_main_t * sm, snat_session_t * s, + u32 thread_index, u8 is_ha); /** * @brief Set NAT44 session limit (session limit, vrf id) @@ -941,6 +976,19 @@ int nat44_set_session_limit (u32 session_limit, u32 vrf_id); */ int nat44_update_session_limit (u32 session_limit, u32 vrf_id); +/** + * @brief Free outside address and port pair + * + * @param addresses vector of outside addresses + * @param thread_index thread index + * @param key address, port and protocol + */ +void +snat_free_outside_address_and_port (snat_address_t * addresses, + u32 thread_index, + ip4_address_t * addr, + u16 port, nat_protocol_t protocol); + void expire_per_vrf_sessions (u32 fib_index); /** @@ -963,9 +1011,9 @@ void expire_per_vrf_sessions (u32 fib_index); */ int snat_static_mapping_match ( vlib_main_t *vm, snat_main_t *sm, ip4_address_t match_addr, u16 match_port, - u32 match_fib_index, ip_protocol_t match_protocol, + u32 match_fib_index, nat_protocol_t match_protocol, ip4_address_t *mapping_addr, u16 *mapping_port, u32 *mapping_fib_index, - int by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, + u8 by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat, snat_static_mapping_t **out); @@ -1012,11 +1060,11 @@ typedef enum nat_translation_error_e nat_6t_flow_buf_translate_i2o ( vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, int is_output_feature); + nat_6t_flow_t *f, nat_protocol_t proto, int is_output_feature); nat_translation_error_e nat_6t_flow_buf_translate_o2i ( vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, int is_output_feature); + nat_6t_flow_t *f, nat_protocol_t proto, int is_output_feature); void nat_6t_l3_l4_csum_calc (nat_6t_flow_t *f); @@ -1024,26 +1072,6 @@ format_function_t format_nat_ed_translation_error; format_function_t format_nat_6t_flow; format_function_t format_ed_session_kvp; -snat_static_mapping_t *nat44_ed_sm_i2o_lookup (snat_main_t *sm, - ip4_address_t addr, u16 port, - u32 fib_index, u8 proto); - -snat_static_mapping_t *nat44_ed_sm_o2i_lookup (snat_main_t *sm, - ip4_address_t addr, u16 port, - u32 fib_index, u8 proto); - -void nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, - u16 isport, ip4_address_t *idaddr, u16 idport, - ip4_address_t *xsaddr, u16 xsport, - ip4_address_t *xdaddr, u16 xdport, u8 proto, - u8 is_twicenat); - -void nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, - u16 isport, ip4_address_t *idaddr, u16 idport, - ip4_address_t *xsaddr, u16 xsport, - ip4_address_t *xdaddr, u16 xdport, u8 proto, - u8 is_twicenat); - #endif /* __included_nat44_ed_h__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat44-ed/nat44_ed_affinity.c b/src/plugins/nat/nat44-ed/nat44_ed_affinity.c index 178671c6b7e..89f11c64ef3 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_affinity.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_affinity.c @@ -37,9 +37,10 @@ format_affinity_kvp (u8 * s, va_list * args) k.as_u64[1] = v->key[1]; s = format (s, "client %U backend %U:%d proto %U index %llu", - format_ip4_address, &k.client_addr, format_ip4_address, - &k.service_addr, clib_net_to_host_u16 (k.service_port), - format_ip_protocol, k.proto); + format_ip4_address, &k.client_addr, + format_ip4_address, &k.service_addr, + clib_net_to_host_u16 (k.service_port), + format_nat_protocol, k.proto); return s; } diff --git a/src/plugins/nat/nat44-ed/nat44_ed_api.c b/src/plugins/nat/nat44-ed/nat44_ed_api.c index d37c2855158..ad00d11052b 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_api.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_api.c @@ -628,7 +628,7 @@ static void ip4_address_t l_addr, e_addr, pool_addr = { 0 }; u32 sw_if_index, flags = 0, vrf_id; u16 l_port = 0, e_port = 0; - ip_protocol_t proto = 0; + nat_protocol_t proto = 0; u8 *tag = 0; memcpy (&l_addr.as_u8, mp->local_ip_address, 4); @@ -641,7 +641,7 @@ static void { l_port = mp->local_port; e_port = mp->external_port; - proto = mp->protocol; + proto = ip_proto_to_nat_proto (mp->protocol); } if (mp->flags & NAT_API_IS_TWICE_NAT) @@ -702,7 +702,7 @@ static void ip4_address_t l_addr, e_addr, pool_addr; u32 sw_if_index, flags = 0, vrf_id; u16 l_port = 0, e_port = 0; - ip_protocol_t proto; + nat_protocol_t proto; u8 *tag = 0; memcpy (&l_addr.as_u8, mp->local_ip_address, 4); @@ -748,7 +748,7 @@ static void memcpy (&e_addr.as_u8, mp->external_ip_address, 4); } - proto = mp->protocol; + proto = ip_proto_to_nat_proto (mp->protocol); vrf_id = clib_net_to_host_u32 (mp->vrf_id); if (mp->is_add) @@ -812,7 +812,7 @@ send_nat44_static_mapping_details (snat_static_mapping_t * m, } else { - rmp->protocol = m->proto; + rmp->protocol = nat_proto_to_ip_proto (m->proto); rmp->external_port = m->external_port; rmp->local_port = m->local_port; } @@ -849,7 +849,7 @@ send_nat44_static_map_resolve_details (snat_static_map_resolve_t * m, } else { - rmp->protocol = m->proto; + rmp->protocol = nat_proto_to_ip_proto (m->proto); rmp->external_port = m->e_port; rmp->local_port = m->l_port; } @@ -898,7 +898,7 @@ static void ip4_address_t addr, pool_addr = { 0 }; u32 sw_if_index, flags, vrf_id; - ip_protocol_t proto = 0; + nat_protocol_t proto = 0; u16 port = 0; u8 *tag = 0; @@ -911,7 +911,7 @@ static void else { port = mp->port; - proto = mp->protocol; + proto = ip_proto_to_nat_proto (mp->protocol); } sw_if_index = clib_net_to_host_u32 (mp->sw_if_index); @@ -964,7 +964,7 @@ send_nat44_identity_mapping_details (snat_static_mapping_t * m, int index, rmp->port = m->local_port; rmp->sw_if_index = ~0; rmp->vrf_id = htonl (local->vrf_id); - rmp->protocol = m->proto; + rmp->protocol = nat_proto_to_ip_proto (m->proto); rmp->context = context; if (m->tag) strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag)); @@ -991,7 +991,7 @@ send_nat44_identity_map_resolve_details (snat_static_map_resolve_t * m, rmp->port = m->l_port; rmp->sw_if_index = htonl (m->sw_if_index); rmp->vrf_id = htonl (m->vrf_id); - rmp->protocol = m->proto; + rmp->protocol = nat_proto_to_ip_proto (m->proto); rmp->context = context; if (m->tag) strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag)); @@ -1140,7 +1140,7 @@ vl_api_nat44_add_del_lb_static_mapping_t_handler ( vl_api_nat44_add_del_lb_static_mapping_reply_t *rmp; nat44_lb_addr_port_t *locals = 0; ip4_address_t e_addr; - ip_protocol_t proto; + nat_protocol_t proto; u32 flags = 0; u8 *tag = 0; int rv = 0; @@ -1148,7 +1148,7 @@ vl_api_nat44_add_del_lb_static_mapping_t_handler ( locals = unformat_nat44_lb_addr_port (mp->locals, clib_net_to_host_u32 (mp->local_num)); clib_memcpy (&e_addr, mp->external_addr, 4); - proto = mp->protocol; + proto = ip_proto_to_nat_proto (mp->protocol); if (mp->flags & NAT_API_IS_TWICE_NAT) { @@ -1193,11 +1193,11 @@ vl_api_nat44_lb_static_mapping_add_del_local_t_handler ( vl_api_nat44_lb_static_mapping_add_del_local_reply_t *rmp; int rv = 0; ip4_address_t e_addr, l_addr; - ip_protocol_t proto; + nat_protocol_t proto; clib_memcpy (&e_addr, mp->external_addr, 4); clib_memcpy (&l_addr, mp->local.addr, 4); - proto = mp->protocol; + proto = ip_proto_to_nat_proto (mp->protocol); rv = nat44_ed_add_del_lb_static_mapping_local ( e_addr, mp->external_port, l_addr, mp->local.port, proto, @@ -1225,7 +1225,7 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t *m, clib_memcpy (rmp->external_addr, &(m->external_addr), 4); rmp->external_port = m->external_port; - rmp->protocol = m->proto; + rmp->protocol = nat_proto_to_ip_proto (m->proto); rmp->context = context; if (is_sm_self_twice_nat (m->flags)) @@ -1740,16 +1740,25 @@ send_nat44_user_session_details (snat_session_t * s, rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes); rmp->total_pkts = ntohl (s->total_pkts); rmp->context = context; - rmp->outside_port = s->out2in.port; - rmp->inside_port = s->in2out.port; - rmp->protocol = ntohs (s->proto); - clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4); - rmp->ext_host_port = s->ext_host_port; - if (nat44_ed_is_twice_nat_session (s)) + if (snat_is_unk_proto_session (s)) { - clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4); - rmp->ext_host_nat_port = s->ext_host_nat_port; + rmp->outside_port = 0; + rmp->inside_port = 0; + rmp->protocol = ntohs (s->in2out.port); } + else + { + rmp->outside_port = s->out2in.port; + rmp->inside_port = s->in2out.port; + rmp->protocol = ntohs (nat_proto_to_ip_proto (s->nat_proto)); + } + clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4); + rmp->ext_host_port = s->ext_host_port; + if (nat44_ed_is_twice_nat_session (s)) + { + clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4); + rmp->ext_host_nat_port = s->ext_host_nat_port; + } vl_api_send_msg (reg, (u8 *) rmp); } diff --git a/src/plugins/nat/nat44-ed/nat44_ed_classify.c b/src/plugins/nat/nat44-ed/nat44_ed_classify.c index 229cf3669e6..5a9f4e42657 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_classify.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_classify.c @@ -98,6 +98,7 @@ nat44_handoff_classify_node_fn_inline (vlib_main_t * vm, u32 next0 = NAT_NEXT_IN2OUT_CLASSIFY; ip4_header_t *ip0; snat_address_t *ap; + clib_bihash_kv_8_8_t kv0, value0; /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; @@ -121,19 +122,23 @@ nat44_handoff_classify_node_fn_inline (vlib_main_t * vm, if (PREDICT_FALSE (pool_elts (sm->static_mappings))) { + init_nat_k (&kv0, ip0->dst_address, 0, 0, 0); /* try to classify the fragment based on IP header alone */ - m = nat44_ed_sm_o2i_lookup (sm, ip0->dst_address, 0, 0, 0); - if (m) + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, + &kv0, &value0)) { + m = pool_elt_at_index (sm->static_mappings, value0.value); if (m->local_addr.as_u32 != m->external_addr.as_u32) next0 = NAT_NEXT_OUT2IN_CLASSIFY; goto enqueue0; } - m = nat44_ed_sm_o2i_lookup ( - sm, ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port, - 0, ip0->protocol); - if (m) + init_nat_k (&kv0, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_dst_port, 0, + ip_proto_to_nat_proto (ip0->protocol)); + if (!clib_bihash_search_8_8 + (&sm->static_mapping_by_external, &kv0, &value0)) { + m = pool_elt_at_index (sm->static_mappings, value0.value); if (m->local_addr.as_u32 != m->external_addr.as_u32) next0 = NAT_NEXT_OUT2IN_CLASSIFY; } @@ -197,6 +202,7 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm, u32 sw_if_index0, rx_fib_index0; ip4_header_t *ip0; snat_address_t *ap; + clib_bihash_kv_8_8_t kv0, value0; clib_bihash_kv_16_8_t ed_kv0, ed_value0; /* speculatively enqueue b0 to the current next frame */ @@ -221,11 +227,11 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm, rx_fib_index0 = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index0); - init_ed_k (&ed_kv0, ip0->src_address.as_u32, + init_ed_k (&ed_kv0, ip0->src_address, vnet_buffer (b0)->ip.reass.l4_src_port, - ip0->dst_address.as_u32, - vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, - ip0->protocol); + ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_dst_port, + rx_fib_index0, ip0->protocol); /* process whole packet */ if (!clib_bihash_search_16_8 (&sm->flow_hash, &ed_kv0, &ed_value0)) @@ -266,19 +272,23 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm, if (PREDICT_FALSE (pool_elts (sm->static_mappings))) { + init_nat_k (&kv0, ip0->dst_address, 0, 0, 0); /* try to classify the fragment based on IP header alone */ - m = nat44_ed_sm_o2i_lookup (sm, ip0->dst_address, 0, 0, 0); - if (m) + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, + &kv0, &value0)) { + m = pool_elt_at_index (sm->static_mappings, value0.value); if (m->local_addr.as_u32 != m->external_addr.as_u32) next0 = NAT_NEXT_OUT2IN_ED_FAST_PATH; goto enqueue0; } - m = nat44_ed_sm_o2i_lookup ( - sm, ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port, - 0, ip0->protocol); - if (m) + init_nat_k (&kv0, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_dst_port, 0, + ip_proto_to_nat_proto (ip0->protocol)); + if (!clib_bihash_search_8_8 + (&sm->static_mapping_by_external, &kv0, &value0)) { + m = pool_elt_at_index (sm->static_mappings, value0.value); if (m->local_addr.as_u32 != m->external_addr.as_u32) next0 = NAT_NEXT_OUT2IN_ED_FAST_PATH; } diff --git a/src/plugins/nat/nat44-ed/nat44_ed_cli.c b/src/plugins/nat/nat44-ed/nat44_ed_cli.c index 5ab14a6729a..413c7959962 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_cli.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_cli.c @@ -283,7 +283,12 @@ nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input, else if (unformat (input, "verbose")) verbose = 2; - vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose); + vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->static_mapping_by_local, + verbose); + vlib_cli_output (vm, "%U", + format_bihash_8_8, &sm->static_mapping_by_external, + verbose); + vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose); vec_foreach_index (i, sm->per_thread_data) { vlib_cli_output (vm, "-------- thread %d %s --------\n", @@ -291,7 +296,8 @@ nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose); } - vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash, verbose); + vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash, + verbose); vlib_cli_output (vm, "-------- hash table parameters --------\n"); vlib_cli_output (vm, "translation buckets: %u", sm->translation_buckets); @@ -496,7 +502,6 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, u32 udp_sessions = 0; u32 tcp_sessions = 0; u32 icmp_sessions = 0; - u32 other_sessions = 0; u32 timed_out = 0; u32 transitory = 0; @@ -521,42 +526,40 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, if (now >= sess_timeout_time) timed_out++; - switch (s->proto) - { - case IP_PROTOCOL_ICMP: - icmp_sessions++; - break; - case IP_PROTOCOL_TCP: - tcp_sessions++; - if (s->state) - { - if (s->tcp_closed_timestamp) - { - if (now >= s->tcp_closed_timestamp) - { - ++transitory_closed; - } - else - { - ++transitory_wait_closed; - } - } - transitory++; - } - else - established++; - break; - case IP_PROTOCOL_UDP: - udp_sessions++; - break; - default: - ++other_sessions; - break; - } - } - nat44_show_lru_summary (vm, tsm, now, sess_timeout_time); - count += pool_elts (tsm->sessions); - } + switch (s->nat_proto) + { + case NAT_PROTOCOL_ICMP: + icmp_sessions++; + break; + case NAT_PROTOCOL_TCP: + tcp_sessions++; + if (s->state) + { + if (s->tcp_closed_timestamp) + { + if (now >= s->tcp_closed_timestamp) + { + ++transitory_closed; + } + else + { + ++transitory_wait_closed; + } + } + transitory++; + } + else + established++; + break; + case NAT_PROTOCOL_UDP: + default: + udp_sessions++; + break; + } + } + nat44_show_lru_summary (vm, tsm, now, sess_timeout_time); + count += pool_elts (tsm->sessions); + } } else { @@ -568,38 +571,36 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, if (now >= sess_timeout_time) timed_out++; - switch (s->proto) - { - case IP_PROTOCOL_ICMP: - icmp_sessions++; - break; - case IP_PROTOCOL_TCP: - tcp_sessions++; - if (s->state) - { - if (s->tcp_closed_timestamp) - { - if (now >= s->tcp_closed_timestamp) - { - ++transitory_closed; - } - else - { - ++transitory_wait_closed; - } - } - transitory++; - } - else - established++; - break; - case IP_PROTOCOL_UDP: - udp_sessions++; - break; - default: - ++other_sessions; - break; - } + switch (s->nat_proto) + { + case NAT_PROTOCOL_ICMP: + icmp_sessions++; + break; + case NAT_PROTOCOL_TCP: + tcp_sessions++; + if (s->state) + { + if (s->tcp_closed_timestamp) + { + if (now >= s->tcp_closed_timestamp) + { + ++transitory_closed; + } + else + { + ++transitory_wait_closed; + } + } + transitory++; + } + else + established++; + break; + case NAT_PROTOCOL_UDP: + default: + udp_sessions++; + break; + } } nat44_show_lru_summary (vm, tsm, now, sess_timeout_time); count = pool_elts (tsm->sessions); @@ -616,7 +617,6 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, transitory_closed); vlib_cli_output (vm, "total udp sessions: %u", udp_sessions); vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions); - vlib_cli_output (vm, "total other sessions: %u", other_sessions); return 0; } @@ -636,6 +636,10 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input, fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); else vlib_cli_output (vm, " tenant VRF independent"); + #define _(N, i, n, s) \ + vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); + foreach_nat_protocol + #undef _ } vlib_cli_output (vm, "NAT44 twice-nat pool addresses:"); vec_foreach (ap, sm->twice_nat_addresses) @@ -646,6 +650,10 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input, fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); else vlib_cli_output (vm, " tenant VRF independent"); + #define _(N, i, n, s) \ + vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); + foreach_nat_protocol + #undef _ } return 0; } @@ -829,13 +837,14 @@ add_static_mapping_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; vnet_main_t *vnm = vnet_get_main (); clib_error_t *error = 0; + int rv; + + nat_protocol_t proto = NAT_PROTOCOL_OTHER; ip4_address_t l_addr, e_addr, pool_addr; u32 l_port = 0, e_port = 0, vrf_id = ~0; u8 l_port_set = 0, e_port_set = 0; - int is_add = 1, rv; - u32 flags = 0; - u32 sw_if_index = ~0; - ip_protocol_t proto = 0; + u32 sw_if_index, flags = 0; + int is_add = 1; if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -877,7 +886,7 @@ add_static_mapping_command_fn (vlib_main_t * vm, } else if (unformat (line_input, "vrf %u", &vrf_id)) ; - else if (unformat (line_input, "%U", unformat_ip_protocol, &proto)) + else if (unformat (line_input, "%U", unformat_nat_protocol, &proto)) ; else if (unformat (line_input, "self-twice-nat")) { @@ -974,7 +983,7 @@ add_identity_mapping_command_fn (vlib_main_t * vm, int rv, is_add = 1, port_set = 0; u32 sw_if_index, port, flags, vrf_id = ~0; - ip_protocol_t proto; + nat_protocol_t proto; ip4_address_t addr; flags = NAT_SM_FLAG_IDENTITY_NAT; @@ -994,7 +1003,7 @@ add_identity_mapping_command_fn (vlib_main_t * vm, } else if (unformat (line_input, "vrf %u", &vrf_id)) ; - else if (unformat (line_input, "%U %u", unformat_ip_protocol, &proto, + else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto, &port)) { port_set = 1; @@ -1071,7 +1080,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, ip4_address_t l_addr, e_addr; u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0, affinity = 0; u8 proto_set = 0; - ip_protocol_t proto; + nat_protocol_t proto; nat44_lb_addr_port_t *locals = 0, local; int rv, is_add = 1; u32 flags = 0; @@ -1105,7 +1114,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, else if (unformat (line_input, "external %U:%u", unformat_ip4_address, &e_addr, &e_port)) ; - else if (unformat (line_input, "protocol %U", unformat_ip_protocol, + else if (unformat (line_input, "protocol %U", unformat_nat_protocol, &proto)) { proto_set = 1; @@ -1193,7 +1202,7 @@ add_lb_backend_command_fn (vlib_main_t * vm, u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0; int is_add = 1; int rv; - ip_protocol_t proto; + nat_protocol_t proto; u8 proto_set = 0; /* Get a line of input. */ @@ -1212,7 +1221,7 @@ add_lb_backend_command_fn (vlib_main_t * vm, else if (unformat (line_input, "external %U:%u", unformat_ip4_address, &e_addr, &e_port)) ; - else if (unformat (line_input, "protocol %U", unformat_ip_protocol, + else if (unformat (line_input, "protocol %U", unformat_nat_protocol, &proto)) proto_set = 1; else if (unformat (line_input, "del")) @@ -1538,7 +1547,7 @@ nat44_del_session_command_fn (vlib_main_t * vm, u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id; clib_error_t *error = 0; ip4_address_t addr, eh_addr; - ip_protocol_t proto; + nat_protocol_t proto; int is_in = 0; int rv; @@ -1547,8 +1556,9 @@ nat44_del_session_command_fn (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port, - unformat_ip_protocol, &proto)) + if (unformat + (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port, + unformat_nat_protocol, &proto)) ; else if (unformat (line_input, "in")) { @@ -1574,8 +1584,8 @@ nat44_del_session_command_fn (vlib_main_t * vm, } rv = nat44_ed_del_session (sm, &addr, clib_host_to_net_u16 (port), &eh_addr, - clib_host_to_net_u16 (eh_port), proto, vrf_id, - is_in); + clib_host_to_net_u16 (eh_port), + nat_proto_to_ip_proto (proto), vrf_id, is_in); switch (rv) { diff --git a/src/plugins/nat/nat44-ed/nat44_ed_format.c b/src/plugins/nat/nat44-ed/nat44_ed_format.c index 5eb683d888e..442f6ad3d7a 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_format.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_format.c @@ -20,6 +20,39 @@ #include <nat/nat44-ed/nat44_ed.h> #include <nat/nat44-ed/nat44_ed_inlines.h> +uword +unformat_nat_protocol (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(N, i, n, s) else if (unformat (input, s)) *r = NAT_PROTOCOL_##N; + foreach_nat_protocol +#undef _ + else + return 0; + return 1; +} + +u8 * +format_nat_protocol (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(N, j, n, str) case NAT_PROTOCOL_##N: t = (u8 *) str; break; + foreach_nat_protocol +#undef _ + default: + s = format (s, "unknown"); + return s; + } + s = format (s, "%s", t); + return s; +} + u8 * format_nat_addr_and_port_alloc_alg (u8 * s, va_list * args) { @@ -40,6 +73,25 @@ format_nat_addr_and_port_alloc_alg (u8 * s, va_list * args) } u8 * +format_snat_key (u8 * s, va_list * args) +{ + u64 key = va_arg (*args, u64); + + ip4_address_t addr; + u16 port; + nat_protocol_t protocol; + u32 fib_index; + + split_nat_key (key, &addr, &port, &fib_index, &protocol); + + s = format (s, "%U proto %U port %d fib %d", + format_ip4_address, &addr, + format_nat_protocol, protocol, + clib_net_to_host_u16 (port), fib_index); + return s; +} + +u8 * format_snat_session_state (u8 * s, va_list * args) { u32 i = va_arg (*args, u32); @@ -64,7 +116,7 @@ format_snat_session (u8 * s, va_list * args) va_arg (*args, snat_main_per_thread_data_t *); snat_session_t *sess = va_arg (*args, snat_session_t *); - if (nat44_ed_is_unk_proto (sess->proto)) + if (snat_is_unk_proto_session (sess)) { s = format (s, " i2o %U proto %u fib %u\n", format_ip4_address, &sess->in2out.addr, @@ -75,13 +127,14 @@ format_snat_session (u8 * s, va_list * args) } else { - s = format (s, " i2o %U proto %U port %d fib %d\n", format_ip4_address, - &sess->in2out.addr, format_ip_protocol, sess->proto, + s = format (s, " i2o %U proto %U port %d fib %d\n", + format_ip4_address, &sess->in2out.addr, + format_nat_protocol, sess->nat_proto, clib_net_to_host_u16 (sess->in2out.port), sess->in2out.fib_index); s = format (s, " o2i %U proto %U port %d fib %d\n", - format_ip4_address, &sess->out2in.addr, format_ip_protocol, - sess->proto, clib_net_to_host_u16 (sess->out2in.port), + format_ip4_address, &sess->out2in.addr, format_nat_protocol, + sess->nat_proto, clib_net_to_host_u16 (sess->out2in.port), sess->out2in.fib_index); } if (nat44_ed_is_twice_nat_session (sess)) @@ -130,8 +183,9 @@ format_snat_static_mapping (u8 * s, va_list * args) s = format (s, "identity mapping %U", format_ip4_address, &m->local_addr); else - s = format (s, "identity mapping %U %U:%d", format_ip_protocol, - m->proto, format_ip4_address, &m->local_addr, + s = format (s, "identity mapping %U %U:%d", + format_nat_protocol, m->proto, + format_ip4_address, &m->local_addr, clib_net_to_host_u16 (m->local_port)); pool_foreach (local, m->locals) @@ -155,8 +209,8 @@ format_snat_static_mapping (u8 * s, va_list * args) if (is_sm_lb (m->flags)) { s = - format (s, "%U external %U:%d %s %s", format_ip_protocol, m->proto, - format_ip4_address, &m->external_addr, + format (s, "%U external %U:%d %s %s", format_nat_protocol, + m->proto, format_ip4_address, &m->external_addr, clib_net_to_host_u16 (m->external_port), is_sm_twice_nat (m->flags) ? "twice-nat" : @@ -173,7 +227,7 @@ format_snat_static_mapping (u8 * s, va_list * args) } else s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s", - format_ip_protocol, m->proto, format_ip4_address, + format_nat_protocol, m->proto, format_ip4_address, &m->local_addr, clib_net_to_host_u16 (m->local_port), format_ip4_address, &m->external_addr, clib_net_to_host_u16 (m->external_port), m->vrf_id, @@ -196,11 +250,12 @@ format_snat_static_map_to_resolve (u8 * s, va_list * args) format_ip4_address, &m->l_addr, format_vnet_sw_if_index_name, vnm, m->sw_if_index, m->vrf_id); else - s = format (s, "%U local %U:%d external %U:%d vrf %d", format_ip_protocol, - m->proto, format_ip4_address, &m->l_addr, - clib_net_to_host_u16 (m->l_port), format_vnet_sw_if_index_name, - vnm, m->sw_if_index, clib_net_to_host_u16 (m->e_port), - m->vrf_id); + s = format (s, "%U local %U:%d external %U:%d vrf %d", + format_nat_protocol, m->proto, + format_ip4_address, &m->l_addr, + clib_net_to_host_u16 (m->l_port), + format_vnet_sw_if_index_name, vnm, m->sw_if_index, + clib_net_to_host_u16 (m->e_port), m->vrf_id); return s; } diff --git a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c index 73dacce57e6..0e330e17b36 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c @@ -25,12 +25,18 @@ #include <vnet/udp/udp_local.h> #include <vppinfra/error.h> +#include <nat/lib/nat_syslog.h> #include <nat/lib/nat_inlines.h> #include <nat/lib/ipfix_logging.h> #include <nat/nat44-ed/nat44_ed.h> #include <nat/nat44-ed/nat44_ed_inlines.h> +/* number of attempts to get a port for ED overloading algorithm, if rolling + * a dice this many times doesn't produce a free port, it's treated + * as if there were no free ports available to conserve resources */ +#define ED_PORT_ALLOC_ATTEMPTS (10) + static char *nat_in2out_ed_error_strings[] = { #define _(sym,string) string, foreach_nat_in2out_ed_error @@ -160,7 +166,7 @@ snat_not_translate_fast (snat_main_t *sm, vlib_node_runtime_t *node, static int nat_ed_alloc_addr_and_port_with_snat_address ( - snat_main_t *sm, u8 proto, u32 thread_index, snat_address_t *a, + snat_main_t *sm, u32 nat_proto, u32 thread_index, snat_address_t *a, u16 port_per_thread, u32 snat_thread_index, snat_session_t *s, ip4_address_t *outside_addr, u16 *outside_port) { @@ -181,13 +187,27 @@ nat_ed_alloc_addr_and_port_with_snat_address ( u16 attempts = ED_PORT_ALLOC_ATTEMPTS; do { - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { s->o2i.match.sport = clib_host_to_net_u16 (port); } s->o2i.match.dport = clib_host_to_net_u16 (port); if (0 == nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2)) { +#define _(N, i, n, s) \ + case NAT_PROTOCOL_##N: \ + ++a->busy_##n##_port_refcounts[port]; \ + a->busy_##n##_ports_per_thread[thread_index]++; \ + a->busy_##n##_ports++; \ + break; + switch (nat_proto) + { + foreach_nat_protocol; + default: + nat_elog_info (sm, "unknown protocol"); + return 1; + } +#undef _ *outside_addr = a->addr; *outside_port = clib_host_to_net_u16 (port); return 0; @@ -203,8 +223,9 @@ nat_ed_alloc_addr_and_port_with_snat_address ( static int nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, u32 thread_index, ip4_address_t s_addr, - u32 snat_thread_index, snat_session_t *s, - ip4_address_t *outside_addr, u16 *outside_port) + u16 port_per_thread, u32 snat_thread_index, + snat_session_t *s, ip4_address_t *outside_addr, + u16 *outside_port) { int i; snat_address_t *a, *ga = 0; @@ -219,7 +240,7 @@ nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, if (a->fib_index == rx_fib_index) { return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, + sm, nat_proto, thread_index, a, port_per_thread, snat_thread_index, s, outside_addr, outside_port); } else if (a->fib_index == ~0) @@ -234,7 +255,7 @@ nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, if (a->fib_index == rx_fib_index) { return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, + sm, nat_proto, thread_index, a, port_per_thread, snat_thread_index, s, outside_addr, outside_port); } else if (a->fib_index == ~0) @@ -246,8 +267,8 @@ nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, if (ga) { return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, - snat_thread_index, s, outside_addr, outside_port); + sm, nat_proto, thread_index, a, port_per_thread, snat_thread_index, + s, outside_addr, outside_port); } } /* Totally out of translations to use... */ @@ -283,18 +304,23 @@ nat_outside_fib_index_lookup (snat_main_t * sm, ip4_address_t addr) static_always_inline int nat44_ed_external_sm_lookup (snat_main_t *sm, ip4_address_t match_addr, - u16 match_port, ip_protocol_t match_protocol, - ip4_address_t *daddr, u16 *dport) + u16 match_port, nat_protocol_t match_protocol, + u32 match_fib_index, ip4_address_t *daddr, + u16 *dport) { - snat_static_mapping_t *m = - nat44_ed_sm_o2i_lookup (sm, match_addr, match_port, 0, match_protocol); - if (!m) + clib_bihash_kv_8_8_t kv, value; + init_nat_k (&kv, match_addr, match_port, match_fib_index, match_protocol); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) { /* Try address only mapping */ - m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0); - if (!m) + init_nat_k (&kv, match_addr, 0, 0, 0); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, + &value)) return 0; } + + snat_static_mapping_t *m = + pool_elt_at_index (sm->static_mappings, value.value); *daddr = m->local_addr; if (dport) { @@ -317,6 +343,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, u32 outside_fib_index; u8 is_identity_nat = 0; + u32 nat_proto = ip_proto_to_nat_proto (proto); snat_session_t *s = NULL; lb_nat_type_t lb = 0; ip4_address_t daddr = r_addr; @@ -355,9 +382,9 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, u32 sm_fib_index; /* First try to match static mapping by local address and port */ int is_sm; - if (snat_static_mapping_match (vm, sm, l_addr, l_port, rx_fib_index, proto, - &sm_addr, &sm_port, &sm_fib_index, 0, 0, 0, - &lb, 0, &is_identity_nat, 0)) + if (snat_static_mapping_match (vm, sm, l_addr, l_port, rx_fib_index, + nat_proto, &sm_addr, &sm_port, &sm_fib_index, + 0, 0, 0, &lb, 0, &is_identity_nat, 0)) { is_sm = 0; } @@ -371,7 +398,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, is_sm = 1; } - if (PREDICT_TRUE (proto == IP_PROTOCOL_TCP)) + if (PREDICT_TRUE (nat_proto == NAT_PROTOCOL_TCP)) { if (PREDICT_FALSE (!tcp_flags_is_init ( vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))) @@ -388,7 +415,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, { s->in2out.addr = l_addr; s->in2out.port = l_port; - s->proto = proto; + s->nat_proto = nat_proto; s->in2out.fib_index = rx_fib_index; s->out2in.fib_index = outside_fib_index; @@ -396,8 +423,8 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, outside_port = l_port; // hairpinning? - int is_hairpinning = nat44_ed_external_sm_lookup (sm, r_addr, r_port, - proto, &daddr, &dport); + int is_hairpinning = nat44_ed_external_sm_lookup ( + sm, r_addr, r_port, nat_proto, outside_fib_index, &daddr, &dport); s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING; // destination addr/port updated with real values in @@ -405,7 +432,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, nat_6t_o2i_flow_init (sm, thread_index, s, daddr, dport, daddr, 0, s->out2in.fib_index, proto); nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32); - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_flow_icmp_id_rewrite_set (&s->o2i, l_port); } @@ -415,9 +442,10 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, } nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); - if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, proto, thread_index, - l_addr, tsm->snat_thread_index, s, - &outside_addr, &outside_port)) + if (nat_ed_alloc_addr_and_port ( + sm, rx_fib_index, nat_proto, thread_index, l_addr, + sm->port_per_thread, tsm->snat_thread_index, s, &outside_addr, + &outside_port)) { nat_elog_notice (sm, "addresses exhausted"); b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS]; @@ -434,17 +462,17 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, s->out2in.port = outside_port = sm_port; s->in2out.addr = l_addr; s->in2out.port = l_port; - s->proto = proto; + s->nat_proto = nat_proto; s->in2out.fib_index = rx_fib_index; s->out2in.fib_index = outside_fib_index; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; // hairpinning? - int is_hairpinning = nat44_ed_external_sm_lookup (sm, r_addr, r_port, - proto, &daddr, &dport); + int is_hairpinning = nat44_ed_external_sm_lookup ( + sm, r_addr, r_port, nat_proto, outside_fib_index, &daddr, &dport); s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING; - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_o2i_flow_init (sm, thread_index, s, daddr, sm_port, sm_addr, sm_port, s->out2in.fib_index, proto); @@ -475,7 +503,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, nat_6t_flow_saddr_rewrite_set (&s->i2o, outside_addr.as_u32); nat_6t_flow_daddr_rewrite_set (&s->i2o, daddr.as_u32); - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_flow_icmp_id_rewrite_set (&s->i2o, outside_port); } @@ -493,14 +521,17 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, } /* log NAT event */ - nat_ipfix_logging_nat44_ses_create ( - thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto, - s->in2out.port, s->out2in.port, s->in2out.fib_index); + nat_ipfix_logging_nat44_ses_create (thread_index, + s->in2out.addr.as_u32, + s->out2in.addr.as_u32, + s->nat_proto, + s->in2out.port, + s->out2in.port, s->in2out.fib_index); nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, &s->ext_host_nat_addr, s->ext_host_nat_port, &s->out2in.addr, s->out2in.port, - &s->ext_host_addr, s->ext_host_port, s->proto, 0); + &s->ext_host_addr, s->ext_host_port, s->nat_proto, 0); per_vrf_sessions_register_session (s, thread_index); @@ -509,6 +540,12 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, error: if (s) { + if (!is_sm) + { + snat_free_outside_address_and_port (sm->addresses, thread_index, + &outside_addr, outside_port, + nat_proto); + } nat_ed_session_delete (sm, s, thread_index, 1); } *sessionp = s = NULL; @@ -523,10 +560,9 @@ nat44_ed_not_translate (vlib_main_t *vm, snat_main_t *sm, { clib_bihash_kv_16_8_t kv, value; - init_ed_k (&kv, ip->dst_address.as_u32, - vnet_buffer (b)->ip.reass.l4_dst_port, ip->src_address.as_u32, - vnet_buffer (b)->ip.reass.l4_src_port, sm->outside_fib_index, - ip->protocol); + init_ed_k (&kv, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, + ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port, + sm->outside_fib_index, ip->protocol); /* NAT packet aimed at external address if has active sessions */ if (clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) @@ -571,18 +607,18 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, &lookup_sport, &lookup_daddr, &lookup_dport, &lookup_protocol)) return 0; - init_ed_k (&kv, lookup_saddr.as_u32, lookup_sport, lookup_daddr.as_u32, - lookup_dport, 0, lookup_protocol); + init_ed_k (&kv, lookup_saddr, lookup_sport, lookup_daddr, lookup_dport, + 0, lookup_protocol); } else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP) { - init_ed_k (&kv, ip->src_address.as_u32, - vnet_buffer (b)->ip.reass.l4_src_port, ip->dst_address.as_u32, - vnet_buffer (b)->ip.reass.l4_dst_port, 0, ip->protocol); + init_ed_k (&kv, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port, + ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, 0, + ip->protocol); } else { - init_ed_k (&kv, ip->src_address.as_u32, 0, ip->dst_address.as_u32, 0, 0, + init_ed_k (&kv, ip->src_address, 0, ip->dst_address, 0, 0, ip->protocol); } @@ -629,8 +665,8 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, u32 tx_fib_index = ip4_fib_table_get_index_for_sw_if_index (tx_sw_if_index); /* src NAT check */ - init_ed_k (&kv, ip->src_address.as_u32, src_port, ip->dst_address.as_u32, - dst_port, tx_fib_index, ip->protocol); + init_ed_k (&kv, ip->src_address, src_port, ip->dst_address, dst_port, + tx_fib_index, ip->protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) { ASSERT (thread_index == ed_value_get_thread_index (&value)); @@ -640,7 +676,7 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, if (nat44_is_ses_closed (s) && (!s->tcp_closed_timestamp || now >= s->tcp_closed_timestamp)) { - nat44_ed_free_session_data (sm, s, thread_index, 0); + nat_free_session_data (sm, s, thread_index, 0); nat_ed_session_delete (sm, s, thread_index, 1); } return 1; @@ -667,8 +703,8 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, s = NULL; } - init_ed_k (&kv, ip->dst_address.as_u32, dst_port, ip->src_address.as_u32, - src_port, rx_fib_index, ip->protocol); + init_ed_k (&kv, ip->dst_address, dst_port, ip->src_address, src_port, + rx_fib_index, ip->protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) { ASSERT (thread_index == ed_value_get_thread_index (&value)); @@ -728,8 +764,9 @@ icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, } else { - if (PREDICT_FALSE (nat44_ed_not_translate ( - vm, sm, node, sw_if_index, b, ip, IP_PROTOCOL_ICMP, rx_fib_index))) + if (PREDICT_FALSE (nat44_ed_not_translate (vm, sm, node, sw_if_index, b, + ip, NAT_PROTOCOL_ICMP, + rx_fib_index))) { return next; } @@ -782,6 +819,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, vlib_main_t *vm, vlib_node_runtime_t *node) { + clib_bihash_kv_8_8_t kv, value; clib_bihash_kv_16_8_t s_kv, s_value; snat_static_mapping_t *m = NULL; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; @@ -814,11 +852,12 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, break; } + init_nat_k (&kv, ip->src_address, 0, rx_fib_index, 0); + /* Try to find static mapping first */ - m = nat44_ed_sm_i2o_lookup (sm, ip->src_address, 0, rx_fib_index, - ip->protocol); - if (m) + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value)) { + m = pool_elt_at_index (sm->static_mappings, value.value); new_src_addr = m->external_addr; } else @@ -827,9 +866,8 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, { if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) { - init_ed_k (&s_kv, s->out2in.addr.as_u32, 0, - ip->dst_address.as_u32, 0, outside_fib_index, - ip->protocol); + init_ed_k (&s_kv, s->out2in.addr, 0, ip->dst_address, 0, + outside_fib_index, ip->protocol); if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value)) { new_src_addr = s->out2in.addr; @@ -842,9 +880,8 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, { for (i = 0; i < vec_len (sm->addresses); i++) { - init_ed_k (&s_kv, sm->addresses[i].addr.as_u32, 0, - ip->dst_address.as_u32, 0, outside_fib_index, - ip->protocol); + init_ed_k (&s_kv, sm->addresses[i].addr, 0, ip->dst_address, 0, + outside_fib_index, ip->protocol); if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value)) { new_src_addr = sm->addresses[i].addr; @@ -873,8 +910,9 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, nat_6t_flow_txfib_rewrite_set (&s->i2o, outside_fib_index); // hairpinning? - int is_hairpinning = nat44_ed_external_sm_lookup ( - sm, ip->dst_address, 0, ip->protocol, &new_dst_addr, NULL); + int is_hairpinning = + nat44_ed_external_sm_lookup (sm, ip->dst_address, 0, NAT_PROTOCOL_OTHER, + outside_fib_index, &new_dst_addr, NULL); s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING; nat_6t_flow_daddr_rewrite_set (&s->i2o, new_dst_addr.as_u32); @@ -887,6 +925,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); s->ext_host_addr.as_u32 = ip->dst_address.as_u32; + s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; s->out2in.addr.as_u32 = new_src_addr.as_u32; s->out2in.fib_index = outside_fib_index; s->in2out.addr.as_u32 = ip->src_address.as_u32; @@ -948,7 +987,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, u32 rx_sw_if_index0, rx_fib_index0, iph_offset0 = 0; u32 tx_sw_if_index0; u32 cntr_sw_if_index0; - ip_protocol_t proto0; + nat_protocol_t proto0; ip4_header_t *ip0; snat_session_t *s0 = 0; clib_bihash_kv_16_8_t kv0, value0; @@ -1000,7 +1039,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, goto trace0; } - proto0 = ip0->protocol; + proto0 = ip_proto_to_nat_proto (ip0->protocol); if (is_output_feature) { @@ -1010,7 +1049,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, goto trace0; } - if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP)) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP)) { if (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request && @@ -1064,8 +1103,8 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, s0 = NULL; } - init_ed_k (&kv0, lookup.saddr.as_u32, lookup.sport, lookup.daddr.as_u32, - lookup.dport, lookup.fib_index, lookup.proto); + init_ed_k (&kv0, lookup.saddr, lookup.sport, lookup.daddr, lookup.dport, + lookup.fib_index, lookup.proto); // lookup flow if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0)) @@ -1087,7 +1126,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index))) { // session is closed, go slow path - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; goto trace0; @@ -1115,7 +1154,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, s0->last_heard + (f64) nat44_session_get_timeout (sm, s0); if (now >= sess_timeout_time) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); // session is closed, go slow path next[0] = def_slow; @@ -1136,7 +1175,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, else { translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH; - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; @@ -1147,7 +1186,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, (translation_error = nat_6t_flow_buf_translate_i2o ( vm, sm, b0, ip0, f, proto0, is_output_feature))) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; @@ -1156,20 +1195,20 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, switch (proto0) { - case IP_PROTOCOL_TCP: + case NAT_PROTOCOL_TCP: vlib_increment_simple_counter (&sm->counters.fastpath.in2out.tcp, thread_index, cntr_sw_if_index0, 1); nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index); break; - case IP_PROTOCOL_UDP: + case NAT_PROTOCOL_UDP: vlib_increment_simple_counter (&sm->counters.fastpath.in2out.udp, thread_index, cntr_sw_if_index0, 1); break; - case IP_PROTOCOL_ICMP: + case NAT_PROTOCOL_ICMP: vlib_increment_simple_counter (&sm->counters.fastpath.in2out.icmp, thread_index, cntr_sw_if_index0, 1); break; - default: + case NAT_PROTOCOL_OTHER: vlib_increment_simple_counter (&sm->counters.fastpath.in2out.other, thread_index, cntr_sw_if_index0, 1); break; @@ -1250,7 +1289,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, u32 rx_sw_if_index0, rx_fib_index0, iph_offset0 = 0; u32 tx_sw_if_index0; u32 cntr_sw_if_index0; - ip_protocol_t proto0; + nat_protocol_t proto0; ip4_header_t *ip0; udp_header_t *udp0; icmp46_header_t *icmp0; @@ -1287,9 +1326,9 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, udp0 = ip4_next_header (ip0); icmp0 = (icmp46_header_t *) udp0; - proto0 = ip0->protocol; + proto0 = ip_proto_to_nat_proto (ip0->protocol); - if (PREDICT_FALSE (nat44_ed_is_unk_proto (proto0))) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER)) { s0 = nat44_ed_in2out_slowpath_unknown_proto ( sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node); @@ -1301,7 +1340,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, (translation_error = nat_6t_flow_buf_translate_i2o ( vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature))) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; @@ -1313,7 +1352,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, goto trace0; } - if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP)) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP)) { next[0] = icmp_in2out_ed_slow_path ( sm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node, next[0], @@ -1323,7 +1362,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, (translation_error = nat_6t_flow_buf_translate_i2o ( vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature))) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; @@ -1335,10 +1374,10 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, goto trace0; } - init_ed_k ( - &kv0, ip0->src_address.as_u32, vnet_buffer (b0)->ip.reass.l4_src_port, - ip0->dst_address.as_u32, vnet_buffer (b0)->ip.reass.l4_dst_port, - rx_fib_index0, ip0->protocol); + init_ed_k (&kv0, ip0->src_address, + vnet_buffer (b0)->ip.reass.l4_src_port, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, + ip0->protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0)) { ASSERT (thread_index == ed_value_get_thread_index (&value0)); @@ -1348,7 +1387,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); s0 = NULL; } @@ -1368,11 +1407,11 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, * Send DHCP packets to the ipv4 stack, or we won't * be able to use dhcp client on the outside interface */ - if (PREDICT_FALSE ( - proto0 == IP_PROTOCOL_UDP && - (vnet_buffer (b0)->ip.reass.l4_dst_port == - clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server)) && - ip0->dst_address.as_u32 == 0xffffffff)) + if (PREDICT_FALSE + (proto0 == NAT_PROTOCOL_UDP + && (vnet_buffer (b0)->ip.reass.l4_dst_port == + clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server)) + && ip0->dst_address.as_u32 == 0xffffffff)) goto trace0; } else @@ -1403,14 +1442,14 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, (translation_error = nat_6t_flow_buf_translate_i2o ( vm, sm, b0, ip0, &s0->i2o, proto0, is_output_feature))) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; goto trace0; } - if (PREDICT_TRUE (proto0 == IP_PROTOCOL_TCP)) + if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) { vlib_increment_simple_counter (&sm->counters.slowpath.in2out.tcp, thread_index, cntr_sw_if_index0, 1); diff --git a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h index cb418960249..0d75e736849 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h +++ b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h @@ -26,50 +26,114 @@ #include <nat/lib/log.h> #include <nat/nat44-ed/nat44_ed.h> +always_inline u64 +calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto) +{ + ASSERT (fib_index <= (1 << 14) - 1); + ASSERT (proto <= (1 << 3) - 1); + return (u64) addr.as_u32 << 32 | (u64) port << 16 | fib_index << 3 | + (proto & 0x7); +} + always_inline void -init_ed_k (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr, - u16 r_port, u32 fib_index, ip_protocol_t proto) +split_nat_key (u64 key, ip4_address_t *addr, u16 *port, u32 *fib_index, + nat_protocol_t *proto) { - kv->key[0] = (u64) r_addr << 32 | l_addr; - kv->key[1] = - (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto; + if (addr) + { + addr->as_u32 = key >> 32; + } + if (port) + { + *port = (key >> 16) & (u16) ~0; + } + if (fib_index) + { + *fib_index = key >> 3 & ((1 << 13) - 1); + } + if (proto) + { + *proto = key & 0x7; + } } always_inline void -init_ed_kv (clib_bihash_kv_16_8_t *kv, u32 l_addr, u16 l_port, u32 r_addr, - u16 r_port, u32 fib_index, u8 proto, u32 thread_index, - u32 session_index) +init_nat_k (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port, + u32 fib_index, nat_protocol_t proto) { - init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto); + kv->key = calc_nat_key (addr, port, fib_index, proto); + kv->value = ~0ULL; +} + +always_inline void +init_nat_kv (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port, + u32 fib_index, nat_protocol_t proto, u32 thread_index, + u32 session_index) +{ + init_nat_k (kv, addr, port, fib_index, proto); + kv->value = (u64) thread_index << 32 | session_index; +} + +always_inline void +init_nat_i2o_k (clib_bihash_kv_8_8_t *kv, snat_session_t *s) +{ + return init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index, + s->nat_proto); +} + +always_inline void +init_nat_i2o_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index, + u32 session_index) +{ + init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index, + s->nat_proto); kv->value = (u64) thread_index << 32 | session_index; } always_inline void -nat44_ed_sm_init_i2o_kv (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port, - u32 fib_index, u8 proto, u32 sm_index) +init_nat_o2i_k (clib_bihash_kv_8_8_t *kv, snat_session_t *s) { - return init_ed_kv (kv, addr, port, 0, 0, fib_index, proto, 0, sm_index); + return init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index, + s->nat_proto); } always_inline void -nat44_ed_sm_init_o2i_kv (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port, - u32 fib_index, u8 proto, u32 sm_index) +init_nat_o2i_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index, + u32 session_index) +{ + init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index, + s->nat_proto); + kv->value = (u64) thread_index << 32 | session_index; +} + +always_inline u32 +nat_value_get_thread_index (clib_bihash_kv_8_8_t *value) +{ + return value->value >> 32; +} + +always_inline u32 +nat_value_get_session_index (clib_bihash_kv_8_8_t *value) { - return init_ed_kv (kv, 0, 0, e_addr, e_port, fib_index, proto, 0, sm_index); + return value->value & ~(u32) 0; } always_inline void -nat44_ed_sm_init_i2o_k (clib_bihash_kv_16_8_t *kv, u32 addr, u16 port, - u32 fib_index, u8 proto) +init_ed_k (clib_bihash_kv_16_8_t *kv, ip4_address_t l_addr, u16 l_port, + ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto) { - return nat44_ed_sm_init_i2o_kv (kv, addr, port, fib_index, proto, 0); + kv->key[0] = (u64) r_addr.as_u32 << 32 | l_addr.as_u32; + kv->key[1] = + (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto; } always_inline void -nat44_ed_sm_init_o2i_k (clib_bihash_kv_16_8_t *kv, u32 e_addr, u16 e_port, - u32 fib_index, u8 proto) +init_ed_kv (clib_bihash_kv_16_8_t *kv, ip4_address_t l_addr, u16 l_port, + ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto, + u32 thread_index, u32 session_index) { - return nat44_ed_sm_init_o2i_kv (kv, e_addr, e_port, fib_index, proto, 0); + init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto); + kv->value = (u64) thread_index << 32 | session_index; } always_inline u32 @@ -151,16 +215,16 @@ nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0, *lookup_protocol = inner_ip0->protocol; lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32; lookup_daddr->as_u32 = inner_ip0->src_address.as_u32; - switch (inner_ip0->protocol) + switch (ip_proto_to_nat_proto (inner_ip0->protocol)) { - case IP_PROTOCOL_ICMP: + case NAT_PROTOCOL_ICMP: inner_icmp0 = (icmp46_header_t *) l4_header; inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1); *lookup_sport = inner_echo0->identifier; *lookup_dport = inner_echo0->identifier; break; - case IP_PROTOCOL_UDP: - case IP_PROTOCOL_TCP: + case NAT_PROTOCOL_UDP: + case NAT_PROTOCOL_TCP: *lookup_sport = ((tcp_udp_header_t *) l4_header)->dst_port; *lookup_dport = ((tcp_udp_header_t *) l4_header)->src_port; break; @@ -174,15 +238,13 @@ nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0, always_inline u32 nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s) { - switch (s->proto) + switch (s->nat_proto) { - case IP_PROTOCOL_ICMP: - /* fallthrough */ - case IP_PROTOCOL_ICMP6: + case NAT_PROTOCOL_ICMP: return sm->timeouts.icmp; - case IP_PROTOCOL_UDP: + case NAT_PROTOCOL_UDP: return sm->timeouts.udp; - case IP_PROTOCOL_TCP: + case NAT_PROTOCOL_TCP: { if (s->state) return sm->timeouts.tcp.transitory; @@ -238,7 +300,7 @@ nat_ed_lru_insert (snat_main_per_thread_data_t *tsm, snat_session_t *s, static_always_inline void nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f) { - init_ed_k (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32, + init_ed_k (kv, f->match.saddr, f->match.sport, f->match.daddr, f->match.dport, f->match.fib_index, f->match.proto); } @@ -246,7 +308,7 @@ static_always_inline void nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f, u32 thread_idx, u32 session_idx) { - init_ed_kv (kv, f->match.saddr.as_u32, f->match.sport, f->match.daddr.as_u32, + init_ed_kv (kv, f->match.saddr, f->match.sport, f->match.daddr, f->match.dport, f->match.fib_index, f->match.proto, thread_idx, session_idx); } @@ -286,15 +348,6 @@ nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx, else { nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions); - if (!(s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING)) - { - if (nat44_ed_sm_o2i_lookup (sm, s->o2i.match.daddr, - s->o2i.match.dport, 0, - s->o2i.match.proto)) - { - return -1; - } - } nat_6t_l3_l4_csum_calc (&s->o2i); } ASSERT (thread_idx == s->thread_index); @@ -343,7 +396,7 @@ nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now, if (now >= sess_timeout_time || (s->tcp_closed_timestamp && now >= s->tcp_closed_timestamp)) { - nat44_ed_free_session_data (sm, s, thread_index, 0); + nat_free_session_data (sm, s, thread_index, 0); nat_ed_session_delete (sm, s, thread_index, 0); return 1; } @@ -815,19 +868,6 @@ nat44_session_update_lru (snat_main_t *sm, snat_session_t *s, u32 thread_index) } } -static_always_inline int -nat44_ed_is_unk_proto (u8 proto) -{ - static const int lookup_table[256] = { - [IP_PROTOCOL_TCP] = 1, - [IP_PROTOCOL_UDP] = 1, - [IP_PROTOCOL_ICMP] = 1, - [IP_PROTOCOL_ICMP6] = 1, - }; - - return 1 - lookup_table[proto]; -} - #endif /* __included_nat44_ed_inlines_h__ */ /* diff --git a/src/plugins/nat/nat44-ed/nat44_ed_out2in.c b/src/plugins/nat/nat44-ed/nat44_ed_out2in.c index 5ad57a17098..cb21b0f62c5 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_out2in.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_out2in.c @@ -25,6 +25,7 @@ #include <vnet/udp/udp_local.h> #include <vppinfra/error.h> +#include <nat/lib/nat_syslog.h> #include <nat/lib/ipfix_logging.h> #include <nat/nat44-ed/nat44_ed.h> @@ -126,8 +127,8 @@ next_src_nat (snat_main_t *sm, ip4_header_t *ip, u16 src_port, u16 dst_port, { clib_bihash_kv_16_8_t kv, value; - init_ed_k (&kv, ip->src_address.as_u32, src_port, ip->dst_address.as_u32, - dst_port, rx_fib_index, ip->protocol); + init_ed_k (&kv, ip->src_address, src_port, ip->dst_address, dst_port, + rx_fib_index, ip->protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) return 1; @@ -141,8 +142,8 @@ static void create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, static snat_session_t *create_session_for_static_mapping_ed ( snat_main_t *sm, vlib_buffer_t *b, ip4_address_t i2o_addr, u16 i2o_port, u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index, - ip_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, - twice_nat_type_t twice_nat, lb_nat_type_t lb_nat, f64 now, + nat_protocol_t nat_proto, vlib_node_runtime_t *node, u32 rx_fib_index, + u32 thread_index, twice_nat_type_t twice_nat, lb_nat_type_t lb_nat, f64 now, snat_static_mapping_t *mapping); static inline u32 @@ -179,10 +180,10 @@ icmp_out2in_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, goto out; } - if (snat_static_mapping_match (vm, sm, ip->dst_address, lookup_sport, - rx_fib_index, ip->protocol, &sm_addr, - &sm_port, &sm_fib_index, 1, &is_addr_only, 0, - 0, 0, &identity_nat, &m)) + if (snat_static_mapping_match ( + vm, sm, ip->dst_address, lookup_sport, rx_fib_index, + ip_proto_to_nat_proto (ip->protocol), &sm_addr, &sm_port, + &sm_fib_index, 1, &is_addr_only, 0, 0, 0, &identity_nat, &m)) { // static mapping not matched if (!sm->forwarding_enabled) @@ -228,8 +229,8 @@ icmp_out2in_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, /* Create session initiated by host from external network */ s = create_session_for_static_mapping_ed ( sm, b, sm_addr, sm_port, sm_fib_index, ip->dst_address, lookup_sport, - rx_fib_index, lookup_protocol, node, thread_index, 0, 0, - vlib_time_now (vm), m); + rx_fib_index, ip_proto_to_nat_proto (lookup_protocol), node, rx_fib_index, + thread_index, 0, 0, vlib_time_now (vm), m); if (!s) next = NAT_NEXT_DROP; @@ -264,29 +265,44 @@ out: return next; } +// allocate exact address based on preference static_always_inline int -nat44_ed_alloc_i2o_port (snat_main_t *sm, snat_address_t *a, snat_session_t *s, - ip4_address_t i2o_addr, u16 i2o_port, - u32 i2o_fib_index, ip_protocol_t proto, - u32 thread_index, u32 snat_thread_index, - ip4_address_t *outside_addr, u16 *outside_port) +nat_alloc_addr_and_port_exact (snat_address_t * a, + u32 thread_index, + nat_protocol_t proto, + ip4_address_t * addr, + u16 * port, + u16 port_per_thread, u32 snat_thread_index) { + snat_main_t *sm = &snat_main; u32 portnum; - for (int i = 0; i < ED_PORT_ALLOC_ATTEMPTS; ++i) + switch (proto) { - portnum = (sm->port_per_thread * snat_thread_index) + - snat_random_port (0, sm->port_per_thread - 1) + 1024; - portnum = clib_host_to_net_u16 (portnum); - nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port, a->addr, - portnum, i2o_fib_index, proto); - if (!nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, - 1 /* is_add */)) - { - *outside_addr = a->addr; - *outside_port = portnum; - return 0; - } +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \ + { \ + while (1) \ + { \ + portnum = (port_per_thread * \ + snat_thread_index) + \ + snat_random_port(0, port_per_thread - 1) + 1024; \ + if (a->busy_##n##_port_refcounts[portnum]) \ + continue; \ + --a->busy_##n##_port_refcounts[portnum]; \ + a->busy_##n##_ports_per_thread[thread_index]++; \ + a->busy_##n##_ports++; \ + *addr = a->addr; \ + *port = clib_host_to_net_u16(portnum); \ + return 0; \ + } \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + return 1; } /* Totally out of translations to use... */ @@ -295,56 +311,80 @@ nat44_ed_alloc_i2o_port (snat_main_t *sm, snat_address_t *a, snat_session_t *s, } static_always_inline int -nat44_ed_alloc_i2o_addr_and_port (snat_main_t *sm, snat_address_t *addresses, - snat_session_t *s, ip4_address_t i2o_addr, - u16 i2o_port, u32 i2o_fib_index, - ip_protocol_t proto, u32 thread_index, - u32 snat_thread_index, - ip4_address_t *outside_addr, - u16 *outside_port) +nat44_ed_alloc_outside_addr_and_port (snat_address_t *addresses, u32 fib_index, + u32 thread_index, nat_protocol_t proto, + ip4_address_t *addr, u16 *port, + u16 port_per_thread, + u32 snat_thread_index) { + snat_main_t *sm = &snat_main; snat_address_t *a, *ga = 0; + u32 portnum; int i; - if (vec_len (addresses) > 0) + for (i = 0; i < vec_len (addresses); i++) { - int s_addr_offset = i2o_addr.as_u32 % vec_len (addresses); - - for (i = s_addr_offset; i < vec_len (addresses); ++i) + a = addresses + i; + switch (proto) { - a = addresses + i; - if (a->fib_index == i2o_fib_index) - { - return nat44_ed_alloc_i2o_port ( - sm, a, s, i2o_addr, i2o_port, i2o_fib_index, proto, - thread_index, snat_thread_index, outside_addr, outside_port); - } - else if (a->fib_index == ~0) - { - ga = a; - } - } - - for (i = 0; i < s_addr_offset; ++i) - { - a = addresses + i; - if (a->fib_index == i2o_fib_index) - { - return nat44_ed_alloc_i2o_port ( - sm, a, s, i2o_addr, i2o_port, i2o_fib_index, proto, - thread_index, snat_thread_index, outside_addr, outside_port); - } - else if (a->fib_index == ~0) - { - ga = a; - } +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \ + { \ + if (a->fib_index == fib_index) \ + { \ + while (1) \ + { \ + portnum = (port_per_thread * snat_thread_index) + \ + snat_random_port (0, port_per_thread - 1) + 1024; \ + if (a->busy_##n##_port_refcounts[portnum]) \ + continue; \ + --a->busy_##n##_port_refcounts[portnum]; \ + a->busy_##n##_ports_per_thread[thread_index]++; \ + a->busy_##n##_ports++; \ + *addr = a->addr; \ + *port = clib_host_to_net_u16 (portnum); \ + return 0; \ + } \ + } \ + else if (a->fib_index == ~0) \ + { \ + ga = a; \ + } \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + return 1; } + } - if (ga) + if (ga) + { + a = ga; + switch (proto) { - return nat44_ed_alloc_i2o_port ( - sm, a, s, i2o_addr, i2o_port, i2o_fib_index, proto, thread_index, - snat_thread_index, outside_addr, outside_port); +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + while (1) \ + { \ + portnum = (port_per_thread * snat_thread_index) + \ + snat_random_port (0, port_per_thread - 1) + 1024; \ + if (a->busy_##n##_port_refcounts[portnum]) \ + continue; \ + ++a->busy_##n##_port_refcounts[portnum]; \ + a->busy_##n##_ports_per_thread[thread_index]++; \ + a->busy_##n##_ports++; \ + *addr = a->addr; \ + *port = clib_host_to_net_u16 (portnum); \ + return 0; \ + } + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info (sm, "unknown protocol"); + return 1; } } @@ -357,23 +397,23 @@ static snat_session_t * create_session_for_static_mapping_ed ( snat_main_t *sm, vlib_buffer_t *b, ip4_address_t i2o_addr, u16 i2o_port, u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index, - ip_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, - twice_nat_type_t twice_nat, lb_nat_type_t lb_nat, f64 now, + nat_protocol_t nat_proto, vlib_node_runtime_t *node, u32 rx_fib_index, + u32 thread_index, twice_nat_type_t twice_nat, lb_nat_type_t lb_nat, f64 now, snat_static_mapping_t *mapping) { snat_session_t *s; ip4_header_t *ip; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - if (PREDICT_FALSE ( - nat44_ed_maximum_sessions_exceeded (sm, o2i_fib_index, thread_index))) + if (PREDICT_FALSE + (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index))) { b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED]; nat_elog_notice (sm, "maximum sessions exceeded"); return 0; } - s = nat_ed_session_alloc (sm, thread_index, now, proto); + s = nat_ed_session_alloc (sm, thread_index, now, nat_proto); if (!s) { b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED]; @@ -385,7 +425,7 @@ create_session_for_static_mapping_ed ( s->ext_host_addr.as_u32 = ip->src_address.as_u32; s->ext_host_port = - proto == IP_PROTOCOL_ICMP ? 0 : vnet_buffer (b)->ip.reass.l4_src_port; + nat_proto == NAT_PROTOCOL_ICMP ? 0 : vnet_buffer (b)->ip.reass.l4_src_port; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; if (lb_nat) s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; @@ -397,9 +437,9 @@ create_session_for_static_mapping_ed ( s->in2out.addr = i2o_addr; s->in2out.port = i2o_port; s->in2out.fib_index = i2o_fib_index; - s->proto = proto; + s->nat_proto = nat_proto; - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_o2i_flow_init (sm, thread_index, s, s->ext_host_addr, o2i_port, o2i_addr, o2i_port, o2i_fib_index, ip->protocol); @@ -445,23 +485,33 @@ create_session_for_static_mapping_ed ( if (filter) { - rc = nat44_ed_alloc_i2o_port ( - sm, filter, s, i2o_addr, i2o_port, i2o_fib_index, proto, - thread_index, tsm->snat_thread_index, &s->ext_host_nat_addr, - &s->ext_host_nat_port); + rc = nat_alloc_addr_and_port_exact (filter, + thread_index, + nat_proto, + &s->ext_host_nat_addr, + &s->ext_host_nat_port, + sm->port_per_thread, + tsm->snat_thread_index); s->flags |= SNAT_SESSION_FLAG_EXACT_ADDRESS; } else { - rc = nat44_ed_alloc_i2o_addr_and_port ( - sm, sm->twice_nat_addresses, s, i2o_addr, i2o_port, i2o_fib_index, - proto, thread_index, tsm->snat_thread_index, &s->ext_host_nat_addr, - &s->ext_host_nat_port); + rc = nat44_ed_alloc_outside_addr_and_port ( + sm->twice_nat_addresses, 0, thread_index, nat_proto, + &s->ext_host_nat_addr, &s->ext_host_nat_port, sm->port_per_thread, + tsm->snat_thread_index); } if (rc) { b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS]; + if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0)) + { + nat_elog_warn (sm, "out2in flow hash del failed"); + } + snat_free_outside_address_and_port ( + sm->twice_nat_addresses, thread_index, &s->ext_host_nat_addr, + s->ext_host_nat_port, s->nat_proto); nat_ed_session_delete (sm, s, thread_index, 1); return 0; } @@ -469,7 +519,7 @@ create_session_for_static_mapping_ed ( s->flags |= SNAT_SESSION_FLAG_TWICE_NAT; nat_6t_flow_saddr_rewrite_set (&s->o2i, s->ext_host_nat_addr.as_u32); - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_flow_icmp_id_rewrite_set (&s->o2i, s->ext_host_nat_port); } @@ -480,8 +530,11 @@ create_session_for_static_mapping_ed ( nat_6t_l3_l4_csum_calc (&s->o2i); + nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port, + s->ext_host_nat_addr, s->ext_host_nat_port, + i2o_fib_index, ip->protocol); nat_6t_flow_daddr_rewrite_set (&s->i2o, s->ext_host_addr.as_u32); - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_flow_icmp_id_rewrite_set (&s->i2o, s->ext_host_port); } @@ -489,21 +542,10 @@ create_session_for_static_mapping_ed ( { nat_6t_flow_dport_rewrite_set (&s->i2o, s->ext_host_port); } - - nat_6t_flow_saddr_rewrite_set (&s->i2o, o2i_addr.as_u32); - if (IP_PROTOCOL_ICMP == proto) - { - nat_6t_flow_icmp_id_rewrite_set (&s->i2o, o2i_port); - } - else - { - nat_6t_flow_sport_rewrite_set (&s->i2o, o2i_port); - } - nat_6t_l3_l4_csum_calc (&s->i2o); } else { - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port, s->ext_host_addr, i2o_port, i2o_fib_index, @@ -515,9 +557,10 @@ create_session_for_static_mapping_ed ( s->ext_host_addr, s->ext_host_port, i2o_fib_index, ip->protocol); } + } nat_6t_flow_saddr_rewrite_set (&s->i2o, o2i_addr.as_u32); - if (IP_PROTOCOL_ICMP == proto) + if (NAT_PROTOCOL_ICMP == nat_proto) { nat_6t_flow_icmp_id_rewrite_set (&s->i2o, o2i_port); } @@ -536,15 +579,18 @@ create_session_for_static_mapping_ed ( nat_ed_session_delete (sm, s, thread_index, 1); return 0; } - } - nat_ipfix_logging_nat44_ses_create ( - thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto, - s->in2out.port, s->out2in.port, s->in2out.fib_index); + + nat_ipfix_logging_nat44_ses_create (thread_index, + s->in2out.addr.as_u32, + s->out2in.addr.as_u32, + s->nat_proto, + s->in2out.port, + s->out2in.port, s->in2out.fib_index); nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, &s->ext_host_nat_addr, s->ext_host_nat_port, &s->out2in.addr, s->out2in.port, - &s->ext_host_addr, s->ext_host_port, s->proto, + &s->ext_host_addr, s->ext_host_port, s->nat_proto, nat44_ed_is_twice_nat_session (s)); per_vrf_sessions_register_session (s, thread_index); @@ -588,8 +634,8 @@ create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s, lookup_protocol = ip->protocol; } - init_ed_k (&kv, lookup_saddr.as_u32, lookup_sport, lookup_daddr.as_u32, - lookup_dport, rx_fib_index, lookup_protocol); + init_ed_k (&kv, lookup_saddr, lookup_sport, lookup_daddr, lookup_dport, + rx_fib_index, lookup_protocol); if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) { @@ -606,6 +652,8 @@ create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s, } else { + u32 proto; + if (PREDICT_FALSE (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index))) @@ -618,12 +666,19 @@ create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s, return; } + proto = ip_proto_to_nat_proto (ip->protocol); + s->ext_host_addr = ip->src_address; s->ext_host_port = lookup_dport; s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS; s->out2in.addr = ip->dst_address; s->out2in.port = lookup_sport; - s->proto = ip->protocol; + s->nat_proto = proto; + if (proto == NAT_PROTOCOL_OTHER) + { + s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; + s->out2in.port = ip->protocol; + } s->out2in.fib_index = rx_fib_index; s->in2out.addr = s->out2in.addr; s->in2out.port = s->out2in.port; @@ -664,6 +719,7 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, vlib_main_t *vm, vlib_node_runtime_t *node) { + clib_bihash_kv_8_8_t kv, value; snat_static_mapping_t *m; snat_session_t *s; @@ -675,13 +731,15 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, return 0; } - m = nat44_ed_sm_o2i_lookup (sm, ip->dst_address, 0, 0, ip->protocol); - if (!m) + init_nat_k (&kv, ip->dst_address, 0, 0, 0); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) { b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION]; return 0; } + m = pool_elt_at_index (sm->static_mappings, value.value); + /* Create a new session */ s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol); if (!s) @@ -692,6 +750,7 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, } s->ext_host_addr.as_u32 = ip->src_address.as_u32; + s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; s->out2in.addr.as_u32 = ip->dst_address.as_u32; s->out2in.fib_index = rx_fib_index; @@ -754,7 +813,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, { vlib_buffer_t *b0; u32 sw_if_index0, rx_fib_index0; - ip_protocol_t proto0; + nat_protocol_t proto0; ip4_header_t *ip0; snat_session_t *s0 = 0; clib_bihash_kv_16_8_t kv0, value0; @@ -803,9 +862,9 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - proto0 = ip0->protocol; + proto0 = ip_proto_to_nat_proto (ip0->protocol); - if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP)) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP)) { if (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request && @@ -854,8 +913,8 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, s0 = NULL; } - init_ed_k (&kv0, lookup.saddr.as_u32, lookup.sport, lookup.daddr.as_u32, - lookup.dport, lookup.fib_index, lookup.proto); + init_ed_k (&kv0, lookup.saddr, lookup.sport, lookup.daddr, lookup.dport, + lookup.fib_index, lookup.proto); // lookup flow if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0)) @@ -876,7 +935,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index))) { // session is closed, go slow path - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); slow_path_reason = NAT_ED_SP_REASON_VRF_EXPIRED; next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; @@ -907,7 +966,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, if (now >= sess_timeout_time) { // session is closed, go slow path - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); slow_path_reason = NAT_ED_SP_SESS_EXPIRED; next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; @@ -930,7 +989,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, * be able to use dhcp client on the outside interface */ if (PREDICT_FALSE ( - proto0 == IP_PROTOCOL_UDP && + proto0 == NAT_PROTOCOL_UDP && (vnet_buffer (b0)->ip.reass.l4_dst_port == clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client)))) { @@ -955,7 +1014,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, // create_bypass_for_fwd (sm, b0, s0, ip0, rx_fib_index0, // thread_index); translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH; - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED]; @@ -975,7 +1034,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, switch (proto0) { - case IP_PROTOCOL_TCP: + case NAT_PROTOCOL_TCP: vlib_increment_simple_counter (&sm->counters.fastpath.out2in.tcp, thread_index, sw_if_index0, 1); nat44_set_tcp_session_state_o2i (sm, now, s0, @@ -987,15 +1046,15 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, reass.tcp_seq_number, thread_index); break; - case IP_PROTOCOL_UDP: + case NAT_PROTOCOL_UDP: vlib_increment_simple_counter (&sm->counters.fastpath.out2in.udp, thread_index, sw_if_index0, 1); break; - case IP_PROTOCOL_ICMP: + case NAT_PROTOCOL_ICMP: vlib_increment_simple_counter (&sm->counters.fastpath.out2in.icmp, thread_index, sw_if_index0, 1); break; - default: + case NAT_PROTOCOL_OTHER: vlib_increment_simple_counter (&sm->counters.fastpath.out2in.other, thread_index, sw_if_index0, 1); break; @@ -1073,7 +1132,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, { vlib_buffer_t *b0; u32 sw_if_index0, rx_fib_index0; - ip_protocol_t proto0; + nat_protocol_t proto0; ip4_header_t *ip0; udp_header_t *udp0; icmp46_header_t *icmp0; @@ -1109,9 +1168,9 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, udp0 = ip4_next_header (ip0); icmp0 = (icmp46_header_t *) udp0; - proto0 = ip0->protocol; + proto0 = ip_proto_to_nat_proto (ip0->protocol); - if (PREDICT_FALSE (nat44_ed_is_unk_proto (proto0))) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER)) { s0 = nat44_ed_out2in_slowpath_unknown_proto ( sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node); @@ -1136,7 +1195,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP)) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP)) { next[0] = icmp_out2in_ed_slow_path (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, @@ -1158,10 +1217,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - init_ed_k ( - &kv0, ip0->src_address.as_u32, vnet_buffer (b0)->ip.reass.l4_src_port, - ip0->dst_address.as_u32, vnet_buffer (b0)->ip.reass.l4_dst_port, - rx_fib_index0, ip0->protocol); + init_ed_k (&kv0, ip0->src_address, + vnet_buffer (b0)->ip.reass.l4_src_port, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, + ip0->protocol); s0 = NULL; if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0)) @@ -1173,7 +1232,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp) { - nat44_ed_free_session_data (sm, s0, thread_index, 0); + nat_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); s0 = NULL; } @@ -1194,10 +1253,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, * Send DHCP packets to the ipv4 stack, or we won't * be able to use dhcp client on the outside interface */ - if (PREDICT_FALSE ( - proto0 == IP_PROTOCOL_UDP && - (vnet_buffer (b0)->ip.reass.l4_dst_port == - clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client)))) + if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_UDP + && (vnet_buffer (b0)->ip.reass.l4_dst_port == + clib_host_to_net_u16 + (UDP_DST_PORT_dhcp_to_client)))) { goto trace0; } @@ -1228,9 +1287,9 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, if (PREDICT_FALSE (identity_nat0)) goto trace0; - if ((proto0 == IP_PROTOCOL_TCP) && - !tcp_flags_is_init ( - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)) + if ((proto0 == NAT_PROTOCOL_TCP) + && !tcp_flags_is_init (vnet_buffer (b0)->ip. + reass.icmp_type_or_tcp_flags)) { b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NON_SYN]; next[0] = NAT_NEXT_DROP; @@ -1238,10 +1297,16 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, } /* Create session initiated by host from external network */ - s0 = create_session_for_static_mapping_ed ( - sm, b0, sm_addr, sm_port, sm_fib_index, ip0->dst_address, - vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0, - node, thread_index, twice_nat0, lb_nat0, now, m); + s0 = create_session_for_static_mapping_ed (sm, b0, + sm_addr, sm_port, + sm_fib_index, + ip0->dst_address, + vnet_buffer (b0)-> + ip.reass.l4_dst_port, + rx_fib_index0, proto0, + node, rx_fib_index0, + thread_index, twice_nat0, + lb_nat0, now, m); if (!s0) { next[0] = NAT_NEXT_DROP; @@ -1257,7 +1322,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - if (PREDICT_TRUE (proto0 == IP_PROTOCOL_TCP)) + if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) { vlib_increment_simple_counter (&sm->counters.slowpath.out2in.tcp, thread_index, sw_if_index0, 1); diff --git a/src/plugins/nat/nat44-ei/nat44_ei.c b/src/plugins/nat/nat44-ei/nat44_ei.c index 3691af3a53e..2dbef8e34df 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.c +++ b/src/plugins/nat/nat44-ei/nat44_ei.c @@ -1102,8 +1102,7 @@ nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s, /* log NAT event */ nat_ipfix_logging_nat44_ses_delete ( thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, - nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port, - s->in2out.fib_index); + s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index); nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr, s->ext_host_port, s->nat_proto, s->out2in.fib_index, @@ -1271,8 +1270,7 @@ nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s, nat_ipfix_logging_nat44_ses_delete ( thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, - nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port, - s->in2out.fib_index); + s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index); nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr, s->ext_host_port, s->nat_proto, s->out2in.fib_index, diff --git a/src/plugins/nat/nat44-ei/nat44_ei.h b/src/plugins/nat/nat44-ei/nat44_ei.h index 2e95b1413ca..2e5d85f071a 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.h +++ b/src/plugins/nat/nat44-ei/nat44_ei.h @@ -36,7 +36,6 @@ #include <nat/lib/lib.h> #include <nat/lib/inlines.h> -#include <nat/lib/nat_proto.h> /* default number of worker handoff frame queue elements */ #define NAT_FQ_NELTS_DEFAULT 64 diff --git a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c index a2fc5910584..1e28ed6b635 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c @@ -271,10 +271,13 @@ nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg) if (clib_bihash_add_del_8_8 (&nm->out2in, &s_kv, 0)) nat_elog_warn (nm, "out2in key del failed"); - nat_ipfix_logging_nat44_ses_delete ( - ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, - nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port, - s->in2out.fib_index); + nat_ipfix_logging_nat44_ses_delete (ctx->thread_index, + s->in2out.addr.as_u32, + s->out2in.addr.as_u32, + s->nat_proto, + s->in2out.port, + s->out2in.port, + s->in2out.fib_index); nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, @@ -427,9 +430,8 @@ slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0, /* log NAT event */ nat_ipfix_logging_nat44_ses_create ( - thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, - nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port, - s->in2out.fib_index); + thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->nat_proto, + s->in2out.port, s->out2in.port, s->in2out.fib_index); nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, &s->out2in.addr, s->out2in.port, diff --git a/src/plugins/nat/nat44-ei/nat44_ei_inlines.h b/src/plugins/nat/nat44-ei/nat44_ei_inlines.h index 399486c77dc..672927256d1 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_inlines.h +++ b/src/plugins/nat/nat44-ei/nat44_ei_inlines.h @@ -20,7 +20,6 @@ #include <nat/nat44-ei/nat44_ei.h> #include <nat/nat44-ei/nat44_ei_ha.h> -#include <nat/lib/nat_proto.h> always_inline u64 calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto) @@ -221,29 +220,6 @@ nat44_ei_session_update_counters (nat44_ei_session_t *s, f64 now, uword bytes, &s->ha_last_refreshed, now); } -static_always_inline u32 -nat_session_get_timeout (nat_timeouts_t *timeouts, nat_protocol_t proto, - u8 state) -{ - switch (proto) - { - case NAT_PROTOCOL_ICMP: - return timeouts->icmp; - case NAT_PROTOCOL_UDP: - return timeouts->udp; - case NAT_PROTOCOL_TCP: - { - if (state) - return timeouts->tcp.transitory; - else - return timeouts->tcp.established; - } - default: - return timeouts->udp; - } - return 0; -} - #endif /* __included_nat44_ei_inlines_h__ */ /* diff --git a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c index 7858811fde5..7796b11cfd7 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c @@ -124,10 +124,13 @@ nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg) if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0)) nat_elog_warn (nm, "out2in key del failed"); - nat_ipfix_logging_nat44_ses_delete ( - ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, - nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port, - s->in2out.fib_index); + nat_ipfix_logging_nat44_ses_delete (ctx->thread_index, + s->in2out.addr.as_u32, + s->out2in.addr.as_u32, + s->nat_proto, + s->in2out.port, + s->out2in.port, + s->in2out.fib_index); nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, @@ -230,10 +233,12 @@ create_session_for_static_mapping ( nat_elog_notice (nm, "out2in key add failed"); /* log NAT event */ - nat_ipfix_logging_nat44_ses_create ( - thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, - nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port, - s->in2out.fib_index); + nat_ipfix_logging_nat44_ses_create (thread_index, + s->in2out.addr.as_u32, + s->out2in.addr.as_u32, + s->nat_proto, + s->in2out.port, + s->out2in.port, s->in2out.fib_index); nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index, &s->in2out.addr, s->in2out.port, &s->out2in.addr, diff --git a/src/plugins/nat/nat64/nat64_db.h b/src/plugins/nat/nat64/nat64_db.h index c34b671999a..711b6bf6b03 100644 --- a/src/plugins/nat/nat64/nat64_db.h +++ b/src/plugins/nat/nat64/nat64_db.h @@ -18,7 +18,6 @@ #include <vnet/vnet.h> #include <vnet/ip/ip.h> #include <vnet/fib/fib_source.h> -#include <nat/lib/nat_proto.h> #include <vppinfra/bihash_24_8.h> #include <vppinfra/bihash_48_8.h> diff --git a/test/framework.py b/test/framework.py index 486553befa1..aa533f7b641 100755 --- a/test/framework.py +++ b/test/framework.py @@ -1304,8 +1304,6 @@ class VppTestCase(CPUInterface, unittest.TestCase): n_rx = len(pkts) self.pg_send(intf, pkts, worker=worker, trace=trace) rx = output.get_capture(n_rx) - if trace: - self.logger.debug(self.vapi.cli("show trace")) return rx def send_and_expect_only(self, intf, pkts, output, timeout=None): diff --git a/test/test_nat44_ed.py b/test/test_nat44_ed.py index 2fb955afa74..ec8d7c8d159 100644 --- a/test/test_nat44_ed.py +++ b/test/test_nat44_ed.py @@ -19,8 +19,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath from vpp_papi import VppEnum -class TestNAT44ED(VppTestCase): - """ NAT44ED Test Case """ +class NAT44EDTestCase(VppTestCase): nat_addr = '10.0.0.3' @@ -38,18 +37,17 @@ class TestNAT44ED(VppTestCase): max_sessions = 100 def setUp(self): - super().setUp() + super(NAT44EDTestCase, self).setUp() self.plugin_enable() def tearDown(self): - super().tearDown() + super(NAT44EDTestCase, self).tearDown() if not self.vpp_dead: self.plugin_disable() def plugin_enable(self): self.vapi.nat44_ed_plugin_enable_disable( - sessions=self.max_sessions, enable=1, - inside_vrf=0, outside_vrf=1) + sessions=self.max_sessions, enable=1) def plugin_disable(self): self.vapi.nat44_ed_plugin_enable_disable(enable=0) @@ -148,7 +146,7 @@ class TestNAT44ED(VppTestCase): @classmethod def setUpClass(cls): - super().setUpClass() + super(NAT44EDTestCase, cls).setUpClass() cls.create_pg_interfaces(range(12)) cls.interfaces = list(cls.pg_interfaces[:4]) @@ -912,6 +910,10 @@ class TestNAT44ED(VppTestCase): self.assertEqual(sd_params.get('XDPORT'), "%d" % self.tcp_external_port) + +class TestNAT44ED(NAT44EDTestCase): + """ NAT44ED Test Case """ + def test_icmp_error(self): """ NAT44ED test ICMP error message with inner header""" @@ -2256,7 +2258,7 @@ class TestNAT44EDMW(TestNAT44ED): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture(pkt_count * 3, timeout=5) + capture = self.pg1.get_capture(pkt_count * 3) if_idx = self.pg0.sw_if_index tc2 = self.statistics['/nat44-ed/in2out/slowpath/tcp'] diff --git a/test/test_nat44_ed_output.py b/test/test_nat44_ed_output.py deleted file mode 100644 index ea5c14e7064..00000000000 --- a/test/test_nat44_ed_output.py +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env python3 -"""NAT44 ED output-feature tests""" - -import random -import unittest -from scapy.layers.inet import ICMP, Ether, IP, TCP -from scapy.packet import Raw -from scapy.data import IP_PROTOS -from framework import VppTestCase, VppTestRunner -from vpp_papi import VppEnum - - -def get_nat44_ed_in2out_worker_index(ip, vpp_worker_count): - if 0 == vpp_worker_count: - return 0 - numeric = socket.inet_aton(ip) - numeric = struct.unpack("!L", numeric)[0] - numeric = socket.htonl(numeric) - h = numeric + (numeric >> 8) + (numeric >> 16) + (numeric >> 24) - return 1 + h % vpp_worker_count - - -class TestNAT44EDOutput(VppTestCase): - """ NAT44 ED output feature Test Case """ - max_sessions = 1024 - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.create_pg_interfaces(range(2)) - cls.interfaces = list(cls.pg_interfaces) - - @classmethod - def tearDownClass(cls): - super().tearDownClass() - - def setUp(self): - super().setUp() - for i in self.interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - self.vapi.nat44_ed_plugin_enable_disable(sessions=self.max_sessions, - enable=1) - - def tearDown(self): - if not self.vpp_dead: - self.logger.debug(self.vapi.cli("show nat44 sessions")) - super().tearDown() - if not self.vpp_dead: - for i in self.pg_interfaces: - i.unconfig_ip4() - i.admin_down() - self.vapi.nat44_ed_plugin_enable_disable(enable=0) - - def test_static_dynamic(self): - """ Create static mapping which matches existing dynamic mapping """ - - old_timeouts = self.vapi.nat_get_timeouts() - new_transitory = 2 - self.vapi.nat_set_timeouts( - udp=old_timeouts.udp, - tcp_established=old_timeouts.tcp_established, - icmp=old_timeouts.icmp, - tcp_transitory=new_transitory) - - local_host = self.pg0.remote_ip4 - remote_host = self.pg1.remote_ip4 - nat_intf = self.pg1 - outside_addr = nat_intf.local_ip4 - - self.vapi.nat44_add_del_address_range(first_ip_address=outside_addr, - last_ip_address=outside_addr, - vrf_id=0xffffffff, - is_add=1, - flags=0) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - is_add=1) - self.vapi.nat44_interface_add_del_feature( - sw_if_index=self.pg0.sw_if_index, - flags=VppEnum.vl_api_nat_config_flags_t.NAT_IS_INSIDE, is_add=1) - self.vapi.nat44_interface_add_del_output_feature( - is_add=1, - sw_if_index=self.pg1.sw_if_index) - - thread_index = get_nat44_ed_in2out_worker_index( - local_host, self.vpp_worker_count) - port_per_thread = int((0xffff-1024) / max(1, self.vpp_worker_count)) - local_sport = 1024 + random.randint(1, port_per_thread) - if self.vpp_worker_count > 0: - local_sport += port_per_thread * (thread_index - 1) - - remote_dport = 10000 - - pg0 = self.pg0 - pg1 = self.pg1 - - # first setup a dynamic TCP session - - # SYN packet in->out - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="S")) - p = self.send_and_expect(pg0, [p], pg1)[0] - - self.assertEqual(p[IP].src, outside_addr) - self.assertEqual(p[TCP].sport, local_sport) - outside_port = p[TCP].sport - - # SYN+ACK packet out->in - p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) / - IP(src=remote_host, dst=outside_addr) / - TCP(sport=remote_dport, dport=outside_port, flags="SA")) - self.send_and_expect(pg1, [p], pg0) - - # ACK packet in->out - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="A")) - self.send_and_expect(pg0, [p], pg1) - - # now we have a session up, create a conflicting static mapping - self.vapi.nat44_add_del_static_mapping( - is_add=1, - local_ip_address=local_host, - external_ip_address=outside_addr, - external_sw_if_index=0xffffffff, - local_port=local_sport, - external_port=outside_port, - protocol=IP_PROTOS.tcp, - flags=VppEnum.vl_api_nat_config_flags_t.NAT_IS_OUT2IN_ONLY) - - sessions = self.vapi.nat44_user_session_dump(local_host, 0) - self.assertEqual(1, len(sessions)) - - # now send some more data over existing session - it should pass - - # in->out - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport) / - Raw("zippity zap")) - self.send_and_expect(pg0, [p], pg1) - - # out->in - p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) / - IP(src=remote_host, dst=outside_addr) / - TCP(sport=remote_dport, dport=outside_port) / - Raw("flippity flop")) - self.send_and_expect(pg1, [p], pg0) - - # now close the session - - # FIN packet in -> out - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="FA", seq=100, - ack=300)) - self.send_and_expect(pg0, [p], pg1) - - # FIN+ACK packet out -> in - p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) / - IP(src=remote_host, dst=outside_addr) / - TCP(sport=remote_dport, dport=outside_port, flags="FA", seq=300, - ack=101)) - self.send_and_expect(pg1, [p], pg0) - - # ACK packet in -> out - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="A", seq=101, - ack=301)) - self.send_and_expect(pg0, [p], pg1) - - # session now in transitory timeout - # try SYN packet in->out - should be dropped - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="S")) - pg0.add_stream(p) - self.pg_enable_capture() - self.pg_start() - - self.sleep(new_transitory, "wait for transitory timeout") - pg0.assert_nothing_captured(0) - - # session should still exist - sessions = self.vapi.nat44_user_session_dump(pg0.remote_ip4, 0) - self.assertEqual(1, len(sessions)) - - # send FIN+ACK packet in->out - will cause session to be wiped - # but won't create a new session - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="FA", seq=300, - ack=101)) - pg1.add_stream(p) - self.pg_enable_capture() - self.pg_start() - pg0.assert_nothing_captured(0) - - sessions = self.vapi.nat44_user_session_dump(pg0.remote_ip4, 0) - self.assertEqual(0, len(sessions)) - - # create a new session and make sure the outside port is remapped - # SYN packet in->out - - p = (Ether(src=pg0.remote_mac, dst=pg0.local_mac) / - IP(src=local_host, dst=remote_host) / - TCP(sport=local_sport, dport=remote_dport, flags="S")) - p = self.send_and_expect(pg0, [p], pg1)[0] - - self.assertEqual(p[IP].src, outside_addr) - self.assertNotEqual(p[TCP].sport, local_sport) - - # make sure static mapping works and creates a new session - # SYN packet out->in - p = (Ether(src=pg1.remote_mac, dst=pg1.local_mac) / - IP(src=remote_host, dst=outside_addr) / - TCP(sport=remote_dport, dport=outside_port, flags="S")) - self.send_and_expect(pg1, [p], pg0) - - sessions = self.vapi.nat44_user_session_dump(pg0.remote_ip4, 0) - self.assertEqual(2, len(sessions)) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) diff --git a/test/test_nat44_ei.py b/test/test_nat44_ei.py index 5fdcf3fa3c7..74a082eee0a 100644 --- a/test/test_nat44_ei.py +++ b/test/test_nat44_ei.py @@ -605,7 +605,7 @@ class MethodHolder(VppTestCase): self.assertEqual(struct.pack("!H", self.udp_port_out), record[227]) else: - self.fail(f"Invalid protocol {scapy.compat.orb(record[4])}") + self.fail("Invalid protocol") self.assertEqual(3, nat44_ses_create_num) self.assertEqual(3, nat44_ses_delete_num) |