diff options
author | Matus Fabian <matfabia@cisco.com> | 2017-01-23 23:42:28 -0800 |
---|---|---|
committer | Ole Trøan <otroan@employees.org> | 2017-01-25 13:27:25 +0000 |
commit | 36532bda926f5255a323c9cac3144dd758a05667 (patch) | |
tree | a774c943419315e57e944789cb9172b373a78621 | |
parent | 6dbbc58b6c7a288d941a8572df4b085983bb00e6 (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.api | 3 | ||||
-rw-r--r-- | src/plugins/snat/snat.c | 199 | ||||
-rw-r--r-- | src/plugins/snat/snat_test.c | 27 | ||||
-rw-r--r-- | test/test_snat.py | 33 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 5 |
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( |