summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/nat/nat.c')
-rwxr-xr-xsrc/plugins/nat/nat.c273
1 files changed, 233 insertions, 40 deletions
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 6bfea3c4162..2e1aa770581 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -665,7 +665,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
snat_session_t *s;
snat_static_map_resolve_t *rp, *rp_match = 0;
nat44_lb_addr_port_t *local;
- u8 find = 0;
+ u32 find = ~0;
if (!sm->endpoint_dependent)
{
@@ -759,13 +759,13 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
if (is_identity_static_mapping (m))
{
/* *INDENT-OFF* */
- vec_foreach (local, m->locals)
- {
- if (local->vrf_id == vrf_id)
- return VNET_API_ERROR_VALUE_EXIST;
- }
+ pool_foreach (local, m->locals,
+ ({
+ if (local->vrf_id == vrf_id)
+ return VNET_API_ERROR_VALUE_EXIST;
+ }));
/* *INDENT-ON* */
- vec_add2 (m->locals, local, 1);
+ pool_get (m->locals, local);
local->vrf_id = vrf_id;
local->fib_index =
fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
@@ -879,7 +879,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
if (identity_nat)
{
m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
- vec_add2 (m->locals, local, 1);
+ pool_get (m->locals, local);
local->vrf_id = vrf_id;
local->fib_index = fib_index;
}
@@ -979,19 +979,19 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
if (vrf_id == ~0)
vrf_id = sm->inside_vrf_id;
- for (i = 0; i < vec_len (m->locals); i++)
- {
- if (m->locals[i].vrf_id == vrf_id)
- {
- find = 1;
- break;
- }
- }
- if (!find)
+ /* *INDENT-OFF* */
+ pool_foreach (local, m->locals,
+ ({
+ if (local->vrf_id == vrf_id)
+ find = local - m->locals;
+ }));
+ /* *INDENT-ON* */
+ if (find == ~0)
return VNET_API_ERROR_NO_SUCH_ENTRY;
- fib_index = m->locals[i].fib_index;
- vec_del1 (m->locals, i);
+ local = pool_elt_at_index (m->locals, find);
+ fib_index = local->fib_index;
+ pool_put (m->locals, local);
}
else
fib_index = m->fib_index;
@@ -1089,7 +1089,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
}
fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
- if (vec_len (m->locals))
+ if (pool_elts (m->locals))
return 0;
m_key.addr = m->external_addr;
@@ -1258,7 +1258,8 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
}
locals[i].prefix = (i == 0) ? locals[i].probability :
(locals[i - 1].prefix + locals[i].probability);
- vec_add1 (m->locals, locals[i]);
+ pool_get (m->locals, local);
+ *local = locals[i];
if (sm->num_workers > 1)
{
ip4_header_t ip = {
@@ -1331,8 +1332,8 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
}
/* *INDENT-OFF* */
- vec_foreach (local, m->locals)
- {
+ pool_foreach (local, m->locals,
+ ({
fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
FIB_SOURCE_PLUGIN_LOW);
m_key.addr = local->addr;
@@ -1361,7 +1362,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
/* Delete sessions */
u_key.addr = local->addr;
- u_key.fib_index = m->fib_index;
+ u_key.fib_index = local->fib_index;
kv.key = u_key.as_u64;
if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
{
@@ -1391,11 +1392,11 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
}
}
}
- }
+ }));
/* *INDENT-ON* */
if (m->affinity)
nat_affinity_flush_service (m->affinity_per_service_list_head_index);
- vec_free (m->locals);
+ pool_free (m->locals);
vec_free (m->tag);
vec_free (m->workers);
@@ -1406,6 +1407,187 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
}
int
+nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
+ ip4_address_t l_addr, u16 l_port,
+ snat_protocol_t proto, u32 vrf_id,
+ u8 probability, u8 is_add)
+{
+ snat_main_t *sm = &snat_main;
+ snat_static_mapping_t *m = 0;
+ snat_session_key_t m_key;
+ clib_bihash_kv_8_8_t kv, value;
+ nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
+ snat_main_per_thread_data_t *tsm;
+ snat_user_key_t u_key;
+ snat_user_t *u;
+ snat_session_t *s;
+ dlist_elt_t *head, *elt;
+ u32 elt_index, head_index, ses_index, *locals = 0;
+ uword *bitmap = 0;
+ int i;
+
+ if (!sm->endpoint_dependent)
+ return VNET_API_ERROR_FEATURE_DISABLED;
+
+ m_key.addr = e_addr;
+ m_key.port = e_port;
+ m_key.protocol = proto;
+ m_key.fib_index = 0;
+ 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);
+
+ if (!m)
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ if (!is_lb_static_mapping (m))
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ /* *INDENT-OFF* */
+ pool_foreach (local, m->locals,
+ ({
+ if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
+ (local->vrf_id == vrf_id))
+ {
+ match_local = local;
+ break;
+ }
+ }));
+ /* *INDENT-ON* */
+
+ if (is_add)
+ {
+ if (match_local)
+ return VNET_API_ERROR_VALUE_EXIST;
+
+ pool_get (m->locals, local);
+ clib_memset (local, 0, sizeof (*local));
+ local->addr.as_u32 = l_addr.as_u32;
+ local->port = l_port;
+ local->probability = probability;
+ local->vrf_id = vrf_id;
+ local->fib_index =
+ fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
+ FIB_SOURCE_PLUGIN_LOW);
+
+ if (!is_out2in_only_static_mapping (m))
+ {
+ m_key.addr = l_addr;
+ m_key.port = l_port;
+ m_key.fib_index = local->fib_index;
+ kv.key = m_key.as_u64;
+ kv.value = m - sm->static_mappings;
+ if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
+ nat_log_err ("static_mapping_by_local key add failed");
+ }
+ }
+ else
+ {
+ if (!match_local)
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ if (pool_elts (m->locals) < 3)
+ return VNET_API_ERROR_UNSPECIFIED;
+
+ fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
+ FIB_SOURCE_PLUGIN_LOW);
+
+ if (!is_out2in_only_static_mapping (m))
+ {
+ m_key.addr = l_addr;
+ m_key.port = l_port;
+ m_key.fib_index = match_local->fib_index;
+ kv.key = m_key.as_u64;
+ if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
+ nat_log_err ("static_mapping_by_local key del failed");
+ }
+
+ if (sm->num_workers > 1)
+ {
+ ip4_header_t ip = {
+ .src_address = local->addr,
+ };
+ tsm = vec_elt_at_index (sm->per_thread_data,
+ sm->worker_in2out_cb (&ip, m->fib_index));
+ }
+ else
+ tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
+
+ /* Delete sessions */
+ u_key.addr = match_local->addr;
+ u_key.fib_index = match_local->fib_index;
+ kv.key = u_key.as_u64;
+ if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+ {
+ u = pool_elt_at_index (tsm->users, value.value);
+ if (u->nstaticsessions)
+ {
+ head_index = u->sessions_per_user_list_head_index;
+ head = pool_elt_at_index (tsm->list_pool, head_index);
+ elt_index = head->next;
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
+ ses_index = elt->value;
+ while (ses_index != ~0)
+ {
+ s = pool_elt_at_index (tsm->sessions, ses_index);
+ elt = pool_elt_at_index (tsm->list_pool, elt->next);
+ ses_index = elt->value;
+
+ if (!(is_lb_session (s)))
+ continue;
+
+ if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
+ (clib_net_to_host_u16 (s->in2out.port) !=
+ match_local->port))
+ continue;
+
+ nat_free_session_data (sm, s, tsm - sm->per_thread_data);
+ nat44_delete_session (sm, s, tsm - sm->per_thread_data);
+ }
+ }
+ }
+
+ pool_put (m->locals, match_local);
+ }
+
+ vec_free (m->workers);
+
+ /* *INDENT-OFF* */
+ pool_foreach (local, m->locals,
+ ({
+ vec_add1 (locals, local - m->locals);
+ if (sm->num_workers > 1)
+ {
+ ip4_header_t ip;
+ ip.src_address.as_u32 = local->addr.as_u32,
+ bitmap = clib_bitmap_set (bitmap,
+ sm->worker_in2out_cb (&ip, local->fib_index),
+ 1);
+ }
+ }));
+ /* *INDENT-ON* */
+
+ local = pool_elt_at_index (m->locals, locals[0]);
+ local->prefix = local->probability;
+ for (i = 1; i < vec_len (locals); i++)
+ {
+ local = pool_elt_at_index (m->locals, locals[i]);
+ prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
+ local->prefix = local->probability + prev_local->prefix;
+ }
+
+ /* Assign workers */
+ if (sm->num_workers > 1)
+ {
+ /* *INDENT-OFF* */
+ clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
+ /* *INDENT-ON* */
+ }
+
+ return 0;
+}
+
+int
snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
u8 twice_nat)
{
@@ -2095,8 +2277,9 @@ snat_static_mapping_match (snat_main_t * sm,
snat_static_mapping_t *m;
snat_session_key_t m_key;
clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
- u32 rand, lo = 0, hi, mid;
+ u32 rand, lo = 0, hi, mid, *tmp = 0, i;
u8 backend_index;
+ nat44_lb_addr_port_t *local;
m_key.fib_index = match.fib_index;
if (by_external)
@@ -2136,42 +2319,52 @@ snat_static_mapping_match (snat_main_t * sm,
&backend_index))
goto get_local;
- mapping->addr = m->locals[backend_index].addr;
- mapping->port =
- clib_host_to_net_u16 (m->locals[backend_index].port);
- mapping->fib_index = m->locals[backend_index].fib_index;
+ local = pool_elt_at_index (m->locals, backend_index);
+ mapping->addr = local->addr;
+ mapping->port = clib_host_to_net_u16 (local->port);
+ mapping->fib_index = local->fib_index;
goto end;
}
get_local:
- hi = vec_len (m->locals) - 1;
- rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
+ /* *INDENT-OFF* */
+ pool_foreach_index (i, m->locals,
+ ({
+ vec_add1 (tmp, i);
+ }));
+ /* *INDENT-ON* */
+ hi = vec_len (tmp) - 1;
+ local = pool_elt_at_index (m->locals, tmp[hi]);
+ rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
while (lo < hi)
{
mid = ((hi - lo) >> 1) + lo;
- (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
+ local = pool_elt_at_index (m->locals, tmp[mid]);
+ (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
}
- if (!(m->locals[lo].prefix >= rand))
+ local = pool_elt_at_index (m->locals, tmp[lo]);
+ if (!(local->prefix >= rand))
return 1;
if (PREDICT_FALSE (sm->num_workers > 1))
{
ip4_header_t ip = {
- .src_address = m->locals[lo].addr,
+ .src_address = local->addr,
};
if (sm->worker_in2out_cb (&ip, m->fib_index) !=
vlib_get_thread_index ())
goto get_local;
}
- mapping->addr = m->locals[lo].addr;
- mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
- mapping->fib_index = m->locals[lo].fib_index;
+ mapping->addr = local->addr;
+ mapping->port = clib_host_to_net_u16 (local->port);
+ mapping->fib_index = local->fib_index;
if (m->affinity)
{
if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
match.protocol, match.port,
- lo, m->affinity,
+ tmp[lo], m->affinity,
m->affinity_per_service_list_head_index))
nat_log_info ("create affinity record failed");
}
+ vec_free (tmp);
}
else
{