udp_header_t *udp;
snat_session_t *s = 0;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+ f64 now = vlib_time_now (sm->vlib_main);
if (!sm->forwarding_enabled)
return 0;
if (ip->protocol == IP_PROTOCOL_TCP)
{
tcp_header_t *tcp = ip4_next_header(ip);
- if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+ if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
return 1;
}
/* Per-user LRU list maintenance */
clib_dlist_remove (tsm->list_pool, s->per_user_index);
clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
s->per_user_index);
+ /* Accounting */
+ s->last_heard = now;
+ s->total_pkts++;
return 1;
}
else
{
if (ip->protocol == IP_PROTOCOL_TCP)
{
- if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+ if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
return 0;
}
/* Per-user LRU list maintenance */
ip->dst_address.as_u32 = s->ext_host_addr.as_u32;
}
tcp->checksum = ip_csum_fold(sum);
- if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+ if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index))
return s;
}
else
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
- if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
- goto trace00;
}
else
{
ip4_header_t /* cheat */,
length /* changed member */);
tcp1->checksum = ip_csum_fold(sum1);
- if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index))
- goto trace01;
}
else
{
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
- if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
- goto trace0;
}
else
{
src_address /* changed member */);
ip0->checksum = ip_csum_fold (sum0);
- /* Hairpinning */
- nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
- s0->ext_host_port, proto0);
-
if (PREDICT_FALSE (ip4_is_first_fragment (ip0)))
{
if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP))
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
- if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
- goto trace0;
}
else
{
}
}
+ /* Hairpinning */
+ nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port,
+ s0->ext_host_port, proto0);
+
/* Accounting */
s0->last_heard = now;
s0->total_pkts++;
* limitations under the License.
*/
-option version = "2.5.0";
+option version = "2.6.0";
/**
* @file nat.api
@param last_heard - last heard timer
@param total_bytes - count of bytes sent through session
@param total_pkts - count of pakets sent through session
- @param is_closed - 1 if TCP session is closed
+ @param is_twicenat - 1 if session is twice-nat
+ @param ext_host_valid - 1 if external host address and port are valid
+ @param ext_host_address - external host IPv4 address
+ @param ext_host_port - external host port
+ @param ext_host_nat_address - post-NAT external host IPv4 address (valid
+ only if twice-nat session)
+ @param ext_host_nat_port - post-NAT external host port (valid only if
+ twice-nat session)
*/
define nat44_user_session_details {
u32 context;
u64 last_heard;
u64 total_bytes;
u32 total_pkts;
- u8 is_closed;
+ u8 is_twicenat;
+ u8 ext_host_valid;
+ u8 ext_host_address[4];
+ u16 ext_host_port;
+ u8 ext_host_nat_address[4];
+ u16 ext_host_nat_port;
};
/** \brief NAT44 load-balancing address and port pair
@param protocol - IP protocol
@param port - port number
@param vfr_id - VRF ID
+ @param ext_host_valid - 1 if external host address and port are valid
+ @param ext_host_address - external host IPv4 address
+ @param ext_host_port - external host port
*/
autoreply define nat44_del_session {
u32 client_index;
u8 protocol;
u16 port;
u32 vrf_id;
+ u8 ext_host_valid;
+ u8 ext_host_address[4];
+ u16 ext_host_port;
};
/** \brief Enable/disable forwarding for NAT44
ed_key.fib_index = 0;
ed_kv.key[0] = ed_key.as_u64[0];
ed_kv.key[1] = ed_key.as_u64[1];
- if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) &&
- s->state != SNAT_SESSION_TCP_CLOSED)
+ if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
clib_warning ("in2out_ed key del failed");
return;
}
}
ed_kv.key[0] = ed_key.as_u64[0];
ed_kv.key[1] = ed_key.as_u64[1];
- if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0) &&
- s->state != SNAT_SESSION_TCP_CLOSED)
+ if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
clib_warning ("out2in_ed key del failed");
ed_key.l_addr = s->in2out.addr;
}
ed_kv.key[0] = ed_key.as_u64[0];
ed_kv.key[1] = ed_key.as_u64[1];
- if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) &&
- s->state != SNAT_SESSION_TCP_CLOSED)
+ if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
clib_warning ("in2out_ed key del failed");
}
s->in2out.fib_index);
/* Twice NAT address and port for external host */
- if (is_twice_nat_session (s) && s->state != SNAT_SESSION_TCP_CLOSED)
+ if (is_twice_nat_session (s))
{
for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
{
/* Session lookup tables */
kv.key = s->in2out.as_u64;
- if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0) &&
- s->state != SNAT_SESSION_TCP_CLOSED)
+ if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
clib_warning ("in2out key del failed");
kv.key = s->out2in.as_u64;
- if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0) &&
- s->state != SNAT_SESSION_TCP_CLOSED)
+ if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
clib_warning ("out2in key del failed");
if (snat_is_session_static (s))
return;
- if (s->outside_address_index != ~0 && s->state != SNAT_SESSION_TCP_CLOSED)
+ if (s->outside_address_index != ~0)
snat_free_outside_address_and_port (sm->addresses, thread_index,
&s->out2in, s->outside_address_index);
}
clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
if (twice_nat || out2in_only)
{
- m_key.port = clib_host_to_net_u16 (l_port);
+ m_key.port = clib_host_to_net_u16 (m->local_port);
kv.key = m_key.as_u64;
kv.value = ~0ULL;
if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
if (snat_is_session_static (s))
continue;
- if (!addr_only && (clib_net_to_host_u16 (s->out2in.port) != m->local_port))
+ if (!addr_only && (clib_net_to_host_u16 (s->in2out.port) != m->local_port))
continue;
nat_free_session_data (sm, s, tsm - sm->per_thread_data);
kv.key = m_key.as_u64;
kv.value = ~0ULL;
if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
- clib_warning ("in2out key del failed");
+ clib_warning ("out2in key del failed");
}
/* Delete session(s) for static mapping if exist */
if (is_lb_session (s))
continue;
+ if (!snat_is_session_static (s))
+ continue;
+
nat_free_session_data (sm, s, tsm - sm->per_thread_data);
clib_dlist_remove (tsm->list_pool, s->per_user_index);
pool_put_index (tsm->list_pool, s->per_user_index);
if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
{
u = pool_elt_at_index (tsm->users, value.value);
- u->nsessions--;
+ if (snat_is_session_static (ses))
+ u->nstaticsessions--;
+ else
+ u->nsessions--;
}
}
}));
s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
}
- if (is_twice_nat_session (sess))
+ if (is_ed_session (sess) || is_fwd_bypass_session (sess))
{
- s = format (s, " external host o2i %U:%d i2o %U:%d\n",
- format_ip4_address, &sess->ext_host_addr,
- clib_net_to_host_u16 (sess->ext_host_port),
- format_ip4_address, &sess->ext_host_nat_addr,
- clib_net_to_host_u16 (sess->ext_host_nat_port));
- }
- else
- {
- if (sess->ext_host_addr.as_u32)
- s = format (s, " external host %U:%u\n",
+ if (is_twice_nat_session (sess))
+ {
+ s = format (s, " external host o2i %U:%d i2o %U:%d\n",
format_ip4_address, &sess->ext_host_addr,
- clib_net_to_host_u16 (sess->ext_host_port));
+ clib_net_to_host_u16 (sess->ext_host_port),
+ format_ip4_address, &sess->ext_host_nat_addr,
+ clib_net_to_host_u16 (sess->ext_host_nat_port));
+ }
+ else
+ {
+ if (sess->ext_host_addr.as_u32)
+ s = format (s, " external host %U:%u\n",
+ format_ip4_address, &sess->ext_host_addr,
+ clib_net_to_host_u16 (sess->ext_host_port));
+ }
}
s = format (s, " last heard %.2f\n", sess->last_heard);
s = format (s, " total pkts %d, total bytes %lld\n",
sess->total_pkts, sess->total_bytes);
- if (sess->in2out.protocol == SNAT_PROTOCOL_TCP)
- {
- s = format (s, " state %s\n",
- sess->state == SNAT_SESSION_TCP_CLOSED ? "closed" : "open");
- }
if (snat_is_session_static (sess))
s = format (s, " static translation\n");
else
s = format (s, " dynamic translation\n");
+ if (is_fwd_bypass_session (sess))
+ s = format (s, " forwarding-bypass\n");
if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
s = format (s, " load-balancing\n");
if (is_twice_nat_session (sess))
t = is_in ? &tsm->in2out : &tsm->out2in;
if (!clib_bihash_search_8_8 (t, &kv, &value))
{
+ if (pool_is_free_index (tsm->sessions, value.value))
+ return VNET_API_ERROR_UNSPECIFIED;
+
s = pool_elt_at_index (tsm->sessions, value.value);
kv.key = s->in2out.as_u64;
clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
{
u = pool_elt_at_index (tsm->users, value.value);
- u->nsessions--;
+ if (snat_is_session_static (s))
+ u->nstaticsessions--;
+ else
+ u->nsessions--;
}
clib_dlist_remove (tsm->list_pool, s->per_user_index);
+ pool_put_index (tsm->list_pool, s->per_user_index);
pool_put (tsm->sessions, s);
return 0;
}
return VNET_API_ERROR_NO_SUCH_ENTRY;
}
+int
+nat44_del_ed_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)
+{
+ ip4_header_t ip;
+ clib_bihash_16_8_t *t;
+ nat_ed_ses_key_t key;
+ clib_bihash_kv_16_8_t kv, value;
+ u32 thread_index;
+ u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+ snat_session_t *s;
+
+ ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
+ if (sm->num_workers > 1)
+ thread_index = sm->worker_in2out_cb (&ip, fib_index);
+ else
+ thread_index = sm->num_workers;
+
+ t = is_in ? &sm->in2out_ed : &sm->out2in_ed;
+ key.l_addr.as_u32 = addr->as_u32;
+ key.r_addr.as_u32 = eh_addr->as_u32;
+ key.l_port = clib_host_to_net_u16 (port);
+ key.r_port = clib_host_to_net_u16 (eh_port);
+ key.proto = proto;
+ key.fib_index = clib_host_to_net_u32 (fib_index);
+ kv.key[0] = key.as_u64[0];
+ kv.key[1] = key.as_u64[1];
+ if (clib_bihash_search_16_8 (t, &kv, &value))
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ if (pool_is_free_index (sm->per_thread_data[thread_index].sessions, value.value))
+ return VNET_API_ERROR_UNSPECIFIED;
+ s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value);
+ nat_free_session_data (sm, s, thread_index);
+ nat44_delete_session (sm, s, thread_index);
+ return 0;
+}
+
void
nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
{
#undef _
} snat_session_state_t;
+#define NAT44_SES_I2O_FIN 1
+#define NAT44_SES_O2I_FIN 2
+#define NAT44_SES_I2O_FIN_ACK 4
+#define NAT44_SES_O2I_FIN_ACK 8
+
+#define nat44_is_ses_closed(s) (s->state == 0xf)
#define SNAT_SESSION_FLAG_STATIC_MAPPING 1
#define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2
/* TCP session state */
u8 state;
+ u32 i2o_fin_seq;
+ u32 o2i_fin_seq;
}) snat_session_t;
u8 *tag);
int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
snat_protocol_t proto, u32 vrf_id, int is_in);
+int nat44_del_ed_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 nat_free_session_data (snat_main_t * sm, snat_session_t * s,
u32 thread_index);
snat_user_t * nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr,
pool_put (tsm->sessions, ses);
}
-/** \brief Set TCP session stet.
+/** \brief Set TCP session state.
@return 1 if session was closed, otherwise 0
*/
always_inline int
-nat44_set_tcp_session_state(snat_main_t * sm, snat_session_t * ses,
- tcp_header_t * tcp, u32 thread_index)
+nat44_set_tcp_session_state_i2o(snat_main_t * sm, snat_session_t * ses,
+ tcp_header_t * tcp, u32 thread_index)
{
- if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_UNKNOWN)
- ses->state = SNAT_SESSION_TCP_FIN_WAIT;
- else if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_TCP_FIN_WAIT)
- ses->state = SNAT_SESSION_TCP_CLOSING;
- else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_FIN_WAIT)
- ses->state = SNAT_SESSION_TCP_CLOSE_WAIT;
- else if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_TCP_CLOSE_WAIT)
- ses->state = SNAT_SESSION_TCP_LAST_ACK;
- else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_CLOSING)
- ses->state = SNAT_SESSION_TCP_LAST_ACK;
- else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_LAST_ACK)
+ if (tcp->flags & TCP_FLAG_FIN)
+ {
+ ses->i2o_fin_seq = clib_net_to_host_u32 (tcp->seq_number);
+ ses->state |= NAT44_SES_I2O_FIN;
+ }
+ if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN))
+ {
+ if (clib_net_to_host_u32 (tcp->ack_number) > ses->o2i_fin_seq)
+ ses->state |= NAT44_SES_O2I_FIN_ACK;
+ }
+ if (nat44_is_ses_closed (ses))
{
nat_free_session_data (sm, ses, thread_index);
- ses->state = SNAT_SESSION_TCP_CLOSED;
nat44_delete_session (sm, ses, thread_index);
return 1;
}
+ return 0;
+}
+always_inline int
+nat44_set_tcp_session_state_o2i(snat_main_t * sm, snat_session_t * ses,
+ tcp_header_t * tcp, u32 thread_index)
+{
+ if (tcp->flags & TCP_FLAG_FIN)
+ {
+ ses->o2i_fin_seq = clib_net_to_host_u32 (tcp->seq_number);
+ ses->state |= NAT44_SES_O2I_FIN;
+ }
+ if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN))
+ {
+ if (clib_net_to_host_u32 (tcp->ack_number) > ses->i2o_fin_seq)
+ ses->state |= NAT44_SES_I2O_FIN_ACK;
+ }
+ if (nat44_is_ses_closed (ses))
+ {
+ nat_free_session_data (sm, ses, thread_index);
+ nat44_delete_session (sm, ses, thread_index);
+ return 1;
+ }
return 0;
}
{
snat_main_t *sm = &snat_main;
unformat_input_t _line_input, *line_input = &_line_input;
- int is_in = 0;
+ int is_in = 0, is_ed = 0;
clib_error_t *error = 0;
- ip4_address_t addr;
- u32 port = 0, vrf_id = sm->outside_vrf_id;
+ ip4_address_t addr, eh_addr;
+ u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
snat_protocol_t proto;
int rv;
is_in = 1;
vrf_id = sm->inside_vrf_id;
}
+ else if (unformat (line_input, "out"))
+ {
+ is_in = 0;
+ vrf_id = sm->outside_vrf_id;
+ }
else if (unformat (line_input, "vrf %u", &vrf_id))
;
+ else
+ if (unformat
+ (line_input, "external-host %U:%u", unformat_ip4_address,
+ &eh_addr, &eh_port))
+ is_ed = 1;
else
{
error = clib_error_return (0, "unknown input '%U'",
}
}
- rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in);
+ if (is_ed)
+ rv =
+ nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port,
+ snat_proto_to_ip_proto (proto), vrf_id, is_in);
+ else
+ rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in);
switch (rv)
{
?*/
VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
.path = "nat44 del session",
- .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
+ .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
.function = nat44_del_session_command_fn,
};
{
vl_api_nat44_user_details_t *rmp;
snat_main_t *sm = &snat_main;
- fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4);
+ ip4_main_t *im = &ip4_main;
rmp = vl_msg_api_alloc (sizeof (*rmp));
memset (rmp, 0, sizeof (*rmp));
rmp->_vl_msg_id = ntohs (VL_API_NAT44_USER_DETAILS + sm->msg_id_base);
- rmp->vrf_id = ntohl (fib->ft_table_id);
+ if (!pool_is_free_index (im->fibs, u->fib_index))
+ {
+ fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4);
+ rmp->vrf_id = ntohl (fib->ft_table_id);
+ }
clib_memcpy (rmp->ip_address, &(u->addr), 4);
rmp->nsessions = ntohl (u->nsessions);
ntohs (VL_API_NAT44_USER_SESSION_DETAILS + sm->msg_id_base);
clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4);
clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4);
- rmp->is_static = s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING ? 1 : 0;
+ rmp->is_static = snat_is_session_static (s) ? 1 : 0;
+ rmp->is_twicenat = is_twice_nat_session (s) ? 1 : 0;
+ rmp->ext_host_valid = is_ed_session (s)
+ || is_fwd_bypass_session (s) ? 1 : 0;
rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard);
rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes);
rmp->total_pkts = ntohl (s->total_pkts);
rmp->inside_port = s->in2out.port;
rmp->protocol = ntohs (snat_proto_to_ip_proto (s->in2out.protocol));
}
- if (s->in2out.protocol == SNAT_PROTOCOL_TCP)
- rmp->is_closed = s->state == SNAT_SESSION_TCP_CLOSED ? 1 : 0;
+ if (is_ed_session (s) || is_fwd_bypass_session (s))
+ {
+ clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4);
+ rmp->ext_host_port = s->ext_host_port;
+ if (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);
}
{
snat_main_t *sm = &snat_main;
vl_api_nat44_del_session_reply_t *rmp;
- ip4_address_t addr;
- u16 port;
+ ip4_address_t addr, eh_addr;
+ u16 port, eh_port;
u32 vrf_id;
int rv = 0;
snat_protocol_t proto;
port = clib_net_to_host_u16 (mp->port);
vrf_id = clib_net_to_host_u32 (mp->vrf_id);
proto = ip_proto_to_snat_proto (mp->protocol);
+ memcpy (&eh_addr.as_u8, mp->ext_host_address, 4);
+ eh_port = clib_net_to_host_u16 (mp->ext_host_port);
- rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in);
+ if (mp->ext_host_valid)
+ rv =
+ nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol,
+ vrf_id, mp->is_in);
+ else
+ rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in);
send_reply:
REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY);
format_ip4_address, mp->address,
clib_net_to_host_u16 (mp->port),
mp->protocol, clib_net_to_host_u32 (mp->vrf_id), mp->is_in);
+ if (mp->ext_host_valid)
+ s = format (s, "ext_host_address %U ext_host_port %d",
+ format_ip4_address, mp->ext_host_address,
+ clib_net_to_host_u16 (mp->ext_host_port));
FINISH;
}
snat_main_t *sm = &snat_main;
vl_api_nat44_forwarding_enable_disable_reply_t *rmp;
int rv = 0;
+ u32 *ses_to_be_removed = 0, *ses_index;
+ snat_main_per_thread_data_t *tsm;
+ snat_session_t *s;
sm->forwarding_enabled = mp->enable != 0;
+ if (mp->enable == 0)
+ {
+ /* *INDENT-OFF* */
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ pool_foreach (s, tsm->sessions,
+ ({
+ if (is_fwd_bypass_session(s))
+ {
+ vec_add1 (ses_to_be_removed, s - tsm->sessions);
+ }
+ }));
+ vec_foreach (ses_index, ses_to_be_removed)
+ {
+ s = pool_elt_at_index(tsm->sessions, ses_index[0]);
+ nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+ nat44_delete_session (sm, s, tsm - sm->per_thread_data);
+ }
+ vec_free (ses_to_be_removed);
+ }
+ /* *INDENT-ON* */
+ }
+
REPLY_MACRO (VL_API_NAT44_FORWARDING_ENABLE_DISABLE_REPLY);
}
snat_user_t *u;
snat_session_t *s = 0;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+ f64 now = vlib_time_now (sm->vlib_main);
if (ip->protocol == IP_PROTOCOL_ICMP)
{
if (ip->protocol == IP_PROTOCOL_TCP)
{
tcp_header_t *tcp = ip4_next_header(ip);
- if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+ if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
return;
}
/* Per-user LRU list maintenance */
clib_dlist_remove (tsm->list_pool, s->per_user_index);
clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index,
s->per_user_index);
+ /* Accounting */
+ s->last_heard = now;
+ s->total_pkts++;
}
/**
ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32;
}
tcp->checksum = ip_csum_fold(sum);
- if (nat44_set_tcp_session_state (sm, s, tcp, thread_index))
+ if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index))
return s;
}
else
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
- if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
- goto trace0;
}
else
{
ip4_header_t /* cheat */,
length /* changed member */);
tcp1->checksum = ip_csum_fold(sum1);
- if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index))
- goto trace1;
}
else
{
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
- if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
- goto trace00;
}
else
{
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
- if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index))
- goto trace0;
}
else
{
finally:
self.pg0.remote_hosts[0] = host0
+ user = self.pg0.remote_hosts[1]
+ sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
+ self.assertEqual(len(sessions), 3)
+ self.assertTrue(sessions[0].ext_host_valid)
+ self.vapi.nat44_del_session(
+ sessions[0].inside_ip_address,
+ sessions[0].inside_port,
+ sessions[0].protocol,
+ ext_host_address=sessions[0].ext_host_address,
+ ext_host_port=sessions[0].ext_host_port)
+ sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0)
+ self.assertEqual(len(sessions), 2)
+
finally:
self.vapi.nat44_forwarding_enable_disable(0)
self.vapi.nat44_add_del_static_mapping(local_ip=real_ip,
self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
+ sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+ self.assertEqual(len(sessions), 1)
+ self.assertTrue(sessions[0].ext_host_valid)
+ self.vapi.nat44_del_session(
+ sessions[0].inside_ip_address,
+ sessions[0].inside_port,
+ sessions[0].protocol,
+ ext_host_address=sessions[0].ext_host_address,
+ ext_host_port=sessions[0].ext_host_port)
+ sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+ self.assertEqual(len(sessions), 0)
+
@unittest.skipUnless(running_extended_tests(), "part of extended tests")
def test_static_lb_multi_clients(self):
""" NAT44 local service load balancing - multiple clients"""
self.assertTrue(session.protocol in
[IP_PROTOS.tcp, IP_PROTOS.udp,
IP_PROTOS.icmp])
+ self.assertFalse(session.ext_host_valid)
# pg4 session dump
sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4n, 10)
self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
+ if eh_translate:
+ sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+ self.assertEqual(len(sessions), 1)
+ self.assertTrue(sessions[0].ext_host_valid)
+ self.assertTrue(sessions[0].is_twicenat)
+ self.vapi.nat44_del_session(
+ sessions[0].inside_ip_address,
+ sessions[0].inside_port,
+ sessions[0].protocol,
+ ext_host_address=sessions[0].ext_host_nat_address,
+ ext_host_port=sessions[0].ext_host_nat_port)
+ sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0)
+ self.assertEqual(len(sessions), 0)
+
def test_twice_nat(self):
""" Twice NAT44 """
self.twice_nat_common()
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
- flags="FA"))
+ flags="FA", seq=100, ack=300))
self.pg0.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
- flags="A"))
+ flags="A", seq=300, ack=101))
pkts.append(p)
# FIN packet out -> in
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
- flags="FA"))
+ flags="FA", seq=300, ack=101))
pkts.append(p)
self.pg1.add_stream(pkts)
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
- flags="A"))
+ flags="A", seq=101, ack=301))
self.pg0.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
- flags="FA"))
+ flags="FA", seq=100, ack=300))
self.pg1.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
self.pg0.get_capture(1)
- pkts = []
-
- # ACK packet in -> out
- p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
- IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
- TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
- flags="A"))
- pkts.append(p)
-
- # ACK packet in -> out
+ # FIN+ACK packet in -> out
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
- flags="FA"))
- pkts.append(p)
+ flags="FA", seq=300, ack=101))
- self.pg0.add_stream(pkts)
+ self.pg0.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
- self.pg1.get_capture(2)
+ self.pg1.get_capture(1)
# ACK packet out -> in
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
- flags="A"))
+ flags="A", seq=101, ack=301))
self.pg1.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
- flags="FA"))
+ flags="FA", seq=100, ack=300))
self.pg0.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
- flags="FA"))
+ flags="FA", seq=300, ack=100))
self.pg1.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
- flags="A"))
+ flags="A", seq=101, ack=301))
self.pg0.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
- flags="A"))
+ flags="A", seq=301, ack=101))
self.pg1.add_stream(p)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
port,
protocol,
vrf_id=0,
- is_in=1):
+ is_in=1,
+ ext_host_address=None,
+ ext_host_port=0):
"""Delete NAT44 session
:param addr: IPv4 address
:param protocol: IP protocol number
:param vrf_id: VRF ID
:param is_in: 1 if inside network addres and port pari, 0 if outside
- """
- return self.api(
- self.papi.nat44_del_session,
- {'address': addr,
- 'port': port,
- 'protocol': protocol,
- 'vrf_id': vrf_id,
- 'is_in': is_in})
+ :param ext_host_address: external host IPv4 address
+ :param ext_host_port: external host port
+ """
+ if ext_host_address is None:
+ return self.api(
+ self.papi.nat44_del_session,
+ {'address': addr,
+ 'port': port,
+ 'protocol': protocol,
+ 'vrf_id': vrf_id,
+ 'is_in': is_in})
+ else:
+ return self.api(
+ self.papi.nat44_del_session,
+ {'address': addr,
+ 'port': port,
+ 'protocol': protocol,
+ 'vrf_id': vrf_id,
+ 'is_in': is_in,
+ 'ext_host_valid': 1,
+ 'ext_host_address': ext_host_address,
+ 'ext_host_port': ext_host_port})
def nat44_forwarding_enable_disable(
self,