};
nat44_is_idle_session_ctx_t ctx;
- nat44_session_try_cleanup (&key->l_addr, rx_fib_index, thread_index, now);
+ u32 cleared = 0;
if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
{
- b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
- nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
- nat_elog_notice ("maximum sessions exceeded");
- return NAT_NEXT_DROP;
+ if (PREDICT_FALSE
+ (!(cleared = nat44_users_cleanup (thread_index, now))))
+ {
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
+ nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
+ nat_elog_notice ("maximum sessions exceeded");
+ return NAT_NEXT_DROP;
+ }
}
key0.addr = key->l_addr;
key1.protocol = key0.protocol = proto;
key0.fib_index = rx_fib_index;
key1.fib_index = sm->outside_fib_index;
+
/* First try to match static mapping by local address and port */
if (snat_static_mapping_match
(sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
sm->port_per_thread,
tsm->snat_thread_index))
{
- nat_elog_notice ("addresses exhausted");
- b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
- return NAT_NEXT_DROP;
+ if (cleared || !nat44_out_of_ports_cleanup (thread_index, now) ||
+ snat_alloc_outside_address_and_port (sm->addresses,
+ rx_fib_index, thread_index,
+ &key1, sm->port_per_thread,
+ tsm->snat_thread_index))
+ {
+ nat_elog_notice ("addresses exhausted");
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
+ return NAT_NEXT_DROP;
+ }
}
}
else
*sessionp = s;
return next;
}
-
is_sm = 1;
}
- if (proto == SNAT_PROTOCOL_TCP)
+ if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP))
{
- if (!tcp_flags_is_init
- (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
+ if (PREDICT_FALSE
+ (!tcp_flags_is_init
+ (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
{
b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
+ if (!is_sm)
+ snat_free_outside_address_and_port (sm->addresses,
+ thread_index, &key1);
return NAT_NEXT_DROP;
}
}
if (!is_sm)
snat_free_outside_address_and_port (sm->addresses,
thread_index, &key1);
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_CANNOT_CREATE_USER];
return NAT_NEXT_DROP;
}
if (!is_sm)
snat_free_outside_address_and_port (sm->addresses,
thread_index, &key1);
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_USER_SESS_EXCEEDED];
return NAT_NEXT_DROP;
}
{
if (ip->protocol == IP_PROTOCOL_TCP)
{
- if (nat44_set_tcp_session_state_i2o (sm, s, b, thread_index))
+ if (nat44_set_tcp_session_state_i2o
+ (sm, now, s, b, thread_index))
return 1;
}
/* Accounting */
thread_index);
if (!u)
{
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_CANNOT_CREATE_USER];
nat_elog_warn ("create NAT user failed");
return 0;
}
s = nat_ed_session_alloc (sm, u, thread_index, now);
if (!s)
{
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_USER_SESS_EXCEEDED];
nat44_delete_user_with_no_session (sm, u, thread_index);
nat_elog_warn ("create NAT session failed");
return 0;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
0, def_slow;
+ u32 tcp_closed_drops = 0;
def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH :
NAT_NEXT_IN2OUT_ED_SLOW_PATH;
next0 = def_slow;
goto trace0;
}
-
s0 = pool_elt_at_index (tsm->sessions, value0.value);
+ if (s0->tcp_close_timestamp)
+ {
+ if (now >= s0->tcp_close_timestamp)
+ {
+ // session is closed, go slow path
+ next0 = def_slow;
+ }
+ else
+ {
+ // session in transitory timeout, drop
+ ++tcp_closed_drops;
+ b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TCP_CLOSED];
+ next0 = NAT_NEXT_DROP;
+ }
+ goto trace0;
+ }
+
+ // drop if session expired
+ u64 sess_timeout_time;
+ sess_timeout_time = s0->last_heard +
+ (f64) nat44_session_get_timeout (sm, s0);
+ if (now >= sess_timeout_time)
+ {
+ // delete session
+ nat_free_session_data (sm, s0, thread_index, 0);
+ nat44_delete_session (sm, s0, thread_index);
+
+ b0->error = node->errors[NAT_IN2OUT_ED_ERROR_SESS_EXPIRED];
+ next0 = NAT_NEXT_DROP;
+ goto trace0;
+ }
+
b0->flags |= VNET_BUFFER_F_IS_NATED;
if (!is_output_feature)
tcp0->checksum = ip_csum_fold (sum0);
}
tcp_packets++;
- if (nat44_set_tcp_session_state_i2o (sm, s0, b0, thread_index))
+ if (nat44_set_tcp_session_state_i2o
+ (sm, now, s0, b0, thread_index))
goto trace0;
}
else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment
vnet_buffer (b0)->ip.reass.l4_src_port,
vnet_buffer (b0)->ip.reass.l4_dst_port);
- if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
+ if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0))
{
+ s0 = pool_elt_at_index (tsm->sessions, value0.value);
+ if (s0->tcp_close_timestamp && now >= s0->tcp_close_timestamp)
+ {
+ nat_free_session_data (sm, s0, thread_index, 0);
+ nat44_delete_session (sm, s0, thread_index);
+ s0 = NULL;
+ }
+ }
+
+ if (!s0)
+ {
if (is_output_feature)
{
if (PREDICT_FALSE
goto trace0;
}
- else
- {
- s0 = pool_elt_at_index (tsm->sessions, value0.value);
- }
-
b0->flags |= VNET_BUFFER_F_IS_NATED;
tcp0->checksum = ip_csum_fold (sum0);
}
tcp_packets++;
- if (nat44_set_tcp_session_state_i2o (sm, s0, b0, thread_index))
+ if (nat44_set_tcp_session_state_i2o
+ (sm, now, s0, b0, thread_index))
goto trace0;
}
else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment