#include <nat/nat_inlines.h>
#include <nat/nat_affinity.h>
#include <nat/nat_syslog.h>
+#include <nat/nat_ha.h>
#include <vnet/fib/fib_table.h>
#include <vnet/fib/ip4_fib.h>
/* *INDENT-ON* */
void
-nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
+nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
+ u8 is_ha)
{
snat_session_key_t key;
clib_bihash_kv_8_8_t kv;
if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
nat_log_warn ("in2out_ed key del failed");
- 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->in2out.protocol, is_twice_nat_session (s));
+ if (!is_ha)
+ 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->in2out.protocol, is_twice_nat_session (s));
}
else
{
if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
nat_log_warn ("out2in key del failed");
- nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
- &s->in2out.addr, s->in2out.port,
- &s->out2in.addr, s->out2in.port,
- s->in2out.protocol);
+ if (!is_ha)
+ nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
+ &s->in2out.addr, s->in2out.port,
+ &s->out2in.addr, s->out2in.port,
+ s->in2out.protocol);
}
if (snat_is_unk_proto_session (s))
return;
- /* log NAT event */
- snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
- s->out2in.addr.as_u32,
- s->in2out.protocol,
- s->in2out.port,
- s->out2in.port, s->in2out.fib_index);
+ if (!is_ha)
+ {
+ /* log NAT event */
+ snat_ipfix_logging_nat44_ses_delete (thread_index,
+ s->in2out.addr.as_u32,
+ s->out2in.addr.as_u32,
+ s->in2out.protocol,
+ 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->out2in.protocol, s->out2in.fib_index,
+ thread_index);
+ }
/* Twice NAT address and port for external host */
if (is_twice_nat_session (s))
snat_session_t *
nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
- u32 thread_index)
+ u32 thread_index, f64 now)
{
snat_session_t *s;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
/* Get the session */
s = pool_elt_at_index (tsm->sessions, session_index);
- nat_free_session_data (sm, s, thread_index);
+ nat_free_session_data (sm, s, thread_index, 0);
if (snat_is_session_static (s))
u->nstaticsessions--;
else
pool_elts (tsm->sessions));
}
+ s->ha_last_refreshed = now;
+
return s;
}
{
clib_dlist_addtail (tsm->list_pool,
u->sessions_per_user_list_head_index, oldest_index);
- nat_free_session_data (sm, s, thread_index);
+ nat_free_session_data (sm, s, thread_index, 0);
if (snat_is_session_static (s))
u->nstaticsessions--;
else
nat_log_warn ("max translations per user %U", format_ip4_address,
&u->addr);
snat_ipfix_logging_max_entries_per_user
- (sm->max_translations_per_user, u->addr.as_u32);
+ (thread_index, sm->max_translations_per_user, u->addr.as_u32);
return 0;
}
else
pool_elts (tsm->sessions));
}
+ s->ha_last_refreshed = now;
+
return s;
}
continue;
nat_free_session_data (sm, s,
- tsm - sm->per_thread_data);
+ tsm - sm->per_thread_data, 0);
nat44_delete_session (sm, s, tsm - sm->per_thread_data);
if (!addr_only && !sm->endpoint_dependent)
continue;
nat_free_session_data (sm, s,
- tsm - sm->per_thread_data);
+ tsm - sm->per_thread_data, 0);
nat44_delete_session (sm, s, tsm - sm->per_thread_data);
if (!addr_only && !sm->endpoint_dependent)
(clib_net_to_host_u16 (s->in2out.port) != local->port))
continue;
- nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+ nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
nat44_delete_session (sm, s, tsm - sm->per_thread_data);
}
}
match_local->port))
continue;
- nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+ nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
nat44_delete_session (sm, s, tsm - sm->per_thread_data);
}
}
}));
/* *INDENT-ON* */
+ ASSERT (vec_len (locals) > 1);
+
local = pool_elt_at_index (m->locals, locals[0]);
local->prefix = local->probability;
for (i = 1; i < vec_len (locals); i++)
pool_foreach (ses, tsm->sessions, ({
if (ses->out2in.addr.as_u32 == addr.as_u32)
{
- nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
+ nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
vec_add1 (ses_to_be_removed, ses - tsm->sessions);
}
}));
{
if (is_del)
{
- outside_fib->refcount--;
+ outside_fib->refcount--;
if (!outside_fib->refcount)
vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
}
snat_interface_t *i;
snat_address_t *ap;
snat_static_mapping_t *m;
+ nat_outside_fib_t *outside_fib;
+ u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
+ sw_if_index);
+
if (sm->deterministic ||
(sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
}));
/* *INDENT-ON* */
+ if (!is_inside)
+ {
+ /* *INDENT-OFF* */
+ vec_foreach (outside_fib, sm->outside_fibs)
+ {
+ if (outside_fib->fib_index == fib_index)
+ {
+ if (is_del)
+ {
+ outside_fib->refcount--;
+ if (!outside_fib->refcount)
+ vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
+ }
+ else
+ outside_fib->refcount++;
+ goto feature_set;
+ }
+ }
+ /* *INDENT-ON* */
+ if (!is_del)
+ {
+ vec_add2 (sm->outside_fibs, outside_fib, 1);
+ outside_fib->refcount = 1;
+ outside_fib->fib_index = fib_index;
+ }
+ }
+
+feature_set:
if (is_inside)
{
if (sm->endpoint_dependent)
return 0;
}
+static void
+snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
+ u32 old_fib_index)
+{
+ snat_main_t *sm = &snat_main;
+ nat_outside_fib_t *outside_fib;
+ snat_interface_t *i;
+ u8 is_add = 1;
+
+ if (new_fib_index == old_fib_index)
+ return;
+
+ if (!vec_len (sm->outside_fibs))
+ return;
+
+ pool_foreach (i, sm->interfaces, (
+ {
+ if (i->sw_if_index == sw_if_index)
+ {
+ if (!(nat_interface_is_outside (i)))
+ return;}
+ }
+ ));
+ vec_foreach (outside_fib, sm->outside_fibs)
+ {
+ if (outside_fib->fib_index == old_fib_index)
+ {
+ outside_fib->refcount--;
+ if (!outside_fib->refcount)
+ vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
+ break;
+ }
+ }
+
+ vec_foreach (outside_fib, sm->outside_fibs)
+ {
+ if (outside_fib->fib_index == new_fib_index)
+ {
+ outside_fib->refcount++;
+ is_add = 0;
+ break;
+ }
+ }
+
+ if (is_add)
+ {
+ vec_add2 (sm->outside_fibs, outside_fib, 1);
+ outside_fib->refcount = 1;
+ outside_fib->fib_index = new_fib_index;
+ }
+}
+
+static void
+snat_ip4_table_bind (ip4_main_t * im,
+ uword opaque,
+ u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
+{
+ snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
+}
static void
snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
uword *bitmap = 0;
u32 i;
ip4_add_del_interface_address_callback_t cb4;
- vlib_node_t *error_drop_node;
+ vlib_node_t *node;
sm->vlib_main = vm;
sm->vnet_main = vnet_get_main ();
sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
sm->forwarding_enabled = 0;
sm->log_class = vlib_log_register_class ("nat", 0);
- error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
- sm->error_node_index = error_drop_node->index;
sm->mss_clamping = 0;
+ node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
+ sm->error_node_index = node->index;
+
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
+ sm->in2out_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
+ sm->in2out_output_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
+ sm->in2out_fast_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
+ sm->in2out_slowpath_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
+ sm->in2out_slowpath_output_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-reass");
+ sm->in2out_reass_node_index = node->index;
+
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
+ sm->ed_in2out_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
+ sm->ed_in2out_slowpath_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-reass");
+ sm->ed_in2out_reass_node_index = node->index;
+
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
+ sm->out2in_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
+ sm->out2in_fast_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-reass");
+ sm->out2in_reass_node_index = node->index;
+
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
+ sm->ed_out2in_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
+ sm->ed_out2in_slowpath_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-reass");
+ sm->ed_out2in_reass_node_index = node->index;
+
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
+ sm->det_in2out_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
+ sm->det_out2in_node_index = node->index;
+
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
+ sm->hairpinning_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
+ sm->hairpin_dst_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
+ sm->hairpin_src_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
+ sm->ed_hairpinning_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
+ sm->ed_hairpin_dst_node_index = node->index;
+ node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
+ sm->ed_hairpin_src_node_index = node->index;
+
p = hash_get_mem (tm->thread_registrations_by_name, "workers");
if (p)
{
dslite_init (vm);
- nat66_init ();
+ nat66_init (vm);
+
+ ip4_table_bind_callback_t cbt4 = {
+ .function = snat_ip4_table_bind,
+ };
+ vec_add1 (ip4_main.table_bind_callbacks, cbt4);
/* Init virtual fragmenentation reassembly */
return nat_reass_init (vm);
}
}
+static int
+nat_set_outside_address_and_port (snat_address_t * addresses,
+ u32 thread_index, snat_session_key_t * k)
+{
+ snat_address_t *a = 0;
+ u32 address_index;
+ u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
+
+ for (address_index = 0; address_index < vec_len (addresses);
+ address_index++)
+ {
+ if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
+ continue;
+
+ a = addresses + address_index;
+ switch (k->protocol)
+ {
+#define _(N, j, n, s) \
+ case SNAT_PROTOCOL_##N: \
+ if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \
+ return VNET_API_ERROR_INSTANCE_IN_USE; \
+ clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \
+ a->busy_##n##_ports_per_thread[thread_index]++; \
+ a->busy_##n##_ports++; \
+ return 0;
+ foreach_snat_protocol
+#undef _
+ default:
+ nat_log_info ("unknown protocol");
+ return 1;
+ }
+ }
+
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+}
+
int
snat_static_mapping_match (snat_main_t * sm,
snat_session_key_t match,
}
/* Totally out of translations to use... */
- snat_ipfix_logging_addresses_exhausted (0);
+ snat_ipfix_logging_addresses_exhausted (thread_index, 0);
return 1;
}
exhausted:
/* Totally out of translations to use... */
- snat_ipfix_logging_addresses_exhausted (0);
+ snat_ipfix_logging_addresses_exhausted (thread_index, 0);
return 1;
}
exhausted:
/* Totally out of translations to use... */
- snat_ipfix_logging_addresses_exhausted (0);
+ snat_ipfix_logging_addresses_exhausted (thread_index, 0);
return 1;
}
if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
return vlib_get_thread_index ();
- if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
- {
- nat_reass_ip4_t *reass;
+ nat_reass_ip4_t *reass;
+ reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
+ ip0->fragment_id, ip0->protocol);
- reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
- ip0->fragment_id, ip0->protocol);
+ if (reass && (reass->thread_index != (u32) ~ 0))
+ return reass->thread_index;
- if (reass && (reass->thread_index != (u32) ~ 0))
- return reass->thread_index;
- else
- return vlib_get_thread_index ();
+ if (ip4_is_first_fragment (ip0))
+ {
+ reass =
+ nat_ip4_reass_create (ip0->src_address, ip0->dst_address,
+ ip0->fragment_id, ip0->protocol);
+ if (!reass)
+ goto no_reass;
+
+ if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
+ {
+ m_key.addr = ip0->dst_address;
+ m_key.port = clib_net_to_host_u16 (port);
+ m_key.protocol = proto;
+ m_key.fib_index = rx_fib_index0;
+ kv.key = m_key.as_u64;
+ if (!clib_bihash_search_8_8
+ (&sm->static_mapping_by_external, &kv, &value))
+ {
+ m = pool_elt_at_index (sm->static_mappings, value.value);
+ reass->thread_index = m->workers[0];
+ return reass->thread_index;
+ }
+ }
+ reass->thread_index = sm->first_worker_index;
+ reass->thread_index +=
+ sm->workers[(clib_net_to_host_u16 (port) - 1024) /
+ sm->port_per_thread];
+ return reass->thread_index;
}
+ else
+ return vlib_get_thread_index ();
}
+no_reass:
/* unknown protocol */
if (PREDICT_FALSE (proto == ~0))
{
return next_worker_index;
}
+void
+nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
+ ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port,
+ ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
+ u32 fib_index, u16 flags, u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ snat_user_t *u;
+ snat_session_t *s;
+ clib_bihash_kv_8_8_t kv;
+ f64 now = vlib_time_now (sm->vlib_main);
+ nat_outside_fib_t *outside_fib;
+ fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+ snat_main_per_thread_data_t *tsm;
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = 32,
+ .fp_addr = {
+ .ip4.as_u32 = eh_addr->as_u32,
+ },
+ };
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+
+ if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
+ {
+ if (nat_set_outside_address_and_port
+ (sm->addresses, thread_index, &key))
+ return;
+ }
+
+ u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
+ if (!u)
+ return;
+
+ s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
+ if (!s)
+ return;
+
+ s->last_heard = now;
+ s->flags = flags;
+ s->ext_host_addr.as_u32 = eh_addr->as_u32;
+ s->ext_host_port = eh_port;
+ user_session_increment (sm, u, snat_is_session_static (s));
+ switch (vec_len (sm->outside_fibs))
+ {
+ case 0:
+ key.fib_index = sm->outside_fib_index;
+ break;
+ case 1:
+ key.fib_index = sm->outside_fibs[0].fib_index;
+ break;
+ default:
+ /* *INDENT-OFF* */
+ vec_foreach (outside_fib, sm->outside_fibs)
+ {
+ fei = fib_table_lookup (outside_fib->fib_index, &pfx);
+ if (FIB_NODE_INDEX_INVALID != fei)
+ {
+ if (fib_entry_get_resolving_interface (fei) != ~0)
+ {
+ key.fib_index = outside_fib->fib_index;
+ break;
+ }
+ }
+ }
+ /* *INDENT-ON* */
+ break;
+ }
+ s->out2in = key;
+ kv.key = key.as_u64;
+ kv.value = s - tsm->sessions;
+ if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
+ nat_log_warn ("out2in key add failed");
+
+ key.addr.as_u32 = in_addr->as_u32;
+ key.port = in_port;
+ key.fib_index = fib_index;
+ s->in2out = key;
+ kv.key = key.as_u64;
+ if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
+ nat_log_warn ("in2out key add failed");
+}
+
+void
+nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
+ u32 ti)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ clib_bihash_kv_8_8_t kv, value;
+ u32 thread_index;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ if (sm->num_workers > 1)
+ thread_index =
+ sm->first_worker_index +
+ (sm->workers[(clib_net_to_host_u16 (out_port) -
+ 1024) / sm->port_per_thread]);
+ else
+ thread_index = sm->num_workers;
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+ key.fib_index = fib_index;
+ kv.key = key.as_u64;
+ if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ nat_free_session_data (sm, s, thread_index, 1);
+ nat44_delete_session (sm, s, thread_index);
+}
+
+void
+nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
+ u32 total_pkts, u64 total_bytes, u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ clib_bihash_kv_8_8_t kv, value;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+ key.fib_index = fib_index;
+ kv.key = key.as_u64;
+ if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ s->total_pkts = total_pkts;
+ s->total_bytes = total_bytes;
+}
+
+void
+nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
+ ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port,
+ ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
+ u32 fib_index, u16 flags, u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ snat_user_t *u;
+ snat_session_t *s;
+ clib_bihash_kv_16_8_t kv;
+ f64 now = vlib_time_now (sm->vlib_main);
+ nat_outside_fib_t *outside_fib;
+ fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+ snat_main_per_thread_data_t *tsm;
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = 32,
+ .fp_addr = {
+ .ip4.as_u32 = eh_addr->as_u32,
+ },
+ };
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+
+ if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
+ {
+ if (nat_set_outside_address_and_port
+ (sm->addresses, thread_index, &key))
+ return;
+ }
+
+ key.addr.as_u32 = ehn_addr->as_u32;
+ key.port = ehn_port;
+ if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
+ {
+ if (nat_set_outside_address_and_port
+ (sm->twice_nat_addresses, thread_index, &key))
+ return;
+ }
+
+ u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
+ if (!u)
+ return;
+
+ s = nat_ed_session_alloc (sm, u, thread_index, now);
+ if (!s)
+ return;
+
+ s->last_heard = now;
+ s->flags = flags;
+ s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
+ s->ext_host_nat_port = s->ext_host_port = eh_port;
+ if (is_twice_nat_session (s))
+ {
+ s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
+ s->ext_host_nat_port = ehn_port;
+ }
+ user_session_increment (sm, u, snat_is_session_static (s));
+ switch (vec_len (sm->outside_fibs))
+ {
+ case 0:
+ key.fib_index = sm->outside_fib_index;
+ break;
+ case 1:
+ key.fib_index = sm->outside_fibs[0].fib_index;
+ break;
+ default:
+ /* *INDENT-OFF* */
+ vec_foreach (outside_fib, sm->outside_fibs)
+ {
+ fei = fib_table_lookup (outside_fib->fib_index, &pfx);
+ if (FIB_NODE_INDEX_INVALID != fei)
+ {
+ if (fib_entry_get_resolving_interface (fei) != ~0)
+ {
+ key.fib_index = outside_fib->fib_index;
+ break;
+ }
+ }
+ }
+ /* *INDENT-ON* */
+ break;
+ }
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ s->out2in = key;
+ kv.value = s - tsm->sessions;
+
+ key.addr.as_u32 = in_addr->as_u32;
+ key.port = in_port;
+ key.fib_index = fib_index;
+ s->in2out = key;
+
+ make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
+ snat_proto_to_ip_proto (proto), fib_index, in_port,
+ s->ext_host_nat_port);
+ if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
+ nat_log_warn ("in2out key add failed");
+
+ make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
+ s->out2in.fib_index, out_port, eh_port);
+ if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
+ nat_log_warn ("out2in key add failed");
+}
+
+void
+nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+ u32 fib_index, u32 ti)
+{
+ snat_main_t *sm = &snat_main;
+ nat_ed_ses_key_t key;
+ clib_bihash_kv_16_8_t kv, value;
+ u32 thread_index;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ if (sm->num_workers > 1)
+ thread_index =
+ sm->first_worker_index +
+ (sm->workers[(clib_net_to_host_u16 (out_port) -
+ 1024) / sm->port_per_thread]);
+ else
+ thread_index = sm->num_workers;
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.l_addr.as_u32 = out_addr->as_u32;
+ key.l_port = out_port;
+ key.r_addr.as_u32 = eh_addr->as_u32;
+ key.r_port = eh_port;
+ key.proto = proto;
+ key.fib_index = fib_index;
+ kv.key[0] = key.as_u64[0];
+ kv.key[1] = key.as_u64[1];
+ if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ nat_free_session_data (sm, s, thread_index, 1);
+ nat44_delete_session (sm, s, thread_index);
+}
+
+void
+nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+ u32 fib_index, u32 total_pkts, u64 total_bytes,
+ u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ nat_ed_ses_key_t key;
+ clib_bihash_kv_16_8_t kv, value;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.l_addr.as_u32 = out_addr->as_u32;
+ key.l_port = out_port;
+ key.r_addr.as_u32 = eh_addr->as_u32;
+ key.r_port = eh_port;
+ key.proto = proto;
+ key.fib_index = fib_index;
+ kv.key[0] = key.as_u64[0];
+ kv.key[1] = key.as_u64[1];
+ if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ s->total_pkts = total_pkts;
+ s->total_bytes = total_bytes;
+}
+
static clib_error_t *
snat_config (vlib_main_t * vm, unformat_input_t * input)
{
sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
nat_affinity_init (vm);
+ nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
+ nat_ha_sref_ed_cb);
}
else
{
sm->out2in_node_index = snat_out2in_node.index;
sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
+ nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
}
if (!static_mapping_only ||
(static_mapping_only && static_mapping_connection_tracking))
return VNET_API_ERROR_UNSPECIFIED;
s = pool_elt_at_index (tsm->sessions, value.value);
- nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+ nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
nat44_delete_session (sm, s, tsm - sm->per_thread_data);
return 0;
}
if (pool_is_free_index (tsm->sessions, value.value))
return VNET_API_ERROR_UNSPECIFIED;
s = pool_elt_at_index (tsm->sessions, value.value);
- nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+ nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
nat44_delete_session (sm, s, tsm - sm->per_thread_data);
return 0;
}