diff options
author | Juraj Sloboda <jsloboda@cisco.com> | 2017-03-06 19:55:21 -0800 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2017-03-07 12:25:31 +0000 |
commit | eab38d91e8db5ad271598a63781a7afa3bd8b5ea (patch) | |
tree | 3dcc6f2f02cf9adce01965edbee3a2ad6faa2777 | |
parent | ede470b4fc50b4e53caf303536e7b7b0ba2b77d9 (diff) |
Add setting of tenant VRF id for SNAT addresses (VPP-641)
Change-Id: I9c0bb35ba16e04206ac481495f6638d3763754a1
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
-rw-r--r-- | src/plugins/snat/in2out.c | 6 | ||||
-rw-r--r-- | src/plugins/snat/snat.api | 4 | ||||
-rw-r--r-- | src/plugins/snat/snat.c | 35 | ||||
-rw-r--r-- | src/plugins/snat/snat.h | 5 | ||||
-rw-r--r-- | test/test_snat.py | 72 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 5 |
6 files changed, 116 insertions, 11 deletions
diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c index fd8d30a164a..e9bc5384916 100644 --- a/src/plugins/snat/in2out.c +++ b/src/plugins/snat/in2out.c @@ -316,7 +316,8 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, (sm, &s->out2in, s->outside_address_index); s->outside_address_index = ~0; - if (snat_alloc_outside_address_and_port (sm, &key1, &address_index)) + if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1, + &address_index)) { ASSERT(0); @@ -334,7 +335,8 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, { static_mapping = 0; /* Try to create dynamic translation */ - if (snat_alloc_outside_address_and_port (sm, &key1, &address_index)) + if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1, + &address_index)) { b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; return SNAT_IN2OUT_NEXT_DROP; diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api index 052d30f6239..8b1537bff67 100644 --- a/src/plugins/snat/snat.api +++ b/src/plugins/snat/snat.api @@ -26,6 +26,7 @@ @param is_ip4 - 1 if address type is IPv4 @param first_ip_address - first IP address @param last_ip_address - last IP address + @param vrf_id - VRF id of tenant, ~0 means independent of VRF @param is_add - 1 if add, 0 if delete */ define snat_add_address_range { @@ -34,6 +35,7 @@ define snat_add_address_range { u8 is_ip4; u8 first_ip_address[16]; u8 last_ip_address[16]; + u32 vrf_id; u8 is_add; }; @@ -59,11 +61,13 @@ define snat_address_dump { @param context - sender context, to match reply w/ request @param is_ip4 - 1 if address type is IPv4 @param ip_address - IP address + @param vrf_id - VRF id of tenant, ~0 means independent of VRF */ define snat_address_details { u32 context; u8 is_ip4; u8 ip_address[16]; + u32 vrf_id; }; /** \brief Enable/disable S-NAT feature on the interface diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 9712a6cb8eb..12d1df402f4 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -241,11 +241,14 @@ snat_add_del_addr_to_fib (ip4_address_t * addr, u32 sw_if_index, int is_add) FIB_SOURCE_PLUGIN_HI); } -void snat_add_address (snat_main_t *sm, ip4_address_t *addr) +void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id) { snat_address_t * ap; snat_interface_t *i; + if (vrf_id != ~0) + sm->vrf_mode = 1; + /* Check if address already exists */ vec_foreach (ap, sm->addresses) { @@ -255,6 +258,7 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr) vec_add2 (sm->addresses, ap, 1); ap->addr = *addr; + ap->fib_index = ip4_fib_index_from_table_id(vrf_id); #define _(N, i, n, s) \ clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); foreach_snat_protocol @@ -824,6 +828,7 @@ vl_api_snat_add_address_range_t_handler vl_api_snat_add_address_range_reply_t * rmp; ip4_address_t this_addr; u32 start_host_order, end_host_order; + u32 vrf_id; int i, count; int rv = 0; u32 * tmp; @@ -847,6 +852,8 @@ vl_api_snat_add_address_range_t_handler count = (end_host_order - start_host_order) + 1; + vrf_id = clib_host_to_net_u32 (mp->vrf_id); + if (count > 1024) clib_warning ("%U - %U, %d addresses...", format_ip4_address, mp->first_ip_address, @@ -858,7 +865,7 @@ vl_api_snat_add_address_range_t_handler for (i = 0; i < count; i++) { if (mp->is_add) - snat_add_address (sm, &this_addr); + snat_add_address (sm, &this_addr, vrf_id); else rv = snat_del_address (sm, this_addr, 0); @@ -898,6 +905,10 @@ send_snat_address_details rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base); rmp->is_ip4 = 1; clib_memcpy (rmp->ip_address, &(a->addr), 4); + if (a->fib_index != ~0) + rmp->vrf_id = ntohl(ip4_fib_get(a->fib_index)->table_id); + else + rmp->vrf_id = ~0; rmp->context = context; vl_msg_api_send_shmem (q, (u8 *) & rmp); @@ -1786,6 +1797,7 @@ int snat_static_mapping_match (snat_main_t * sm, } int snat_alloc_outside_address_and_port (snat_main_t * sm, + u32 fib_index, snat_session_key_t * k, u32 * address_indexp) { @@ -1796,6 +1808,8 @@ int snat_alloc_outside_address_and_port (snat_main_t * sm, for (i = 0; i < vec_len (sm->addresses); i++) { a = sm->addresses + i; + if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index) + continue; switch (k->protocol) { #define _(N, j, n, s) \ @@ -1842,6 +1856,7 @@ add_address_command_fn (vlib_main_t * vm, snat_main_t * sm = &snat_main; ip4_address_t start_addr, end_addr, this_addr; u32 start_host_order, end_host_order; + u32 vrf_id = ~0; int i, count; int is_add = 1; int rv = 0; @@ -1857,6 +1872,8 @@ add_address_command_fn (vlib_main_t * vm, unformat_ip4_address, &start_addr, unformat_ip4_address, &end_addr)) ; + else if (unformat (line_input, "tenant-vrf %u", &vrf_id)) + ; else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) end_addr = start_addr; else if (unformat (line_input, "del")) @@ -1897,7 +1914,7 @@ add_address_command_fn (vlib_main_t * vm, for (i = 0; i < count; i++) { if (is_add) - snat_add_address (sm, &this_addr); + snat_add_address (sm, &this_addr, vrf_id); else rv = snat_del_address (sm, this_addr, 0); @@ -1924,7 +1941,8 @@ done: VLIB_CLI_COMMAND (add_address_command, static) = { .path = "snat add address", - .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]", + .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] " + "[tenant-vrf <vrf-id>] [del]", .function = add_address_command_fn, }; @@ -2543,6 +2561,11 @@ show_snat_command_fn (vlib_main_t * vm, vec_foreach (ap, sm->addresses) { vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); + if (ap->fib_index != ~0) + vlib_cli_output (vm, " tenant VRF: %u", + ip4_fib_get(ap->fib_index)->table_id); + else + vlib_cli_output (vm, " tenant VRF independent"); #define _(N, i, n, s) \ vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); foreach_snat_protocol @@ -2675,7 +2698,7 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im, if (sm->addresses[j].addr.as_u32 == address->as_u32) return; - snat_add_address (sm, address); + snat_add_address (sm, address, ~0); /* Scan static map resolution vector */ for (j = 0; j < vec_len (sm->to_resolve); j++) { @@ -2773,7 +2796,7 @@ static int snat_add_interface_address (snat_main_t *sm, /* If the address is already bound - or static - add it now */ if (first_int_addr) - snat_add_address (sm, first_int_addr); + snat_add_address (sm, first_int_addr, ~0); return 0; } diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h index 47f2e6ee70f..1d203aa870a 100644 --- a/src/plugins/snat/snat.h +++ b/src/plugins/snat/snat.h @@ -118,6 +118,7 @@ typedef struct { typedef struct { ip4_address_t addr; + u32 fib_index; #define _(N, i, n, s) \ u32 busy_##n##_ports; \ uword * busy_##n##_port_bitmap; @@ -226,6 +227,9 @@ typedef struct { u32 inside_vrf_id; u32 inside_fib_index; + /* tenant VRF aware address pool activation flag */ + u8 vrf_mode; + /* API message ID base */ u16 msg_id_base; @@ -250,6 +254,7 @@ void snat_free_outside_address_and_port (snat_main_t * sm, u32 address_index); int snat_alloc_outside_address_and_port (snat_main_t * sm, + u32 fib_index, snat_session_key_t * k, u32 * address_indexp); diff --git a/test/test_snat.py b/test/test_snat.py index 4cb51161353..f5e6e1398f0 100644 --- a/test/test_snat.py +++ b/test/test_snat.py @@ -405,7 +405,7 @@ class TestSNAT(VppTestCase): proto, is_add) - def snat_add_address(self, ip, is_add=1): + def snat_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF): """ Add/delete S-NAT address @@ -413,7 +413,8 @@ class TestSNAT(VppTestCase): :param is_add: 1 if add, 0 if delete (Default add) """ snat_addr = socket.inet_pton(socket.AF_INET, ip) - self.vapi.snat_add_address_range(snat_addr, snat_addr, is_add) + self.vapi.snat_add_address_range(snat_addr, snat_addr, is_add, + vrf_id=vrf_id) def test_dynamic(self): """ SNAT dynamic translation test """ @@ -1201,6 +1202,73 @@ class TestSNAT(VppTestCase): self.pg_start() capture = self.pg1.get_capture(0) + def test_vrf_mode(self): + """ S-NAT tenant VRF aware address pool mode """ + + vrf_id1 = 1 + vrf_id2 = 2 + nat_ip1 = "10.0.0.10" + nat_ip2 = "10.0.0.11" + + self.pg0.unconfig_ip4() + self.pg1.unconfig_ip4() + self.pg0.set_table_ip4(vrf_id1) + self.pg1.set_table_ip4(vrf_id2) + self.pg0.config_ip4() + self.pg1.config_ip4() + + self.snat_add_address(nat_ip1, vrf_id=vrf_id1) + self.snat_add_address(nat_ip2, vrf_id=vrf_id2) + self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg2.sw_if_index, + is_inside=0) + + # first VRF + pkts = self.create_stream_in(self.pg0, self.pg2) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg2.get_capture(len(pkts)) + self.verify_capture_out(capture, nat_ip1) + + # second VRF + pkts = self.create_stream_in(self.pg1, self.pg2) + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg2.get_capture(len(pkts)) + self.verify_capture_out(capture, nat_ip2) + + def test_vrf_feature_independent(self): + """ S-NAT tenant VRF independent address pool mode """ + + nat_ip1 = "10.0.0.10" + nat_ip2 = "10.0.0.11" + + self.snat_add_address(nat_ip1) + self.snat_add_address(nat_ip2) + self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index) + self.vapi.snat_interface_add_del_feature(self.pg2.sw_if_index, + is_inside=0) + + # first VRF + pkts = self.create_stream_in(self.pg0, self.pg2) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg2.get_capture(len(pkts)) + self.verify_capture_out(capture, nat_ip1) + + # second VRF + pkts = self.create_stream_in(self.pg1, self.pg2) + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg2.get_capture(len(pkts)) + self.verify_capture_out(capture, nat_ip1) + def tearDown(self): super(TestSNAT, self).tearDown() if not self.vpp_dead: diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index fe152de3969..c7e875f0481 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1023,11 +1023,13 @@ class VppPapiProvider(object): first_ip_address, last_ip_address, is_add=1, - is_ip4=1): + is_ip4=1, + vrf_id=0xFFFFFFFF): """Add/del S-NAT address range :param first_ip_address: First IP address :param last_ip_address: Last IP address + :param vrf_id: VRF id for the address range :param is_add: 1 if add, 0 if delete (Default value = 1) :param is_ip4: 1 if address type is IPv4 (Default value = 1) """ @@ -1036,6 +1038,7 @@ class VppPapiProvider(object): {'is_ip4': is_ip4, 'first_ip_address': first_ip_address, 'last_ip_address': last_ip_address, + 'vrf_id': vrf_id, 'is_add': is_add}) def snat_address_dump(self): |