summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2017-01-23 23:42:28 -0800
committerOle Trøan <otroan@employees.org>2017-01-25 13:27:25 +0000
commit36532bda926f5255a323c9cac3144dd758a05667 (patch)
treea774c943419315e57e944789cb9172b373a78621
parent6dbbc58b6c7a288d941a8572df4b085983bb00e6 (diff)
SNAT: static mappings for dhcp addressed interfaces (VPP-590)
updated API added test Change-Id: I3f6017ecf09b924cb320c1b5f323cd33f7a37447 Signed-off-by: Matus Fabian <matfabia@cisco.com>
-rw-r--r--src/plugins/snat/snat.api3
-rw-r--r--src/plugins/snat/snat.c199
-rw-r--r--src/plugins/snat/snat_test.c27
-rw-r--r--test/test_snat.py33
-rw-r--r--test/vpp_papi_provider.py5
5 files changed, 176 insertions, 91 deletions
diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api
index ff1d9bc1b8a..b562e7a08e1 100644
--- a/src/plugins/snat/snat.api
+++ b/src/plugins/snat/snat.api
@@ -120,6 +120,8 @@ define snat_interface_details {
@param external_ip_address - external IP address
@param local_port - local port number
@param external_port - external port number
+ @param external_sw_if_index - external interface (if set
+ external_ip_address is ignored)
@param vfr_id - VRF ID
*/
define snat_add_static_mapping {
@@ -132,6 +134,7 @@ define snat_add_static_mapping {
u8 external_ip_address[16];
u16 local_port;
u16 external_port;
+ u32 external_sw_if_index;
u32 vrf_id;
};
diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c
index 337a0e08a3b..fb566598730 100644
--- a/src/plugins/snat/snat.c
+++ b/src/plugins/snat/snat.c
@@ -240,81 +240,6 @@ static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
return 0;
}
-int snat_del_address (snat_main_t *sm, ip4_address_t addr)
-{
- snat_address_t *a = 0;
- snat_session_t *ses;
- u32 *ses_to_be_removed = 0, *ses_index;
- clib_bihash_kv_8_8_t kv, value;
- snat_user_key_t user_key;
- snat_user_t *u;
- snat_main_per_thread_data_t *tsm;
-
- int i;
-
- /* Find SNAT address */
- for (i=0; i < vec_len (sm->addresses); i++)
- {
- if (sm->addresses[i].addr.as_u32 == addr.as_u32)
- {
- a = sm->addresses + i;
- break;
- }
- }
- if (!a)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- /* Check if address is used in some static mapping */
- if (is_snat_address_used_in_static_mapping(sm, addr))
- {
- clib_warning ("address used in static mapping");
- return VNET_API_ERROR_UNSPECIFIED;
- }
-
- /* Delete sessions using address */
- if (a->busy_ports)
- {
- vec_foreach (tsm, sm->per_thread_data)
- {
- pool_foreach (ses, tsm->sessions, ({
- if (ses->out2in.addr.as_u32 == addr.as_u32)
- {
- /* log NAT event */
- snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
- ses->out2in.addr.as_u32,
- ses->in2out.protocol,
- ses->in2out.port,
- ses->out2in.port,
- ses->in2out.fib_index);
- vec_add1 (ses_to_be_removed, ses - tsm->sessions);
- kv.key = ses->in2out.as_u64;
- clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
- kv.key = ses->out2in.as_u64;
- clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
- clib_dlist_remove (tsm->list_pool, ses->per_user_index);
- user_key.addr = ses->in2out.addr;
- user_key.fib_index = ses->in2out.fib_index;
- kv.key = user_key.as_u64;
- if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
- {
- u = pool_elt_at_index (tsm->users, value.value);
- u->nsessions--;
- }
- }
- }));
-
- vec_foreach (ses_index, ses_to_be_removed)
- pool_put_index (tsm->sessions, ses_index[0]);
-
- vec_free (ses_to_be_removed);
- }
- }
-
- vec_del1 (sm->addresses, i);
-
- return 0;
-}
-
static void increment_v4_address (ip4_address_t * a)
{
u32 v;
@@ -356,6 +281,7 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm,
* @param e_port External port number.
* @param vrf_id VRF ID.
* @param addr_only If 0 address port and pair mapping, otherwise address only.
+ * @param sw_if_index External port instead of specific IP address.
* @param is_add If 0 delete static mapping, otherwise add.
*
* @returns
@@ -638,6 +564,94 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
return 0;
}
+int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
+{
+ snat_address_t *a = 0;
+ snat_session_t *ses;
+ u32 *ses_to_be_removed = 0, *ses_index;
+ clib_bihash_kv_8_8_t kv, value;
+ snat_user_key_t user_key;
+ snat_user_t *u;
+ snat_main_per_thread_data_t *tsm;
+ snat_static_mapping_t *m;
+ int i;
+
+ /* Find SNAT address */
+ for (i=0; i < vec_len (sm->addresses); i++)
+ {
+ if (sm->addresses[i].addr.as_u32 == addr.as_u32)
+ {
+ a = sm->addresses + i;
+ break;
+ }
+ }
+ if (!a)
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ if (delete_sm)
+ {
+ 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, m->addr_only, ~0, 0);
+ }));
+ }
+ else
+ {
+ /* Check if address is used in some static mapping */
+ if (is_snat_address_used_in_static_mapping(sm, addr))
+ {
+ clib_warning ("address used in static mapping");
+ return VNET_API_ERROR_UNSPECIFIED;
+ }
+ }
+
+ /* Delete sessions using address */
+ if (a->busy_ports)
+ {
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ pool_foreach (ses, tsm->sessions, ({
+ if (ses->out2in.addr.as_u32 == addr.as_u32)
+ {
+ /* log NAT event */
+ snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
+ ses->out2in.addr.as_u32,
+ ses->in2out.protocol,
+ ses->in2out.port,
+ ses->out2in.port,
+ ses->in2out.fib_index);
+ vec_add1 (ses_to_be_removed, ses - tsm->sessions);
+ kv.key = ses->in2out.as_u64;
+ clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
+ kv.key = ses->out2in.as_u64;
+ clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
+ clib_dlist_remove (tsm->list_pool, ses->per_user_index);
+ user_key.addr = ses->in2out.addr;
+ user_key.fib_index = ses->in2out.fib_index;
+ kv.key = user_key.as_u64;
+ if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
+ {
+ u = pool_elt_at_index (tsm->users, value.value);
+ u->nsessions--;
+ }
+ }
+ }));
+
+ vec_foreach (ses_index, ses_to_be_removed)
+ pool_put_index (tsm->sessions, ses_index[0]);
+
+ vec_free (ses_to_be_removed);
+ }
+ }
+
+ vec_del1 (sm->addresses, i);
+
+ return 0;
+}
+
static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
{
snat_main_t *sm = &snat_main;
@@ -750,7 +764,7 @@ vl_api_snat_add_address_range_t_handler
if (mp->is_add)
snat_add_address (sm, &this_addr);
else
- rv = snat_del_address (sm, this_addr);
+ rv = snat_del_address (sm, this_addr, 0);
if (rv)
goto send_reply;
@@ -904,7 +918,7 @@ vl_api_snat_add_static_mapping_t_handler
vl_api_snat_add_static_mapping_reply_t * rmp;
ip4_address_t local_addr, external_addr;
u16 local_port = 0, external_port = 0;
- u32 vrf_id;
+ u32 vrf_id, external_sw_if_index;
int rv = 0;
if (mp->is_ip4 != 1)
@@ -921,10 +935,11 @@ vl_api_snat_add_static_mapping_t_handler
external_port = clib_net_to_host_u16 (mp->external_port);
}
vrf_id = clib_net_to_host_u32 (mp->vrf_id);
+ external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
rv = snat_add_static_mapping(local_addr, external_addr, local_port,
external_port, vrf_id, mp->addr_only,
- ~0 /* sw_if_index */,
+ external_sw_if_index,
mp->is_add);
send_reply:
@@ -949,6 +964,9 @@ static void *vl_api_snat_add_static_mapping_t_print
if (mp->vrf_id != ~0)
s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id));
+ if (mp->external_sw_if_index != ~0)
+ s = format (s, "external_sw_if_index %d",
+ clib_net_to_host_u32 (mp->external_sw_if_index));
FINISH;
}
@@ -1578,7 +1596,7 @@ add_address_command_fn (vlib_main_t * vm,
if (is_add)
snat_add_address (sm, &this_addr);
else
- rv = snat_del_address (sm, this_addr);
+ rv = snat_del_address (sm, this_addr, 0);
switch (rv)
{
@@ -2285,7 +2303,7 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
}
else
{
- (void) snat_del_address(sm, address[0]);
+ (void) snat_del_address(sm, address[0], 1);
return;
}
}
@@ -2299,7 +2317,9 @@ static int snat_add_interface_address (snat_main_t *sm,
{
ip4_main_t * ip4_main = sm->ip4_main;
ip4_address_t * first_int_addr;
- int i;
+ snat_static_map_resolve_t *rp;
+ u32 *indices_to_delete = 0;
+ int i, j;
first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
0 /* just want the address*/);
@@ -2312,7 +2332,22 @@ static int snat_add_interface_address (snat_main_t *sm,
{
/* if have address remove it */
if (first_int_addr)
- (void) snat_del_address (sm, first_int_addr[0]);
+ (void) snat_del_address (sm, first_int_addr[0], 1);
+ else
+ {
+ for (j = 0; j < vec_len (sm->to_resolve); j++)
+ {
+ rp = sm->to_resolve + j;
+ if (rp->sw_if_index == sw_if_index)
+ vec_add1 (indices_to_delete, j);
+ }
+ if (vec_len(indices_to_delete))
+ {
+ for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
+ vec_del1(sm->to_resolve, j);
+ vec_free(indices_to_delete);
+ }
+ }
vec_del1(sm->auto_add_sw_if_indices, i);
}
else
diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c
index b601d7d9c86..67dc4380cf7 100644
--- a/src/plugins/snat/snat_test.c
+++ b/src/plugins/snat/snat_test.c
@@ -213,24 +213,32 @@ static int api_snat_add_static_mapping(vat_main_t * vam)
unformat_input_t * i = vam->input;
f64 timeout;
vl_api_snat_add_static_mapping_t * mp;
- u8 addr_set_n = 0;
+ u8 external_addr_set = 0;
+ u8 local_addr_set;
u8 is_add = 1;
u8 addr_only = 1;
ip4_address_t local_addr, external_addr;
u32 local_port = 0, external_port = 0, vrf_id = ~0;
+ u32 sw_if_index = ~0;
+ u8 sw_if_index_set = 0;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "local_addr %U", unformat_ip4_address, &local_addr))
- addr_set_n++;
+ local_addr_set = 1;
else if (unformat (i, "external_addr %U", unformat_ip4_address,
&external_addr))
- addr_set_n++;
+ external_addr_set = 1;
else if (unformat (i, "local_port %u", &local_port))
addr_only = 0;
else if (unformat (i, "external_port %u", &external_port))
addr_only = 0;
- else if (unformat (i, "vrf %u", &vrf_id))
+ else if (unformat (i, "external_if %U", unformat_sw_if_index, vam,
+ &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "external_sw_if_index %d", &sw_if_index))
+ sw_if_index_set = 1;
+ else if (unformat (i, "vrf %u", &vrf_id))
;
else if (unformat (i, "del"))
is_add = 0;
@@ -241,9 +249,14 @@ static int api_snat_add_static_mapping(vat_main_t * vam)
}
}
- if (addr_set_n != 2)
+ if (!local_addr_set)
+ {
+ errmsg ("local addr required\n");
+ return -99;
+ }
+ if (!external_addr_set && !sw_if_index_set)
{
- errmsg ("local_addr and remote_addr required\n");
+ errmsg ("external addr or interface required\n");
return -99;
}
@@ -253,6 +266,7 @@ static int api_snat_add_static_mapping(vat_main_t * vam)
mp->addr_only = addr_only;
mp->local_port = ntohs ((u16) local_port);
mp->external_port = ntohs ((u16) external_port);
+ mp->external_sw_if_index = ntohl (sw_if_index);
mp->vrf_id = ntohl (vrf_id);
memcpy (mp->local_ip_address, &local_addr, 4);
memcpy (mp->external_ip_address, &external_addr, 4);
@@ -618,6 +632,7 @@ _(snat_add_address_range, "<start-addr> [- <end-addr] [del]") \
_(snat_interface_add_del_feature, \
"<intfc> | sw_if_index <id> [in] [out] [del]") \
_(snat_add_static_mapping, "local_addr <ip> external_addr <ip> " \
+ "| external_if <intfc> | external_sw_if_ndex <id>) " \
"[local_port <n>] [external_port <n>] [vrf <table-id>] [del]") \
_(snat_set_workers, "<wokrers_bitmap>") \
_(snat_static_mapping_dump, "") \
diff --git a/test/test_snat.py b/test/test_snat.py
index 09fdb108c0b..b6cc1c9a17f 100644
--- a/test/test_snat.py
+++ b/test/test_snat.py
@@ -269,6 +269,9 @@ class TestSNAT(VppTestCase):
"""
Clear SNAT configuration.
"""
+ if self.pg7.has_ip4_config:
+ self.pg7.unconfig_ip4()
+
interfaces = self.vapi.snat_interface_addr_dump()
for intf in interfaces:
self.vapi.snat_add_interface_addr(intf.sw_if_index, is_add=0)
@@ -297,8 +300,9 @@ class TestSNAT(VppTestCase):
addr.ip_address,
is_add=0)
- def snat_add_static_mapping(self, local_ip, external_ip, local_port=0,
- external_port=0, vrf_id=0, is_add=1):
+ def snat_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
+ local_port=0, external_port=0, vrf_id=0,
+ is_add=1, external_sw_if_index=0xFFFFFFFF):
"""
Add/delete S-NAT static mapping
@@ -308,6 +312,7 @@ class TestSNAT(VppTestCase):
:param external_port: External port number (Optional)
:param vrf_id: VRF ID (Default 0)
:param is_add: 1 if add, 0 if delete (Default add)
+ :param external_sw_if_index: External interface instead of IP address
"""
addr_only = 1
if local_port and external_port:
@@ -317,6 +322,7 @@ class TestSNAT(VppTestCase):
self.vapi.snat_add_static_mapping(
l_ip,
e_ip,
+ external_sw_if_index,
local_port,
external_port,
addr_only,
@@ -762,12 +768,35 @@ class TestSNAT(VppTestCase):
self.pg7.config_ip4()
adresses = self.vapi.snat_address_dump()
self.assertEqual(1, len(adresses))
+ self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n)
# remove interface address and check NAT address pool
self.pg7.unconfig_ip4()
adresses = self.vapi.snat_address_dump()
self.assertEqual(0, len(adresses))
+ def test_interface_addr_static_mapping(self):
+ """ Static mapping with addresses from interface """
+ self.vapi.snat_add_interface_addr(self.pg7.sw_if_index)
+ self.snat_add_static_mapping('1.2.3.4',
+ external_sw_if_index=self.pg7.sw_if_index)
+
+ # no static mappings
+ static_mappings = self.vapi.snat_static_mapping_dump()
+ self.assertEqual(0, len(static_mappings))
+
+ # configure interface address and check static mappings
+ self.pg7.config_ip4()
+ static_mappings = self.vapi.snat_static_mapping_dump()
+ self.assertEqual(1, len(static_mappings))
+ self.assertEqual(static_mappings[0].external_ip_address[0:4],
+ self.pg7.local_ip4n)
+
+ # remove interface address and check static mappings
+ self.pg7.unconfig_ip4()
+ static_mappings = self.vapi.snat_static_mapping_dump()
+ self.assertEqual(0, len(static_mappings))
+
def test_ipfix_nat44_sess(self):
""" S-NAT IPFIX logging NAT44 session created/delted """
self.snat_add_address(self.snat_addr)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 96f3ddc5dae..901ea2744cb 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -843,7 +843,8 @@ class VppPapiProvider(object):
def snat_add_static_mapping(
self,
local_ip,
- external_ip,
+ external_ip=0,
+ external_sw_if_index=0xFFFFFFFF,
local_port=0,
external_port=0,
addr_only=1,
@@ -854,6 +855,7 @@ class VppPapiProvider(object):
:param local_ip: Local IP address
:param external_ip: External IP address
+ :param external_sw_if_index: External interface instead of IP address
:param local_port: Local port number (Default value = 0)
:param external_port: External port number (Default value = 0)
:param addr_only: 1 if address only mapping, 0 if address and port
@@ -870,6 +872,7 @@ class VppPapiProvider(object):
'external_ip_address': external_ip,
'local_port': local_port,
'external_port': external_port,
+ 'external_sw_if_index': external_sw_if_index,
'vrf_id': vrf_id})
def snat_add_address_range(