aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/out2in_ed.c
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2020-12-15 18:47:05 +0100
committerOle Tr�an <otroan@employees.org>2021-01-18 08:36:26 +0000
commit4881cb4c6f0d9c6276eb7a45ed355f9fc3d729b3 (patch)
tree07959eb6fc99b88b30e6f81f4620d8d6c70110e2 /src/plugins/nat/out2in_ed.c
parent4a58e49cfe03150034a65e147a2ffe8d24391b86 (diff)
nat: deal with flows instead of sessions
This change introduces flow concept to endpoint-dependent NAT. Instead of having a session and a plethora of special cases in code for e.g. hairpinning, twice-nat and others, figure all this out and store it in flow logic. Every flow has a match and a rewrite part. This unifies all the NAT packet processing cases into one - match a flow and rewrite the packet based on that flow. It also provides a cure for hairpinning dilemma where one part of the flow is on one worker and another on a different one. These cases are also sped up by not requiring destination adress lookup every single time to be able to rewrite source nat as this is now part of flow rewrite logic. Type: improvement Change-Id: Ib60c992e16792ea4d4129bc10202ebb99a73b5be Signed-off-by: Klement Sekera <ksekera@cisco.com>
Diffstat (limited to 'src/plugins/nat/out2in_ed.c')
-rw-r--r--src/plugins/nat/out2in_ed.c1255
1 files changed, 514 insertions, 741 deletions
diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c
index beb259eee33..d6beadc61bc 100644
--- a/src/plugins/nat/out2in_ed.c
+++ b/src/plugins/nat/out2in_ed.c
@@ -42,14 +42,15 @@ typedef struct
u32 sw_if_index;
u32 next_index;
u32 session_index;
- u32 is_slow_path;
+ nat_translation_error_e translation_error;
+ nat_6t_flow_t i2of;
+ nat_6t_flow_t o2if;
+ clib_bihash_kv_16_8_t search_key;
+ u8 is_slow_path;
+ u8 translation_via_i2of;
+ u8 lookup_skipped;
} nat44_ed_out2in_trace_t;
-typedef struct
-{
- u16 thread_next;
-} nat44_ed_out2in_handoff_trace_t;
-
static u8 *
format_nat44_ed_out2in_trace (u8 * s, va_list * args)
{
@@ -64,130 +65,174 @@ format_nat44_ed_out2in_trace (u8 * s, va_list * args)
s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag,
t->sw_if_index, t->next_index, t->session_index);
+ if (~0 != t->session_index)
+ {
+ s = format (s, ", translation result '%U' via %s",
+ format_nat_ed_translation_error, t->translation_error,
+ t->translation_via_i2of ? "i2of" : "o2if");
+ s = format (s, "\n i2of %U", format_nat_6t_flow, &t->i2of);
+ s = format (s, "\n o2if %U", format_nat_6t_flow, &t->o2if);
+ }
+ if (!t->is_slow_path)
+ {
+ if (t->lookup_skipped)
+ {
+ s = format (s, "\n lookup skipped - cached session index used");
+ }
+ else
+ {
+ s = format (s, "\n search key %U", format_ed_session_kvp,
+ &t->search_key);
+ }
+ }
return s;
}
+static int
+next_src_nat (snat_main_t *sm, ip4_header_t *ip, u16 src_port, u16 dst_port,
+ u32 thread_index, u32 rx_fib_index)
+{
+ clib_bihash_kv_16_8_t kv, value;
+
+ 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;
+
+ return 0;
+}
+
+static void create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b,
+ snat_session_t *s, ip4_header_t *ip,
+ u32 rx_fib_index, u32 thread_index);
+
+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,
+ 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
-icmp_out2in_ed_slow_path (snat_main_t * sm, vlib_buffer_t * b0,
- ip4_header_t * ip0, icmp46_header_t * icmp0,
- u32 sw_if_index0, u32 rx_fib_index0,
- vlib_node_runtime_t * node, u32 next0, f64 now,
- u32 thread_index, snat_session_t ** p_s0)
+icmp_out2in_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip,
+ icmp46_header_t *icmp, u32 sw_if_index,
+ u32 rx_fib_index, vlib_node_runtime_t *node,
+ u32 next, f64 now, u32 thread_index,
+ snat_session_t **s_p)
{
vlib_main_t *vm = vlib_get_main ();
- next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
- next0, thread_index, p_s0, 0);
- snat_session_t *s0 = *p_s0;
- if (PREDICT_TRUE (next0 != NAT_NEXT_DROP && s0))
+ ip_csum_t sum;
+ u16 checksum;
+
+ snat_session_t *s = 0;
+ u8 is_addr_only, identity_nat;
+ ip4_address_t sm_addr;
+ u16 sm_port;
+ u32 sm_fib_index;
+ snat_static_mapping_t *m;
+ u8 lookup_protocol;
+ ip4_address_t lookup_saddr, lookup_daddr;
+ u16 lookup_sport, lookup_dport;
+
+ sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
+ rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
+
+ if (nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr, &lookup_sport,
+ &lookup_daddr, &lookup_dport,
+ &lookup_protocol))
{
- /* Accounting */
- nat44_session_update_counters (s0, now,
- vlib_buffer_length_in_chain
- (vm, b0), thread_index);
- /* Per-user LRU list maintenance */
- nat44_session_update_lru (sm, s0, thread_index);
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
+ next = NAT_NEXT_DROP;
+ goto out;
}
- return next0;
-}
-
-#ifndef CLIB_MARCH_VARIANT
-int
-nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
-{
- snat_main_t *sm = &snat_main;
- nat44_is_idle_session_ctx_t *ctx = arg;
- snat_session_t *s;
- u64 sess_timeout_time;
- u8 proto;
- u16 r_port, l_port;
- ip4_address_t *l_addr, *r_addr;
- u32 fib_index;
- clib_bihash_kv_16_8_t ed_kv;
- int i;
- //snat_address_t *a;
- snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
- ctx->thread_index);
- s = pool_elt_at_index (tsm->sessions, kv->value);
- sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
- if (ctx->now >= sess_timeout_time)
+ if (snat_static_mapping_match (
+ 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))
{
- l_addr = &s->in2out.addr;
- r_addr = &s->ext_host_addr;
- fib_index = s->in2out.fib_index;
- if (snat_is_unk_proto_session (s))
+ // static mapping not matched
+ if (!sm->forwarding_enabled)
{
- proto = s->in2out.port;
- r_port = 0;
- l_port = 0;
+ /* Don't NAT packet aimed at the intfc address */
+ if (!is_interface_addr (sm, node, sw_if_index,
+ ip->dst_address.as_u32))
+ {
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
+ next = NAT_NEXT_DROP;
+ }
}
else
{
- proto = nat_proto_to_ip_proto (s->nat_proto);
- l_port = s->in2out.port;
- r_port = s->ext_host_port;
- }
- if (is_twice_nat_session (s))
- {
- r_addr = &s->ext_host_nat_addr;
- r_port = s->ext_host_nat_port;
- }
- init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
- if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
- nat_elog_warn ("in2out_ed key del failed");
-
- if (snat_is_unk_proto_session (s))
- goto delete;
-
- 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_sdel (s->user_index, 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, is_twice_nat_session (s));
-
- if (is_twice_nat_session (s))
- {
- for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
+ if (next_src_nat (sm, ip, lookup_sport, lookup_dport, thread_index,
+ rx_fib_index))
{
- // FIXME TODO this is obviously wrong code ... needs fix!
- // key.protocol = s->nat_proto;
- // key.port = s->ext_host_nat_port;
- // a = sm->twice_nat_addresses + i;
- // if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
- // {
- // snat_free_outside_address_and_port (sm->twice_nat_addresses,
- // ctx->thread_index,
- // &key);
- // break;
- // }
+ next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
+ }
+ else
+ {
+ create_bypass_for_fwd (sm, b, s, ip, rx_fib_index, thread_index);
}
}
+ goto out;
+ }
- if (snat_is_session_static (s))
- goto delete;
+ if (PREDICT_FALSE (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
+ ICMP4_echo_reply &&
+ (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
+ ICMP4_echo_request ||
+ !is_addr_only)))
+ {
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
+ next = NAT_NEXT_DROP;
+ goto out;
+ }
- snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
- &s->out2in.addr, s->out2in.port,
- s->nat_proto);
- delete:
- nat_ed_session_delete (sm, s, ctx->thread_index, 1);
- return 1;
+ if (PREDICT_FALSE (identity_nat))
+ {
+ goto out;
}
- return 0;
+ /* 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, 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;
+
+ if (PREDICT_TRUE (!ip4_is_fragment (ip)))
+ {
+ sum = ip_incremental_checksum_buffer (
+ vm, b, (u8 *) icmp - (u8 *) vlib_buffer_get_current (b),
+ ntohs (ip->length) - ip4_header_bytes (ip), 0);
+ checksum = ~ip_csum_fold (sum);
+ if (checksum != 0 && checksum != 0xffff)
+ {
+ next = NAT_NEXT_DROP;
+ goto out;
+ }
+ }
+
+ if (PREDICT_TRUE (next != NAT_NEXT_DROP && s))
+ {
+ /* Accounting */
+ nat44_session_update_counters (
+ s, now, vlib_buffer_length_in_chain (vm, b), thread_index);
+ /* Per-user LRU list maintenance */
+ nat44_session_update_lru (sm, s, thread_index);
+ }
+out:
+ if (NAT_NEXT_DROP == next && s)
+ {
+ nat_ed_session_delete (sm, s, thread_index, 1);
+ s = 0;
+ }
+ *s_p = s;
+ return next;
}
-#endif
// allocate exact address based on preference
static_always_inline int
@@ -317,28 +362,17 @@ nat44_ed_alloc_outside_addr_and_port (snat_address_t *addresses, u32 fib_index,
}
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,
- 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)
+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,
+ 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;
udp_header_t *udp;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
- clib_bihash_kv_16_8_t kv;
- nat44_is_idle_session_ctx_t ctx;
if (PREDICT_FALSE
(nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
@@ -375,15 +409,29 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
s->in2out.fib_index = i2o_fib_index;
s->nat_proto = nat_proto;
- /* Add to lookup tables */
- init_ed_kv (&kv, o2i_addr, o2i_port, s->ext_host_addr, s->ext_host_port,
- o2i_fib_index, ip->protocol, thread_index, s - tsm->sessions);
- ctx.now = now;
- ctx.thread_index = thread_index;
- if (clib_bihash_add_or_overwrite_stale_16_8 (&sm->out2in_ed, &kv,
- nat44_o2i_ed_is_idle_session_cb,
- &ctx))
- nat_elog_notice ("out2in-ed key add failed");
+ 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);
+ nat_6t_flow_icmp_id_rewrite_set (&s->o2i, i2o_port);
+ }
+ else
+ {
+ nat_6t_o2i_flow_init (sm, thread_index, s, s->ext_host_addr,
+ s->ext_host_port, o2i_addr, o2i_port,
+ o2i_fib_index, ip->protocol);
+ nat_6t_flow_dport_rewrite_set (&s->o2i, i2o_port);
+ }
+ nat_6t_flow_daddr_rewrite_set (&s->o2i, i2o_addr.as_u32);
+ nat_6t_flow_txfib_rewrite_set (&s->o2i, i2o_fib_index);
+
+ if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
+ {
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_HASH_ADD_FAILED];
+ nat_ed_session_delete (sm, s, thread_index, 1);
+ nat_elog_warn ("out2in flow hash add failed");
+ return 0;
+ }
if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF &&
ip->src_address.as_u32 == i2o_addr.as_u32))
@@ -427,27 +475,80 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
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 ("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);
- if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &kv, 0))
- nat_elog_notice ("out2in-ed key del failed");
return 0;
}
s->flags |= SNAT_SESSION_FLAG_TWICE_NAT;
- init_ed_kv (&kv, i2o_addr, i2o_port, s->ext_host_nat_addr,
- s->ext_host_nat_port, i2o_fib_index, ip->protocol,
- thread_index, s - tsm->sessions);
+
+ nat_6t_flow_saddr_rewrite_set (&s->o2i, s->ext_host_nat_addr.as_u32);
+ if (NAT_PROTOCOL_ICMP == nat_proto)
+ {
+ nat_6t_flow_icmp_id_rewrite_set (&s->o2i, s->ext_host_nat_port);
+ }
+ else
+ {
+ nat_6t_flow_sport_rewrite_set (&s->o2i, s->ext_host_nat_port);
+ }
+
+ 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 (NAT_PROTOCOL_ICMP == nat_proto)
+ {
+ nat_6t_flow_icmp_id_rewrite_set (&s->i2o, s->ext_host_port);
+ }
+ else
+ {
+ nat_6t_flow_dport_rewrite_set (&s->i2o, s->ext_host_port);
+ }
+ }
+ else
+ {
+ 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,
+ ip->protocol);
+ }
+ else
+ {
+ nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port,
+ 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 (NAT_PROTOCOL_ICMP == nat_proto)
+ {
+ nat_6t_flow_icmp_id_rewrite_set (&s->i2o, o2i_port);
}
else
{
- init_ed_kv (&kv, i2o_addr, i2o_port, s->ext_host_addr,
- s->ext_host_port, i2o_fib_index, ip->protocol,
- thread_index, s - tsm->sessions);
+ nat_6t_flow_sport_rewrite_set (&s->i2o, o2i_port);
+ }
+
+ if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
+ {
+ nat_elog_notice ("in2out flow hash add failed");
+ if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
+ {
+ nat_elog_warn ("out2in flow hash del failed");
+ }
+ nat_ed_session_delete (sm, s, thread_index, 1);
+ return 0;
}
- if (clib_bihash_add_or_overwrite_stale_16_8 (&tsm->in2out_ed, &kv,
- nat44_i2o_ed_is_idle_session_cb,
- &ctx))
- nat_elog_notice ("in2out-ed key add failed");
nat_ipfix_logging_nat44_ses_create (thread_index,
s->in2out.addr.as_u32,
@@ -468,37 +569,24 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
return s;
}
-static int
-next_src_nat (snat_main_t * sm, ip4_header_t * ip, u16 src_port,
- u16 dst_port, u32 thread_index, u32 rx_fib_index)
-{
- clib_bihash_kv_16_8_t kv, value;
- snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-
- 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 (&tsm->in2out_ed, &kv, &value))
- return 1;
-
- return 0;
-}
-
static void
-create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
- u32 rx_fib_index, u32 thread_index)
+create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s,
+ ip4_header_t *ip, u32 rx_fib_index, u32 thread_index)
{
clib_bihash_kv_16_8_t kv, value;
udp_header_t *udp;
- snat_session_t *s = 0;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
vlib_main_t *vm = vlib_get_main ();
f64 now = vlib_time_now (vm);
- u16 l_port, r_port;
+ u16 lookup_sport, lookup_dport;
+ u8 lookup_protocol;
+ ip4_address_t lookup_saddr, lookup_daddr;
if (ip->protocol == IP_PROTOCOL_ICMP)
{
- if (get_icmp_o2i_ed_key
- (b, ip, rx_fib_index, ~0, ~0, 0, &l_port, &r_port, &kv))
+ if (nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr,
+ &lookup_sport, &lookup_daddr,
+ &lookup_dport, &lookup_protocol))
return;
}
else
@@ -506,19 +594,23 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP)
{
udp = ip4_next_header (ip);
- l_port = udp->dst_port;
- r_port = udp->src_port;
+ lookup_sport = udp->dst_port;
+ lookup_dport = udp->src_port;
}
else
{
- l_port = 0;
- r_port = 0;
+ lookup_sport = 0;
+ lookup_dport = 0;
}
- init_ed_k (&kv, ip->dst_address, l_port, ip->src_address, r_port,
- rx_fib_index, ip->protocol);
+ lookup_saddr.as_u32 = ip->dst_address.as_u32;
+ lookup_daddr.as_u32 = ip->src_address.as_u32;
+ lookup_protocol = ip->protocol;
}
- if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv, &value))
+ 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))
{
ASSERT (thread_index == ed_value_get_thread_index (&value));
s =
@@ -550,10 +642,10 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
proto = ip_proto_to_nat_proto (ip->protocol);
s->ext_host_addr = ip->src_address;
- s->ext_host_port = r_port;
+ s->ext_host_port = lookup_dport;
s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS;
s->out2in.addr = ip->dst_address;
- s->out2in.port = l_port;
+ s->out2in.port = lookup_sport;
s->nat_proto = proto;
if (proto == NAT_PROTOCOL_OTHER)
{
@@ -565,9 +657,16 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
s->in2out.port = s->out2in.port;
s->in2out.fib_index = s->out2in.fib_index;
- kv.value = s - tsm->sessions;
- if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
- nat_elog_notice ("in2out_ed key add failed");
+ nat_6t_i2o_flow_init (sm, thread_index, s, ip->dst_address, lookup_sport,
+ ip->src_address, lookup_dport, rx_fib_index,
+ ip->protocol);
+ nat_6t_flow_txfib_rewrite_set (&s->i2o, rx_fib_index);
+ if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
+ {
+ nat_elog_notice ("in2out flow add failed");
+ nat_ed_session_delete (sm, s, thread_index, 1);
+ return;
+ }
per_vrf_sessions_register_session (s, thread_index);
}
@@ -586,261 +685,75 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
nat44_session_update_lru (sm, s, thread_index);
}
-static_always_inline int
-create_bypass_for_fwd_worker (snat_main_t * sm,
- vlib_buffer_t * b, ip4_header_t * ip,
- u32 rx_fib_index, u32 thread_index)
-{
- ip4_header_t tmp = {
- .src_address = ip->dst_address,
- };
- u32 index = sm->worker_in2out_cb (&tmp, rx_fib_index, 0);
-
- if (index != thread_index)
- {
- vnet_buffer2 (b)->nat.thread_next = index;
- return 1;
- }
-
- create_bypass_for_fwd (sm, b, ip, rx_fib_index, thread_index);
- return 0;
-}
-
-#ifndef CLIB_MARCH_VARIANT
-u32
-icmp_match_out2in_ed (snat_main_t * sm, vlib_node_runtime_t * node,
- u32 thread_index, vlib_buffer_t * b,
- ip4_header_t * ip, ip4_address_t * addr,
- u16 * port, u32 * fib_index, nat_protocol_t * proto,
- void *d, void *e, u8 * dont_translate)
+static snat_session_t *
+nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
+ ip4_header_t *ip, u32 rx_fib_index,
+ u32 thread_index, f64 now,
+ vlib_main_t *vm,
+ vlib_node_runtime_t *node)
{
- u32 next = ~0, sw_if_index, rx_fib_index;
- clib_bihash_kv_16_8_t kv, value;
- snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
- snat_session_t *s = 0;
- u8 is_addr_only, identity_nat;
- u16 l_port, r_port;
- vlib_main_t *vm = vlib_get_main ();
- ip4_address_t sm_addr;
- u16 sm_port;
- u32 sm_fib_index;
- *dont_translate = 0;
+ clib_bihash_kv_8_8_t kv, value;
snat_static_mapping_t *m;
+ snat_session_t *s;
- sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
- rx_fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
-
- if (get_icmp_o2i_ed_key
- (b, ip, rx_fib_index, ~0, ~0, proto, &l_port, &r_port, &kv))
+ if (PREDICT_FALSE (
+ nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
{
- b->error = node->errors[NAT_OUT2IN_ED_ERROR_UNSUPPORTED_PROTOCOL];
- next = NAT_NEXT_DROP;
- goto out;
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
+ nat_elog_notice ("maximum sessions exceeded");
+ return 0;
}
- if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
+ init_nat_k (&kv, ip->dst_address, 0, 0, 0);
+ if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
{
- if (snat_static_mapping_match
- (sm, ip->dst_address, l_port, 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)
- {
- /* Don't NAT packet aimed at the intfc address */
- if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index,
- ip->dst_address.as_u32)))
- {
- *dont_translate = 1;
- }
- else
- {
- b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
- next = NAT_NEXT_DROP;
- }
- }
- else
- {
- *dont_translate = 1;
- if (next_src_nat (sm, ip, l_port, r_port,
- thread_index, rx_fib_index))
- {
- next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
- }
- else
- {
- if (sm->num_workers > 1)
- {
- if (create_bypass_for_fwd_worker (sm, b, ip,
- rx_fib_index,
- thread_index))
- {
- next = NAT_NEXT_OUT2IN_ED_HANDOFF;
- }
- }
- else
- {
- create_bypass_for_fwd (sm, b, ip, rx_fib_index,
- thread_index);
- }
- }
- }
- goto out;
- }
-
- if (PREDICT_FALSE
- (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
- ICMP4_echo_reply
- && (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
- ICMP4_echo_request || !is_addr_only)))
- {
- b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
- next = NAT_NEXT_DROP;
- goto out;
- }
-
- if (PREDICT_FALSE (identity_nat))
- {
- *dont_translate = 1;
- goto out;
- }
-
- /* 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,
- l_port, rx_fib_index, *proto,
- node, rx_fib_index,
- thread_index, 0, 0,
- vlib_time_now (vm), m);
- if (!s)
- next = NAT_NEXT_DROP;
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
+ return 0;
}
- else
- {
- if (PREDICT_FALSE
- (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
- ICMP4_echo_reply
- && vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags !=
- ICMP4_echo_request
- && !icmp_type_is_error_message (vnet_buffer (b)->ip.
- reass.icmp_type_or_tcp_flags)))
- {
- b->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
- next = NAT_NEXT_DROP;
- goto out;
- }
- ASSERT (thread_index == ed_value_get_thread_index (&value));
- s =
- pool_elt_at_index (tsm->sessions,
- ed_value_get_session_index (&value));
- }
-out:
- if (s)
+ 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)
{
- *addr = s->in2out.addr;
- *port = s->in2out.port;
- *fib_index = s->in2out.fib_index;
+ b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
+ nat_elog_warn ("create NAT session failed");
+ return 0;
}
- if (d)
- *(snat_session_t **) d = s;
- return next;
-}
-#endif
-
-static snat_session_t *
-nat44_ed_out2in_unknown_proto (snat_main_t * sm,
- vlib_buffer_t * b,
- ip4_header_t * ip,
- u32 rx_fib_index,
- u32 thread_index,
- f64 now,
- 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;
- u32 old_addr, new_addr;
- ip_csum_t sum;
- snat_session_t *s;
- snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
- old_addr = ip->dst_address.as_u32;
-
- init_ed_k (&s_kv, ip->dst_address, 0, ip->src_address, 0, rx_fib_index,
- ip->protocol);
-
- if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
+ 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->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
+ s->out2in.addr.as_u32 = ip->dst_address.as_u32;
+ s->out2in.fib_index = rx_fib_index;
+ s->in2out.addr.as_u32 = m->local_addr.as_u32;
+ s->in2out.fib_index = m->fib_index;
+ s->in2out.port = s->out2in.port = ip->protocol;
+
+ nat_6t_o2i_flow_init (sm, thread_index, s, ip->dst_address, 0,
+ ip->src_address, 0, m->fib_index, ip->protocol);
+ nat_6t_flow_saddr_rewrite_set (&s->i2o, ip->dst_address.as_u32);
+ if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
{
- ASSERT (thread_index == ed_value_get_thread_index (&s_value));
- s =
- pool_elt_at_index (tsm->sessions,
- ed_value_get_session_index (&s_value));
- new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32;
+ nat_elog_notice ("in2out key add failed");
+ nat_ed_session_delete (sm, s, thread_index, 1);
+ return NULL;
}
- else
- {
- 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 ("maximum sessions exceeded");
- return 0;
- }
-
- 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);
-
- new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
- /* Create a new session */
- s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
- if (!s)
- {
- b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
- nat_elog_warn ("create NAT session failed");
- return 0;
- }
-
- 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->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
- s->out2in.addr.as_u32 = old_addr;
- s->out2in.fib_index = rx_fib_index;
- s->in2out.addr.as_u32 = new_addr;
- s->in2out.fib_index = m->fib_index;
- s->in2out.port = s->out2in.port = ip->protocol;
-
- /* Add to lookup tables */
- s_kv.value = s - tsm->sessions;
- if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1))
- nat_elog_notice ("out2in key add failed");
-
- init_ed_kv (&s_kv, ip->dst_address, 0, ip->src_address, 0, m->fib_index,
- ip->protocol, thread_index, s - tsm->sessions);
- if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &s_kv, 1))
- nat_elog_notice ("in2out key add failed");
-
- per_vrf_sessions_register_session (s, thread_index);
+ nat_6t_o2i_flow_init (sm, thread_index, s, ip->src_address, 0,
+ ip->dst_address, 0, rx_fib_index, ip->protocol);
+ nat_6t_flow_daddr_rewrite_set (&s->o2i, m->local_addr.as_u32);
+ nat_6t_flow_txfib_rewrite_set (&s->o2i, m->fib_index);
+ if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
+ {
+ nat_elog_notice ("out2in flow hash add failed");
+ nat_ed_session_delete (sm, s, thread_index, 1);
+ return NULL;
}
- /* Update IP checksum */
- sum = ip->checksum;
- sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
- ip->checksum = ip_csum_fold (sum);
-
- vnet_buffer (b)->sw_if_index[VLIB_TX] = s->in2out.fib_index;
+ per_vrf_sessions_register_session (s, thread_index);
/* Accounting */
nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b),
@@ -873,18 +786,24 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
while (n_left_from > 0)
{
vlib_buffer_t *b0;
- u32 sw_if_index0, rx_fib_index0, proto0, old_addr0, new_addr0;
- u16 old_port0, new_port0;
+ u32 sw_if_index0, rx_fib_index0;
+ nat_protocol_t proto0;
ip4_header_t *ip0;
- udp_header_t *udp0;
- tcp_header_t *tcp0;
snat_session_t *s0 = 0;
clib_bihash_kv_16_8_t kv0, value0;
- ip_csum_t sum0;
+ nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
+ nat_6t_flow_t *f = 0;
+ ip4_address_t lookup_saddr, lookup_daddr;
+ u16 lookup_sport, lookup_dport;
+ u8 lookup_protocol;
+ int lookup_skipped = 0;
b0 = *b;
b++;
+ lookup_sport = vnet_buffer (b0)->ip.reass.l4_src_port;
+ lookup_dport = vnet_buffer (b0)->ip.reass.l4_dst_port;
+
/* Prefetch next iteration. */
if (PREDICT_TRUE (n_left_from >= 2))
{
@@ -916,56 +835,68 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
goto trace0;
}
- udp0 = ip4_next_header (ip0);
- tcp0 = (tcp_header_t *) udp0;
proto0 = ip_proto_to_nat_proto (ip0->protocol);
- if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
+ if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
{
- next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
- goto trace0;
+ if (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
+ ICMP4_echo_request &&
+ vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
+ ICMP4_echo_reply &&
+ !icmp_type_is_error_message (
+ vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
+ {
+ b0->error = node->errors[NAT_OUT2IN_ED_ERROR_BAD_ICMP_TYPE];
+ next[0] = NAT_NEXT_DROP;
+ goto trace0;
+ }
+ int err = nat_get_icmp_session_lookup_values (
+ b0, ip0, &lookup_saddr, &lookup_sport, &lookup_daddr,
+ &lookup_dport, &lookup_protocol);
+ if (err != 0)
+ {
+ b0->error = node->errors[err];
+ next[0] = NAT_NEXT_DROP;
+ goto trace0;
+ }
}
-
- if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
+ else
{
- next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
- goto trace0;
+ lookup_saddr.as_u32 = ip0->src_address.as_u32;
+ lookup_daddr.as_u32 = ip0->dst_address.as_u32;
+ lookup_protocol = ip0->protocol;
}
- init_ed_k (&kv0, ip0->dst_address,
- vnet_buffer (b0)->ip.reass.l4_dst_port, ip0->src_address,
- vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
- ip0->protocol);
-
- /* there is a stashed index in vnet_buffer2 from handoff node,
- * see if we can use it */
- if (is_multi_worker
- &&
- PREDICT_TRUE (!pool_is_free_index
- (tsm->sessions,
- vnet_buffer2 (b0)->nat.ed_out2in_nat_session_index)))
+ /* there might be a stashed index in vnet_buffer2 from handoff or
+ * classify node, see if it can be used */
+ if (!pool_is_free_index (tsm->sessions,
+ vnet_buffer2 (b0)->nat.cached_session_index))
{
s0 = pool_elt_at_index (tsm->sessions,
- vnet_buffer2 (b0)->
- nat.ed_out2in_nat_session_index);
- if (PREDICT_TRUE
- (s0->out2in.addr.as_u32 == ip0->dst_address.as_u32
- && s0->out2in.port == vnet_buffer (b0)->ip.reass.l4_dst_port
- && s0->nat_proto == ip_proto_to_nat_proto (ip0->protocol)
- && s0->out2in.fib_index == rx_fib_index0
- && s0->ext_host_addr.as_u32 == ip0->src_address.as_u32
- && s0->ext_host_port ==
- vnet_buffer (b0)->ip.reass.l4_src_port))
+ vnet_buffer2 (b0)->nat.cached_session_index);
+ if (PREDICT_TRUE (
+ nat_6t_flow_match (&s0->o2i, b0, lookup_saddr, lookup_sport,
+ lookup_daddr, lookup_dport, lookup_protocol,
+ rx_fib_index0) ||
+ (s0->flags & SNAT_SESSION_FLAG_TWICE_NAT &&
+ nat_6t_flow_match (&s0->i2o, b0, lookup_saddr, lookup_sport,
+ lookup_daddr, lookup_dport,
+ lookup_protocol, rx_fib_index0))))
{
/* yes, this is the droid we're looking for */
+ lookup_skipped = 1;
goto skip_lookup;
}
+ s0 = NULL;
}
- // lookup for session
- if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv0, &value0))
+ init_ed_k (&kv0, lookup_saddr, lookup_sport, lookup_daddr, lookup_dport,
+ rx_fib_index0, lookup_protocol);
+
+ // lookup flow
+ if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
{
- // session does not exist go slow path
+ // flow does not exist go slow path
next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
goto trace0;
}
@@ -973,7 +904,6 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
s0 =
pool_elt_at_index (tsm->sessions,
ed_value_get_session_index (&value0));
-
skip_lookup:
if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
@@ -1014,48 +944,72 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
goto trace0;
}
- old_addr0 = ip0->dst_address.as_u32;
- new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
-
- sum0 = ip0->checksum;
- sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
- dst_address);
- if (PREDICT_FALSE (is_twice_nat_session (s0)))
- sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
- s0->ext_host_nat_addr.as_u32, ip4_header_t,
- src_address);
- ip0->checksum = ip_csum_fold (sum0);
-
- old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
-
- if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
+ if (nat_6t_flow_match (&s0->o2i, b0, lookup_saddr, lookup_sport,
+ lookup_daddr, lookup_dport, lookup_protocol,
+ rx_fib_index0))
+ {
+ f = &s0->o2i;
+ }
+ else if (s0->flags & SNAT_SESSION_FLAG_TWICE_NAT &&
+ nat_6t_flow_match (&s0->i2o, b0, lookup_saddr, lookup_sport,
+ lookup_daddr, lookup_dport, lookup_protocol,
+ rx_fib_index0))
{
- if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
+ f = &s0->i2o;
+ }
+ else
+ {
+ /*
+ * 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 == NAT_PROTOCOL_UDP &&
+ (vnet_buffer (b0)->ip.reass.l4_dst_port ==
+ clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
+ {
+ goto trace0;
+ }
+
+ if (!sm->forwarding_enabled)
{
- new_port0 = udp0->dst_port = s0->in2out.port;
- sum0 = tcp0->checksum;
- sum0 =
- ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
- dst_address);
- sum0 =
- ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
- length);
- if (is_twice_nat_session (s0))
+ b0->error = node->errors[NAT_OUT2IN_ED_ERROR_NO_TRANSLATION];
+ next[0] = NAT_NEXT_DROP;
+ goto trace0;
+ }
+ else
+ {
+ if (nat_6t_flow_match (&s0->i2o, b0, lookup_saddr, lookup_sport,
+ lookup_daddr, lookup_dport,
+ lookup_protocol, rx_fib_index0))
{
- sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
- s0->ext_host_nat_addr.as_u32,
- ip4_header_t, dst_address);
- sum0 =
- ip_csum_update (sum0,
- vnet_buffer (b0)->ip.reass.l4_src_port,
- s0->ext_host_nat_port, ip4_header_t,
- length);
- tcp0->src_port = s0->ext_host_nat_port;
- ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
+ f = &s0->i2o;
+ }
+ else
+ {
+ // FIXME TODO bypass ???
+ // create_bypass_for_fwd (sm, b0, s0, ip0, rx_fib_index0,
+ // thread_index);
+ translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH;
+ nat_free_session_data (sm, s0, thread_index, 0);
+ nat_ed_session_delete (sm, s0, thread_index, 1);
+ next[0] = NAT_NEXT_DROP;
+ goto trace0;
}
- tcp0->checksum = ip_csum_fold (sum0);
}
+ }
+
+ if (NAT_ED_TRNSL_ERR_SUCCESS !=
+ (translation_error = nat_6t_flow_buf_translate (
+ sm, b0, ip0, f, proto0, 0 /* is_output_feature */)))
+ {
+ next[0] = NAT_NEXT_DROP;
+ goto trace0;
+ }
+
+ switch (proto0)
+ {
+ case NAT_PROTOCOL_TCP:
vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.tcp,
thread_index, sw_if_index0, 1);
nat44_set_tcp_session_state_o2i (sm, now, s0,
@@ -1066,46 +1020,20 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
vnet_buffer (b0)->ip.
reass.tcp_seq_number,
thread_index);
- }
- else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
- && udp0->checksum)
- {
- new_port0 = udp0->dst_port = s0->in2out.port;
- sum0 = udp0->checksum;
- sum0 =
- ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
- dst_address);
- sum0 =
- ip_csum_update (sum0, old_port0, new_port0, ip4_header_t, length);
- if (PREDICT_FALSE (is_twice_nat_session (s0)))
- {
- sum0 =
- ip_csum_update (sum0, ip0->src_address.as_u32,
- s0->ext_host_nat_addr.as_u32, ip4_header_t,
- dst_address);
- sum0 =
- ip_csum_update (sum0, vnet_buffer (b0)->ip.reass.l4_src_port,
- s0->ext_host_nat_port, ip4_header_t, length);
- udp0->src_port = s0->ext_host_nat_port;
- ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
- }
- udp0->checksum = ip_csum_fold (sum0);
+ break;
+ case NAT_PROTOCOL_UDP:
vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.udp,
thread_index, sw_if_index0, 1);
- }
- else
- {
- if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
- {
- new_port0 = udp0->dst_port = s0->in2out.port;
- if (PREDICT_FALSE (is_twice_nat_session (s0)))
- {
- udp0->src_port = s0->ext_host_nat_port;
- ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
- }
- }
- vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.udp,
+ break;
+ case NAT_PROTOCOL_ICMP:
+ vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.icmp,
thread_index, sw_if_index0, 1);
+ break;
+ case NAT_PROTOCOL_OTHER:
+ vlib_increment_simple_counter (
+ &sm->counters.fastpath.out2in_ed.other, thread_index, sw_if_index0,
+ 1);
+ break;
}
/* Accounting */
@@ -1124,11 +1052,21 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
t->sw_if_index = sw_if_index0;
t->next_index = next[0];
t->is_slow_path = 0;
+ t->translation_error = translation_error;
+ clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
+ t->lookup_skipped = lookup_skipped;
if (s0)
- t->session_index = s0 - tsm->sessions;
+ {
+ t->session_index = s0 - tsm->sessions;
+ clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
+ clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
+ t->translation_via_i2of = (&s0->i2o == f);
+ }
else
- t->session_index = ~0;
+ {
+ t->session_index = ~0;
+ }
}
if (next[0] == NAT_NEXT_DROP)
@@ -1169,21 +1107,20 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
while (n_left_from > 0)
{
vlib_buffer_t *b0;
- u32 sw_if_index0, rx_fib_index0, proto0, old_addr0, new_addr0;
- u16 old_port0, new_port0;
+ u32 sw_if_index0, rx_fib_index0;
+ nat_protocol_t proto0;
ip4_header_t *ip0;
udp_header_t *udp0;
- tcp_header_t *tcp0;
icmp46_header_t *icmp0;
snat_session_t *s0 = 0;
clib_bihash_kv_16_8_t kv0, value0;
- ip_csum_t sum0;
lb_nat_type_t lb_nat0;
twice_nat_type_t twice_nat0;
u8 identity_nat0;
ip4_address_t sm_addr;
u16 sm_port;
u32 sm_fib_index;
+ nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
b0 = *b;
next[0] = vnet_buffer2 (b0)->nat.arc_next;
@@ -1206,20 +1143,26 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
}
udp0 = ip4_next_header (ip0);
- tcp0 = (tcp_header_t *) udp0;
icmp0 = (icmp46_header_t *) udp0;
proto0 = ip_proto_to_nat_proto (ip0->protocol);
if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
{
- s0 =
- nat44_ed_out2in_unknown_proto (sm, b0, ip0, rx_fib_index0,
- thread_index, now, vm, node);
+ s0 = nat44_ed_out2in_slowpath_unknown_proto (
+ sm, b0, ip0, rx_fib_index0, thread_index, now, vm, node);
if (!sm->forwarding_enabled)
{
if (!s0)
next[0] = NAT_NEXT_DROP;
}
+ if (NAT_NEXT_DROP != next[0] &&
+ NAT_ED_TRNSL_ERR_SUCCESS !=
+ (translation_error = nat_6t_flow_buf_translate (
+ sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
+ {
+ goto trace0;
+ }
+
vlib_increment_simple_counter (&sm->counters.slowpath.
out2in_ed.other, thread_index,
sw_if_index0, 1);
@@ -1231,19 +1174,28 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
next[0] = icmp_out2in_ed_slow_path
(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
next[0], now, thread_index, &s0);
+
+ if (NAT_NEXT_DROP != next[0] && s0 &&
+ NAT_ED_TRNSL_ERR_SUCCESS !=
+ (translation_error = nat_6t_flow_buf_translate (
+ sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
+ {
+ goto trace0;
+ }
+
vlib_increment_simple_counter (&sm->counters.slowpath.
out2in_ed.icmp, thread_index,
sw_if_index0, 1);
goto trace0;
}
- init_ed_k (&kv0, ip0->dst_address,
- vnet_buffer (b0)->ip.reass.l4_dst_port, ip0->src_address,
- vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
+ 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->out2in_ed, &kv0, &value0))
+ if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
{
ASSERT (thread_index == ed_value_get_thread_index (&value0));
s0 =
@@ -1298,18 +1250,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
}
else
{
- if ((sm->num_workers > 1)
- && create_bypass_for_fwd_worker (sm, b0, ip0,
- rx_fib_index0,
- thread_index))
- {
- next[0] = NAT_NEXT_OUT2IN_ED_HANDOFF;
- }
- else
- {
- create_bypass_for_fwd (sm, b0, ip0, rx_fib_index0,
- thread_index);
- }
+ create_bypass_for_fwd (sm, b0, s0, ip0, rx_fib_index0,
+ thread_index);
}
}
goto trace0;
@@ -1345,48 +1287,16 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
}
}
- old_addr0 = ip0->dst_address.as_u32;
- new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
-
- sum0 = ip0->checksum;
- sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
- dst_address);
- if (PREDICT_FALSE (is_twice_nat_session (s0)))
- sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
- s0->ext_host_nat_addr.as_u32, ip4_header_t,
- src_address);
- ip0->checksum = ip_csum_fold (sum0);
-
- old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
+ if (NAT_ED_TRNSL_ERR_SUCCESS !=
+ (translation_error = nat_6t_flow_buf_translate (
+ sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
+ {
+ next[0] = NAT_NEXT_DROP;
+ goto trace0;
+ }
if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
{
- if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
- {
- new_port0 = udp0->dst_port = s0->in2out.port;
- sum0 = tcp0->checksum;
- sum0 =
- ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
- dst_address);
- sum0 =
- ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
- length);
- if (is_twice_nat_session (s0))
- {
- sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
- s0->ext_host_nat_addr.as_u32,
- ip4_header_t, dst_address);
- sum0 =
- ip_csum_update (sum0,
- vnet_buffer (b0)->ip.reass.l4_src_port,
- s0->ext_host_nat_port, ip4_header_t,
- length);
- tcp0->src_port = s0->ext_host_nat_port;
- ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
- }
- tcp0->checksum = ip_csum_fold (sum0);
- }
vlib_increment_simple_counter (&sm->counters.slowpath.out2in_ed.tcp,
thread_index, sw_if_index0, 1);
nat44_set_tcp_session_state_o2i (sm, now, s0,
@@ -1398,42 +1308,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
reass.tcp_seq_number,
thread_index);
}
- else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
- && udp0->checksum)
- {
- new_port0 = udp0->dst_port = s0->in2out.port;
- sum0 = udp0->checksum;
- sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
- dst_address);
- sum0 = ip_csum_update (sum0, old_port0, new_port0, ip4_header_t,
- length);
- if (PREDICT_FALSE (is_twice_nat_session (s0)))
- {
- sum0 = ip_csum_update (sum0, ip0->src_address.as_u32,
- s0->ext_host_nat_addr.as_u32,
- ip4_header_t, dst_address);
- sum0 =
- ip_csum_update (sum0,
- vnet_buffer (b0)->ip.reass.l4_src_port,
- s0->ext_host_nat_port, ip4_header_t, length);
- udp0->src_port = s0->ext_host_nat_port;
- ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
- }
- udp0->checksum = ip_csum_fold (sum0);
- vlib_increment_simple_counter (&sm->counters.slowpath.out2in_ed.udp,
- thread_index, sw_if_index0, 1);
- }
else
{
- if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
- {
- new_port0 = udp0->dst_port = s0->in2out.port;
- if (PREDICT_FALSE (is_twice_nat_session (s0)))
- {
- udp0->src_port = s0->ext_host_nat_port;
- ip0->src_address.as_u32 = s0->ext_host_nat_addr.as_u32;
- }
- }
vlib_increment_simple_counter (&sm->counters.slowpath.out2in_ed.udp,
thread_index, sw_if_index0, 1);
}
@@ -1454,11 +1330,19 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
t->sw_if_index = sw_if_index0;
t->next_index = next[0];
t->is_slow_path = 1;
+ t->translation_error = translation_error;
+ clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
if (s0)
- t->session_index = s0 - tsm->sessions;
+ {
+ t->session_index = s0 - tsm->sessions;
+ clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of));
+ clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if));
+ }
else
- t->session_index = ~0;
+ {
+ t->session_index = ~0;
+ }
}
if (next[0] == NAT_NEXT_DROP)
@@ -1479,88 +1363,6 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
return frame->n_vectors;
}
-static inline uword
-nat_handoff_node_fn_inline (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame, u32 fq_index)
-{
- u32 n_enq, n_left_from, *from;
-
- u16 thread_indices[VLIB_FRAME_SIZE], *ti = thread_indices;
- vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
-
- from = vlib_frame_vector_args (frame);
- n_left_from = frame->n_vectors;
-
- vlib_get_buffers (vm, from, b, n_left_from);
-
- while (n_left_from >= 4)
- {
- if (PREDICT_TRUE (n_left_from >= 8))
- {
- vlib_prefetch_buffer_header (b[4], LOAD);
- vlib_prefetch_buffer_header (b[5], LOAD);
- vlib_prefetch_buffer_header (b[6], LOAD);
- vlib_prefetch_buffer_header (b[7], LOAD);
- CLIB_PREFETCH (&b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH (&b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH (&b[6]->data, CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH (&b[7]->data, CLIB_CACHE_LINE_BYTES, LOAD);
- }
-
- ti[0] = vnet_buffer2 (b[0])->nat.thread_next;
- ti[1] = vnet_buffer2 (b[1])->nat.thread_next;
- ti[2] = vnet_buffer2 (b[2])->nat.thread_next;
- ti[3] = vnet_buffer2 (b[3])->nat.thread_next;
-
- b += 4;
- ti += 4;
- n_left_from -= 4;
- }
-
- while (n_left_from > 0)
- {
- ti[0] = vnet_buffer2 (b[0])->nat.thread_next;
-
- b += 1;
- ti += 1;
- n_left_from -= 1;
- }
-
- if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
- {
- u32 i;
- b = bufs;
- ti = thread_indices;
-
- for (i = 0; i < frame->n_vectors; i++)
- {
- if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
- {
- nat44_ed_out2in_handoff_trace_t *t =
- vlib_add_trace (vm, node, b[0], sizeof (*t));
- t->thread_next = ti[0];
- b += 1;
- ti += 1;
- }
- else
- break;
- }
- }
-
- n_enq = vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
- frame->n_vectors, 1);
-
- if (n_enq < frame->n_vectors)
- {
- vlib_node_increment_counter (vm, node->node_index,
- NAT44_HANDOFF_ERROR_CONGESTION_DROP,
- frame->n_vectors - n_enq);
- }
-
- return frame->n_vectors;
-}
-
VLIB_NODE_FN (nat44_ed_out2in_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
@@ -1609,35 +1411,6 @@ VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
/* *INDENT-ON* */
static u8 *
-format_nat44_ed_out2in_handoff_trace (u8 * s, va_list * args)
-{
- CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
- CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
- nat44_ed_out2in_handoff_trace_t *t =
- va_arg (*args, nat44_ed_out2in_handoff_trace_t *);
- return format (s, "out2in ed handoff thread_next index %d", t->thread_next);
-}
-
-VLIB_NODE_FN (nat44_ed_out2in_handoff_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
-{
- return nat_handoff_node_fn_inline (vm, node, frame,
- snat_main.ed_out2in_node_index);
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (nat44_ed_out2in_handoff_node) = {
- .name = "nat44-ed-out2in-handoff",
- .vector_size = sizeof (u32),
- .sibling_of = "nat-default",
- .format_trace = format_nat44_ed_out2in_handoff_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = 0,
-};
-/* *INDENT-ON* */
-
-static u8 *
format_nat_pre_trace (u8 * s, va_list * args)
{
CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);