snat_main_per_thread_data_t *tsm =
vec_elt_at_index (sm->per_thread_data, thread_index);
+ if (is_ed_session (s))
+ {
+ per_vrf_sessions_unregister_session (s, thread_index);
+ }
+
if (is_fwd_bypass_session (s))
{
if (snat_is_unk_proto_session (s))
s->nat_proto);
}
-int
-nat44_set_session_limit (u32 session_limit, u32 vrf_id)
-{
- snat_main_t *sm = &snat_main;
- u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
- u32 len = vec_len (sm->max_translations_per_fib);
-
- if (len <= fib_index)
- {
- vec_validate (sm->max_translations_per_fib, fib_index + 1);
-
- for (; len < vec_len (sm->max_translations_per_fib); len++)
- sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
- }
-
- sm->max_translations_per_fib[fib_index] = session_limit;
- return 0;
-}
-
void
nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
u32 thread_index, u8 is_ha)
nat_protocol_t proto,
int addr_only, int is_add, u8 * tag,
int twice_nat, int out2in_only,
- int identity_nat)
+ int identity_nat,
+ ip4_address_t pool_addr, int exact)
{
snat_static_map_resolve_t *rp;
rp->out2in_only = out2in_only;
rp->identity_nat = identity_nat;
rp->tag = vec_dup (tag);
+ rp->pool_addr = pool_addr;
+ rp->exact = exact;
}
static u32
u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
u32 sw_if_index, nat_protocol_t proto, int is_add,
twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
- u8 identity_nat)
+ u8 identity_nat, ip4_address_t pool_addr, int exact)
{
snat_main_t *sm = &snat_main;
snat_static_mapping_t *m;
snat_add_static_mapping_when_resolved
(sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
- addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
+ addr_only, is_add, tag, twice_nat, out2in_only,
+ identity_nat, pool_addr, exact);
/* DHCP resolution required? */
if (first_int_addr == 0)
m->local_addr = l_addr;
m->external_addr = e_addr;
m->twice_nat = twice_nat;
+
+ if (twice_nat == TWICE_NAT && exact)
+ {
+ m->flags |= NAT_STATIC_MAPPING_FLAG_EXACT_ADDRESS;
+ m->pool_addr = pool_addr;
+ }
+
if (out2in_only)
m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
if (addr_only)
if (delete_sm)
{
+ ip4_address_t pool_addr = { 0 };
/* *INDENT-OFF* */
pool_foreach (m, sm->static_mappings,
({
if (m->external_addr.as_u32 == addr.as_u32)
(void) snat_add_static_mapping (m->local_addr, m->external_addr,
m->local_port, m->external_port,
- m->vrf_id, is_addr_only_static_mapping(m), ~0,
- m->proto, 0, m->twice_nat,
- is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
+ m->vrf_id,
+ is_addr_only_static_mapping(m), ~0,
+ m->proto, 0 /* is_add */,
+ m->twice_nat,
+ is_out2in_only_static_mapping(m),
+ m->tag,
+ is_identity_static_mapping(m),
+ pool_addr, 0);
}));
/* *INDENT-ON* */
}
vlib_zero_simple_counter (&sm->counters.hairpinning, sw_if_index);
}
+void
+expire_per_vrf_sessions (u32 fib_index)
+{
+ per_vrf_sessions_t *per_vrf_sessions;
+ snat_main_per_thread_data_t *tsm;
+ snat_main_t *sm = &snat_main;
+
+ /* *INDENT-OFF* */
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
+ {
+ if ((per_vrf_sessions->rx_fib_index == fib_index) ||
+ (per_vrf_sessions->tx_fib_index == fib_index))
+ {
+ per_vrf_sessions->expired = 1;
+ }
+ }
+ }
+ /* *INDENT-ON* */
+}
+
+void
+update_per_vrf_sessions_vec (u32 fib_index, int is_del)
+{
+ snat_main_t *sm = &snat_main;
+ nat_fib_t *fib;
+
+ // we don't care if it is outside/inside fib
+ // we just care about their ref_count
+ // if it reaches 0 sessions should expire
+ // because the fib isn't valid for NAT anymore
+
+ vec_foreach (fib, sm->fibs)
+ {
+ if (fib->fib_index == fib_index)
+ {
+ if (is_del)
+ {
+ fib->ref_count--;
+ if (!fib->ref_count)
+ {
+ vec_del1 (sm->fibs, fib - sm->fibs);
+ expire_per_vrf_sessions (fib_index);
+ }
+ return;
+ }
+ else
+ fib->ref_count++;
+ }
+ }
+ if (!is_del)
+ {
+ vec_add2 (sm->fibs, fib, 1);
+ fib->ref_count = 1;
+ fib->fib_index = fib_index;
+ }
+}
+
int
snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
{
sm->fq_out2in_index =
vlib_frame_queue_main_init (sm->out2in_node_index, NAT_FQ_NELTS);
+ if (sm->endpoint_dependent)
+ update_per_vrf_sessions_vec (fib_index, is_del);
+
if (!is_inside)
{
/* *INDENT-OFF* */
outside_fib->fib_index = fib_index;
}
}
+
feature_set:
/* *INDENT-OFF* */
pool_foreach (i, sm->interfaces,
u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
sw_if_index);
-
if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
return VNET_API_ERROR_UNSUPPORTED;
}));
/* *INDENT-ON* */
+ if (sm->endpoint_dependent)
+ update_per_vrf_sessions_vec (fib_index, is_del);
+
if (!is_inside)
{
/* *INDENT-OFF* */
ASSERT (fib_index == fib_index2);
}
+static clib_error_t *
+nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add)
+{
+ snat_main_t *sm = &snat_main;
+ u32 fib_index;
+
+ if (sm->endpoint_dependent)
+ {
+ // TODO: consider removing all NAT interfaces
+
+ if (!is_add)
+ {
+ fib_index = ip4_fib_index_from_table_id (table_id);
+ if (fib_index != ~0)
+ expire_per_vrf_sessions (fib_index);
+ }
+ }
+ return 0;
+}
+
+VNET_IP_TABLE_ADD_DEL_FUNCTION (nat_ip_table_add_del);
+
+
static clib_error_t *
snat_init (vlib_main_t * vm)
{
u8 * is_addr_only,
twice_nat_type_t * twice_nat,
lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
- u8 * is_identity_nat)
+ u8 * is_identity_nat, snat_static_mapping_t ** out)
{
clib_bihash_kv_8_8_t kv, value;
+ clib_bihash_8_8_t *mapping_hash;
snat_static_mapping_t *m;
- clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
u32 rand, lo = 0, hi, mid, *tmp = 0, i;
- u8 backend_index;
nat44_lb_addr_port_t *local;
+ u8 backend_index;
- if (by_external)
+ if (!by_external)
{
- mapping_hash = &sm->static_mapping_by_external;
- init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
+ mapping_hash = &sm->static_mapping_by_local;
+ init_nat_k (&kv, match_addr, match_port, match_fib_index,
+ match_protocol);
if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
{
/* Try address only mapping */
- init_nat_k (&kv, match_addr, 0, 0, 0);
+ init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
return 1;
}
-
}
else
{
- init_nat_k (&kv, match_addr, match_port, match_fib_index,
- match_protocol);
+ mapping_hash = &sm->static_mapping_by_external;
+ init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
{
/* Try address only mapping */
- init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
+ init_nat_k (&kv, match_addr, 0, 0, 0);
if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
return 1;
}
-
}
m = pool_elt_at_index (sm->static_mappings, value.value);
if (PREDICT_FALSE (is_identity_nat != 0))
*is_identity_nat = is_identity_static_mapping (m);
+ if (out != 0)
+ *out = m;
+
return 0;
}
return n_buckets * (8 + kv_size * 4);
}
+u32
+nat44_get_max_session_limit ()
+{
+ snat_main_t *sm = &snat_main;
+ u32 max_limit = 0, len = 0;
+
+ for (; len < vec_len (sm->max_translations_per_fib); len++)
+ {
+ if (max_limit < sm->max_translations_per_fib[len])
+ max_limit = sm->max_translations_per_fib[len];
+ }
+ return max_limit;
+}
+
+int
+nat44_set_session_limit (u32 session_limit, u32 vrf_id)
+{
+ snat_main_t *sm = &snat_main;
+ u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+ u32 len = vec_len (sm->max_translations_per_fib);
+
+ if (len <= fib_index)
+ {
+ vec_validate (sm->max_translations_per_fib, fib_index + 1);
+
+ for (; len < vec_len (sm->max_translations_per_fib); len++)
+ sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
+ }
+
+ sm->max_translations_per_fib[fib_index] = session_limit;
+ return 0;
+}
+
+int
+nat44_update_session_limit (u32 session_limit, u32 vrf_id)
+{
+ snat_main_t *sm = &snat_main;
+
+ if (nat44_set_session_limit (session_limit, vrf_id))
+ return 1;
+ sm->max_translations_per_thread = nat44_get_max_session_limit ();
+
+ sm->translation_buckets =
+ nat_calc_bihash_buckets (sm->max_translations_per_thread);
+
+ if (!sm->translation_memory_size_set)
+ {
+ sm->translation_memory_size =
+ nat_calc_bihash_memory (sm->translation_buckets,
+ sizeof (clib_bihash_16_8_t));
+ }
+
+ nat44_sessions_clear ();
+ return 0;
+}
+
void
nat44_db_init (snat_main_per_thread_data_t * tsm)
{
sm->translation_memory_size);
clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
format_ed_session_kvp);
+
}
else
{
if (sm->endpoint_dependent)
{
clib_bihash_free_16_8 (&tsm->in2out_ed);
+ vec_free (tsm->per_vrf_sessions_vec);
}
else
{
// translation buckets 1024
max_translations_per_thread = 10 * 1024;
}
+ sm->translation_memory_size_set = translation_memory_size != 0;
+
sm->max_translations_per_thread = max_translations_per_thread;
sm->translation_buckets =
nat_calc_bihash_buckets (sm->max_translations_per_thread);
rp->vrf_id,
rp->addr_only, ~0 /* sw_if_index */ ,
rp->proto, !is_delete, rp->twice_nat,
- rp->out2in_only, rp->tag, rp->identity_nat);
+ rp->out2in_only, rp->tag, rp->identity_nat,
+ rp->pool_addr, rp->exact);
if (rv)
nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
}
rp->proto,
rp->is_add, rp->twice_nat,
rp->out2in_only, rp->tag,
- rp->identity_nat);
+ rp->identity_nat,
+ rp->pool_addr, rp->exact);
if (rv)
nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
"i4", rv);