NAT44: identity NAT fix (VPP-1441)
Change-Id: Ic4affc54d15d08b9b730f6ec6146ee053b28b4b6 Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:

committed by
Damjan Marion

parent
7212e61d92
commit
33f276e0af
@ -631,7 +631,6 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
clib_bihash_kv_8_8_t kv, value;
|
||||
snat_address_t *a = 0;
|
||||
u32 fib_index = ~0;
|
||||
uword *p;
|
||||
snat_interface_t *interface;
|
||||
int i;
|
||||
snat_main_per_thread_data_t *tsm;
|
||||
@ -643,6 +642,8 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
u64 user_index;
|
||||
snat_session_t *s;
|
||||
snat_static_map_resolve_t *rp, *rp_match = 0;
|
||||
nat44_lb_addr_port_t *local;
|
||||
u8 find = 0;
|
||||
|
||||
if (!sm->endpoint_dependent)
|
||||
{
|
||||
@ -732,19 +733,42 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
if (is_add)
|
||||
{
|
||||
if (m)
|
||||
return VNET_API_ERROR_VALUE_EXIST;
|
||||
{
|
||||
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;
|
||||
}
|
||||
/* *INDENT-ON* */
|
||||
vec_add2 (m->locals, local, 1);
|
||||
local->vrf_id = vrf_id;
|
||||
local->fib_index =
|
||||
fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
|
||||
FIB_SOURCE_PLUGIN_LOW);
|
||||
m_key.addr = m->local_addr;
|
||||
m_key.port = m->local_port;
|
||||
m_key.protocol = m->proto;
|
||||
m_key.fib_index = local->fib_index;
|
||||
kv.key = m_key.as_u64;
|
||||
kv.value = m - sm->static_mappings;
|
||||
clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return VNET_API_ERROR_VALUE_EXIST;
|
||||
}
|
||||
|
||||
if (twice_nat && addr_only)
|
||||
return VNET_API_ERROR_UNSUPPORTED;
|
||||
|
||||
/* Convert VRF id to FIB index */
|
||||
if (vrf_id != ~0)
|
||||
{
|
||||
p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
|
||||
if (!p)
|
||||
return VNET_API_ERROR_NO_SUCH_FIB;
|
||||
fib_index = p[0];
|
||||
}
|
||||
fib_index =
|
||||
fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
|
||||
FIB_SOURCE_PLUGIN_LOW);
|
||||
/* If not specified use inside VRF id from SNAT plugin startup config */
|
||||
else
|
||||
{
|
||||
@ -752,7 +776,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
vrf_id = sm->inside_vrf_id;
|
||||
}
|
||||
|
||||
if (!out2in_only)
|
||||
if (!(out2in_only || identity_nat))
|
||||
{
|
||||
m_key.addr = l_addr;
|
||||
m_key.port = addr_only ? 0 : l_port;
|
||||
@ -825,15 +849,23 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
m->tag = vec_dup (tag);
|
||||
m->local_addr = l_addr;
|
||||
m->external_addr = e_addr;
|
||||
m->vrf_id = vrf_id;
|
||||
m->fib_index = fib_index;
|
||||
m->twice_nat = twice_nat;
|
||||
if (out2in_only)
|
||||
m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
|
||||
if (addr_only)
|
||||
m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
|
||||
if (identity_nat)
|
||||
m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
|
||||
{
|
||||
m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
|
||||
vec_add2 (m->locals, local, 1);
|
||||
local->vrf_id = vrf_id;
|
||||
local->fib_index = fib_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
m->vrf_id = vrf_id;
|
||||
m->fib_index = fib_index;
|
||||
}
|
||||
if (!addr_only)
|
||||
{
|
||||
m->local_port = l_port;
|
||||
@ -855,7 +887,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
m_key.addr = m->local_addr;
|
||||
m_key.port = m->local_port;
|
||||
m_key.protocol = m->proto;
|
||||
m_key.fib_index = m->fib_index;
|
||||
m_key.fib_index = fib_index;
|
||||
kv.key = m_key.as_u64;
|
||||
kv.value = m - sm->static_mappings;
|
||||
if (!out2in_only)
|
||||
@ -920,6 +952,25 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
}
|
||||
|
||||
if (identity_nat)
|
||||
{
|
||||
for (i = 0; i < vec_len (m->locals); i++)
|
||||
{
|
||||
if (m->locals[i].vrf_id == vrf_id)
|
||||
{
|
||||
find = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!find)
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
|
||||
fib_index = m->locals[i].fib_index;
|
||||
vec_del1 (m->locals, i);
|
||||
}
|
||||
else
|
||||
fib_index = m->fib_index;
|
||||
|
||||
/* Free external address port */
|
||||
if (!(addr_only || sm->static_mapping_only || out2in_only))
|
||||
{
|
||||
@ -958,23 +1009,17 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
|
||||
m_key.addr = m->local_addr;
|
||||
m_key.port = m->local_port;
|
||||
m_key.protocol = m->proto;
|
||||
m_key.fib_index = m->fib_index;
|
||||
m_key.fib_index = fib_index;
|
||||
kv.key = m_key.as_u64;
|
||||
if (!out2in_only)
|
||||
clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
|
||||
|
||||
m_key.addr = m->external_addr;
|
||||
m_key.port = m->external_port;
|
||||
m_key.fib_index = 0;
|
||||
kv.key = m_key.as_u64;
|
||||
clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
|
||||
|
||||
/* Delete session(s) for static mapping if exist */
|
||||
if (!(sm->static_mapping_only) ||
|
||||
(sm->static_mapping_only && sm->static_mapping_connection_tracking))
|
||||
{
|
||||
u_key.addr = m->local_addr;
|
||||
u_key.fib_index = m->fib_index;
|
||||
u_key.fib_index = fib_index;
|
||||
kv.key = u_key.as_u64;
|
||||
if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
|
||||
{
|
||||
@ -1018,6 +1063,16 @@ 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))
|
||||
return 0;
|
||||
|
||||
m_key.addr = m->external_addr;
|
||||
m_key.port = m->external_port;
|
||||
m_key.fib_index = 0;
|
||||
kv.key = m_key.as_u64;
|
||||
clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
|
||||
|
||||
vec_free (m->tag);
|
||||
vec_free (m->workers);
|
||||
/* Delete static mapping from pool */
|
||||
@ -1137,6 +1192,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
|
||||
m->external_port = e_port;
|
||||
m->proto = proto;
|
||||
m->twice_nat = twice_nat;
|
||||
m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
|
||||
if (out2in_only)
|
||||
m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
|
||||
m->affinity = affinity;
|
||||
@ -1205,6 +1261,9 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
|
||||
if (!m)
|
||||
return VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
|
||||
if (!is_lb_static_mapping (m))
|
||||
return VNET_API_ERROR_INVALID_VALUE;
|
||||
|
||||
/* Free external address port */
|
||||
if (!(sm->static_mapping_only || out2in_only))
|
||||
{
|
||||
@ -2041,7 +2100,7 @@ snat_static_mapping_match (snat_main_t * sm,
|
||||
|
||||
if (by_external)
|
||||
{
|
||||
if (vec_len (m->locals))
|
||||
if (is_lb_static_mapping (m))
|
||||
{
|
||||
if (PREDICT_FALSE (lb != 0))
|
||||
*lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
|
||||
@ -2612,7 +2671,7 @@ nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
|
||||
(&sm->static_mapping_by_external, &kv, &value))
|
||||
{
|
||||
m = pool_elt_at_index (sm->static_mappings, value.value);
|
||||
if (!vec_len (m->locals))
|
||||
if (!is_lb_static_mapping (m))
|
||||
return m->workers[0];
|
||||
|
||||
hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
|
||||
|
@ -183,6 +183,7 @@ typedef enum
|
||||
#define NAT_STATIC_MAPPING_FLAG_ADDR_ONLY 1
|
||||
#define NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY 2
|
||||
#define NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT 4
|
||||
#define NAT_STATIC_MAPPING_FLAG_LB 8
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
typedef CLIB_PACKED(struct
|
||||
@ -666,6 +667,12 @@ unformat_function_t unformat_snat_protocol;
|
||||
*/
|
||||
#define is_identity_static_mapping(sm) (sm->flags & NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT)
|
||||
|
||||
/** \brief Check if NAT static mapping is load-balancing.
|
||||
@param sm NAT static mapping
|
||||
@return 1 if load-balancing
|
||||
*/
|
||||
#define is_lb_static_mapping(sm) (sm->flags & NAT_STATIC_MAPPING_FLAG_LB)
|
||||
|
||||
/* logging */
|
||||
#define nat_log_err(...) \
|
||||
vlib_log(VLIB_LOG_LEVEL_ERR, snat_main.log_class, __VA_ARGS__)
|
||||
|
@ -1100,7 +1100,7 @@ vl_api_nat44_static_mapping_dump_t_handler (vl_api_nat44_static_mapping_dump_t
|
||||
/* *INDENT-OFF* */
|
||||
pool_foreach (m, sm->static_mappings,
|
||||
({
|
||||
if (!is_identity_static_mapping(m) && !vec_len (m->locals))
|
||||
if (!is_identity_static_mapping(m) && !is_lb_static_mapping (m))
|
||||
send_nat44_static_mapping_details (m, reg, mp->context);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
@ -1181,17 +1181,17 @@ static void *vl_api_nat44_add_del_identity_mapping_t_print
|
||||
|
||||
if (mp->addr_only == 0)
|
||||
s =
|
||||
format (s, "protocol %d port %d", mp->protocol,
|
||||
format (s, " protocol %d port %d", mp->protocol,
|
||||
clib_net_to_host_u16 (mp->port));
|
||||
|
||||
if (mp->vrf_id != ~0)
|
||||
s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id));
|
||||
s = format (s, " vrf %d", clib_net_to_host_u32 (mp->vrf_id));
|
||||
|
||||
FINISH;
|
||||
}
|
||||
|
||||
static void
|
||||
send_nat44_identity_mapping_details (snat_static_mapping_t * m,
|
||||
send_nat44_identity_mapping_details (snat_static_mapping_t * m, int index,
|
||||
vl_api_registration_t * reg, u32 context)
|
||||
{
|
||||
vl_api_nat44_identity_mapping_details_t *rmp;
|
||||
@ -1205,7 +1205,7 @@ send_nat44_identity_mapping_details (snat_static_mapping_t * m,
|
||||
clib_memcpy (rmp->ip_address, &(m->local_addr), 4);
|
||||
rmp->port = htons (m->local_port);
|
||||
rmp->sw_if_index = ~0;
|
||||
rmp->vrf_id = htonl (m->vrf_id);
|
||||
rmp->vrf_id = htonl (m->locals[index].vrf_id);
|
||||
rmp->protocol = snat_proto_to_ip_proto (m->proto);
|
||||
rmp->context = context;
|
||||
if (m->tag)
|
||||
@ -1258,8 +1258,11 @@ static void
|
||||
/* *INDENT-OFF* */
|
||||
pool_foreach (m, sm->static_mappings,
|
||||
({
|
||||
if (is_identity_static_mapping(m) && !vec_len (m->locals))
|
||||
send_nat44_identity_mapping_details (m, reg, mp->context);
|
||||
if (is_identity_static_mapping(m) && !is_lb_static_mapping (m))
|
||||
{
|
||||
for (j = 0; j < vec_len (m->locals); j++)
|
||||
send_nat44_identity_mapping_details (m, j, reg, mp->context);
|
||||
}
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@ -1689,7 +1692,7 @@ static void
|
||||
/* *INDENT-OFF* */
|
||||
pool_foreach (m, sm->static_mappings,
|
||||
({
|
||||
if (vec_len(m->locals))
|
||||
if (is_lb_static_mapping(m))
|
||||
send_nat44_lb_static_mapping_details (m, reg, mp->context);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
|
@ -220,6 +220,23 @@ format_snat_static_mapping (u8 * s, va_list * args)
|
||||
snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
|
||||
nat44_lb_addr_port_t *local;
|
||||
|
||||
if (is_identity_static_mapping (m))
|
||||
{
|
||||
if (is_addr_only_static_mapping (m))
|
||||
s = format (s, "identity mapping %U",
|
||||
format_ip4_address, &m->local_addr);
|
||||
else
|
||||
s = format (s, "identity mapping %U:%d",
|
||||
format_ip4_address, &m->local_addr, m->local_port);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
vec_foreach (local, m->locals)
|
||||
s = format (s, " vrf %d", local->vrf_id);
|
||||
/* *INDENT-ON* */
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
if (is_addr_only_static_mapping (m))
|
||||
s = format (s, "local %U external %U vrf %d %s %s",
|
||||
format_ip4_address, &m->local_addr,
|
||||
@ -230,7 +247,7 @@ format_snat_static_mapping (u8 * s, va_list * args)
|
||||
is_out2in_only_static_mapping (m) ? "out2in-only" : "");
|
||||
else
|
||||
{
|
||||
if (vec_len (m->locals))
|
||||
if (is_lb_static_mapping (m))
|
||||
{
|
||||
s = format (s, "%U external %U:%d %s %s",
|
||||
format_snat_protocol, m->proto,
|
||||
|
@ -1937,6 +1937,10 @@ class TestNAT44(MethodHolder):
|
||||
|
||||
sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
|
||||
self.assertEqual(len(sessions), 0)
|
||||
self.vapi.nat44_add_del_identity_mapping(ip=self.pg0.remote_ip4n,
|
||||
vrf_id=1)
|
||||
identity_mappings = self.vapi.nat44_identity_mapping_dump()
|
||||
self.assertEqual(len(identity_mappings), 2)
|
||||
|
||||
def test_multiple_inside_interfaces(self):
|
||||
""" NAT44 multiple non-overlapping address space inside interfaces """
|
||||
|
Reference in New Issue
Block a user