From 6c57a4a985a1e4a49d1aeaf2684166cf2e122cfb Mon Sep 17 00:00:00 2001 From: Dmitry Vakhrushev Date: Tue, 20 Aug 2019 14:44:51 -0400 Subject: nat: fix update of outside fibs (output-feature) NAT hasn't worked when NAT interfaces wasn't in default VRF (fib_index = 0). This issue has been occurred with interfaces with output-feature in endpoint-dependent mode. Update VAT commands: - update nat44_add_del_address_range - add nat44_interface_add_del_output_feature Ticket: VPP-1732 Type: fix Change-Id: Iddea15dde4b948f159a0056d48c55bd917037fd1 Signed-off-by: Dmitry Vakhrushev --- src/plugins/nat/nat.c | 10 ++++ src/plugins/nat/nat_test.c | 71 ++++++++++++++++++++++- src/plugins/nat/test/test_nat.py | 121 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 198 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 248cd759414..85072bcda31 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -2199,6 +2199,16 @@ snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index, match = 1; } })); + + pool_foreach (i, sm->output_feature_interfaces, + ({ + if (i->sw_if_index == sw_if_index) + { + if (!(nat_interface_is_outside (i))) + return; + match = 1; + } + })); /* *INDENT-ON* */ if (!match) diff --git a/src/plugins/nat/nat_test.c b/src/plugins/nat/nat_test.c index 1dd25b31205..685f85b92e7 100644 --- a/src/plugins/nat/nat_test.c +++ b/src/plugins/nat/nat_test.c @@ -64,6 +64,7 @@ snat_test_main_t snat_test_main; #define foreach_standard_reply_retval_handler \ _(nat44_add_del_address_range_reply) \ _(nat44_interface_add_del_feature_reply) \ +_(nat44_interface_add_del_output_feature_reply) \ _(nat44_add_del_static_mapping_reply) \ _(nat_set_workers_reply) \ _(nat44_add_del_interface_addr_reply) \ @@ -98,6 +99,8 @@ _(NAT44_ADD_DEL_ADDRESS_RANGE_REPLY, \ nat44_add_del_address_range_reply) \ _(NAT44_INTERFACE_ADD_DEL_FEATURE_REPLY, \ nat44_interface_add_del_feature_reply) \ +_(NAT44_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY, \ + nat44_interface_add_del_output_feature_reply) \ _(NAT44_ADD_DEL_STATIC_MAPPING_REPLY, \ nat44_add_del_static_mapping_reply) \ _(NAT_CONTROL_PING_REPLY, nat_control_ping_reply) \ @@ -133,6 +136,8 @@ static int api_nat44_add_del_address_range (vat_main_t * vam) u32 start_host_order, end_host_order; vl_api_nat44_add_del_address_range_t * mp; u8 is_add = 1; + u8 twice_nat = 0; + int vrf_id = ~0; int count; int ret; @@ -144,6 +149,10 @@ static int api_nat44_add_del_address_range (vat_main_t * vam) ; else if (unformat (i, "%U", unformat_ip4_address, &start_addr)) end_addr = start_addr; + else if (unformat (i, "twice-nat")) + twice_nat = 1; + else if (unformat (i, "vrf %u", &vrf_id)) + ; else if (unformat (i, "del")) is_add = 0; else @@ -176,6 +185,9 @@ static int api_nat44_add_del_address_range (vat_main_t * vam) memcpy (mp->first_ip_address, &start_addr, 4); memcpy (mp->last_ip_address, &end_addr, 4); + mp->vrf_id = vrf_id; + if (twice_nat) + mp->flags = (vl_api_nat_config_flags_t)NAT_API_IS_TWICE_NAT; mp->is_add = is_add; S(mp); @@ -229,6 +241,52 @@ static int api_nat44_interface_add_del_feature (vat_main_t * vam) return ret; } +static int api_nat44_interface_add_del_output_feature (vat_main_t * vam) +{ + unformat_input_t * i = vam->input; + vl_api_nat44_interface_add_del_output_feature_t * mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_inside = 1; + u8 is_add = 1; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "out")) + is_inside = 0; + else if (unformat (i, "in")) + is_inside = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("interface / sw_if_index required\n"); + return -99; + } + + M(NAT44_INTERFACE_ADD_DEL_OUTPUT_FEATURE, mp); + mp->sw_if_index = ntohl(sw_if_index); + mp->is_add = is_add; + if (is_inside) + mp->flags |= NAT_API_IS_INSIDE; + + S(mp); + W (ret); + return ret; +} + static int api_nat44_add_del_static_mapping(vat_main_t * vam) { unformat_input_t * i = vam->input; @@ -578,6 +636,7 @@ static int api_nat44_add_del_interface_addr (vat_main_t * vam) u32 sw_if_index; u8 sw_if_index_set = 0; u8 is_add = 1; + u8 twice_nat = 0; int ret; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) @@ -586,6 +645,8 @@ static int api_nat44_add_del_interface_addr (vat_main_t * vam) sw_if_index_set = 1; else if (unformat (i, "sw_if_index %d", &sw_if_index)) sw_if_index_set = 1; + else if (unformat (i, "twice-nat")) + twice_nat = 1; else if (unformat (i, "del")) is_add = 0; else @@ -603,7 +664,8 @@ static int api_nat44_add_del_interface_addr (vat_main_t * vam) M(NAT44_ADD_DEL_INTERFACE_ADDR, mp); mp->sw_if_index = ntohl(sw_if_index); - + if (twice_nat) + mp->flags = (vl_api_nat_config_flags_t)NAT_API_IS_TWICE_NAT; mp->is_add = is_add; S(mp); @@ -1099,9 +1161,12 @@ static int api_nat_det_session_dump(vat_main_t * vam) * and that the data plane plugin processes */ #define foreach_vpe_api_msg \ -_(nat44_add_del_address_range, " [- [- ] [vrf ] [twice-nat] [del]") \ _(nat44_interface_add_del_feature, \ " | sw_if_index [in] [out] [del]") \ +_(nat44_interface_add_del_output_feature, \ + " | sw_if_index [in] [out] [del]") \ _(nat44_add_del_static_mapping, "local_addr " \ " (external_addr | external_if |" \ " external_sw_if_ndex ) [local_port ]" \ @@ -1113,7 +1178,7 @@ _(nat44_address_dump, "") \ _(nat44_interface_dump, "") \ _(nat_worker_dump, "") \ _(nat44_add_del_interface_addr, \ - " | sw_if_index [del]") \ + " | sw_if_index [twice-nat] [del]") \ _(nat44_interface_addr_dump, "") \ _(nat_ipfix_enable_disable, "[domain ] [src_port ] " \ "[disable]") \ diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py index 4d48ee494c6..ad44dbd69bd 100644 --- a/src/plugins/nat/test/test_nat.py +++ b/src/plugins/nat/test/test_nat.py @@ -4414,7 +4414,7 @@ class TestNAT44EndpointDependent(MethodHolder): cls.ipfix_domain_id = 1 cls.tcp_external_port = 80 - cls.create_pg_interfaces(range(7)) + cls.create_pg_interfaces(range(9)) cls.interfaces = list(cls.pg_interfaces[0:3]) for i in cls.interfaces: @@ -4493,6 +4493,16 @@ class TestNAT44EndpointDependent(MethodHolder): cls.pg5.resolve_arp() cls.pg6.resolve_arp() + cls.pg7.admin_up() + cls.pg7.config_ip4() + cls.pg7.resolve_arp() + cls.pg7.generate_remote_hosts(3) + cls.pg7.configure_ipv4_neighbors() + + cls.pg8.admin_up() + cls.pg8.config_ip4() + cls.pg8.resolve_arp() + except Exception: super(TestNAT44EndpointDependent, cls).tearDownClass() raise @@ -4767,6 +4777,115 @@ class TestNAT44EndpointDependent(MethodHolder): sessions = self.statistics.get_counter('/nat44/total-sessions') self.assertEqual(sessions[0][0], 3) + def test_dynamic_output_feature_vrf(self): + """ NAT44 dynamic translation test: output-feature, VRF""" + + # other then default (0) + new_vrf_id = 22 + + self.nat44_add_address(self.nat_addr) + flags = self.config_flags.NAT_IS_INSIDE + self.vapi.nat44_interface_add_del_output_feature( + sw_if_index=self.pg7.sw_if_index, + flags=flags, is_add=1) + self.vapi.nat44_interface_add_del_output_feature( + sw_if_index=self.pg8.sw_if_index, + is_add=1) + + try: + self.vapi.ip_table_add_del(is_add=1, table_id=new_vrf_id) + + self.pg7.unconfig_ip4() + self.pg7.set_table_ip4(new_vrf_id) + self.pg7.config_ip4() + self.pg7.resolve_arp() + + self.pg8.unconfig_ip4() + self.pg8.set_table_ip4(new_vrf_id) + self.pg8.config_ip4() + self.pg8.resolve_arp() + + nat_config = self.vapi.nat_show_config() + self.assertEqual(1, nat_config.endpoint_dependent) + + # in2out + tcpn = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/TCP packets') + udpn = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/UDP packets') + icmpn = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/ICMP packets') + totaln = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/good in2out packets processed') + + pkts = self.create_stream_in(self.pg7, self.pg8) + self.pg7.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg8.get_capture(len(pkts)) + self.verify_capture_out(capture) + + err = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/TCP packets') + self.assertEqual(err - tcpn, 1) + err = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/UDP packets') + self.assertEqual(err - udpn, 1) + err = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/ICMP packets') + self.assertEqual(err - icmpn, 1) + err = self.statistics.get_err_counter( + '/err/nat44-ed-in2out-slowpath/good in2out packets processed') + self.assertEqual(err - totaln, 3) + + # out2in + tcpn = self.statistics.get_err_counter( + '/err/nat44-ed-out2in/TCP packets') + udpn = self.statistics.get_err_counter( + '/err/nat44-ed-out2in/UDP packets') + icmpn = self.statistics.get_err_counter( + '/err/nat44-ed-out2in-slowpath/ICMP packets') + totaln = self.statistics.get_err_counter( + '/err/nat44-ed-out2in/good out2in packets processed') + + pkts = self.create_stream_out(self.pg8) + self.pg8.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg7.get_capture(len(pkts)) + self.verify_capture_in(capture, self.pg7) + + err = self.statistics.get_err_counter( + '/err/nat44-ed-out2in/TCP packets') + self.assertEqual(err - tcpn, 1) + err = self.statistics.get_err_counter( + '/err/nat44-ed-out2in/UDP packets') + self.assertEqual(err - udpn, 1) + err = self.statistics.get_err_counter( + '/err/nat44-ed-out2in-slowpath/ICMP packets') + self.assertEqual(err - icmpn, 1) + err = self.statistics.get_err_counter( + '/err/nat44-ed-out2in/good out2in packets processed') + self.assertEqual(err - totaln, 2) + + users = self.statistics.get_counter('/nat44/total-users') + self.assertEqual(users[0][0], 1) + sessions = self.statistics.get_counter('/nat44/total-sessions') + self.assertEqual(sessions[0][0], 3) + + finally: + self.pg7.unconfig_ip4() + self.pg7.set_table_ip4(1) + self.pg7.config_ip4() + self.pg7.resolve_arp() + + self.pg8.unconfig_ip4() + self.pg8.set_table_ip4(1) + self.pg8.config_ip4() + self.pg8.resolve_arp() + + self.vapi.ip_table_add_del(is_add=0, table_id=new_vrf_id) + def test_forwarding(self): """ NAT44 forwarding test """ -- cgit 1.2.3-korg