diff options
author | Matus Fabian <matfabia@cisco.com> | 2017-12-18 05:38:24 -0800 |
---|---|---|
committer | Ole Trøan <otroan@employees.org> | 2017-12-19 10:34:07 +0000 |
commit | b932d26ea48ba8aa7677dc3b6ffd5d4729176c8f (patch) | |
tree | d4349f5f528814032502dac7fde65d16a44834cc /test | |
parent | f13f6a4dc9b68d6972ffbfb1dd94912d66887358 (diff) |
NAT: Twice NAT44 (VPP-969)
Translation of both source and destination addresses and ports for 1:1 NAT
session initiated from outside network (ExternalIP K8 use case).
Change-Id: Ic0000497cf71619aac996d6d580844f0ea0edc14
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/test_nat.py | 177 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 22 |
2 files changed, 190 insertions, 9 deletions
diff --git a/test/test_nat.py b/test/test_nat.py index 36163297961..1f87bffab57 100644 --- a/test/test_nat.py +++ b/test/test_nat.py @@ -737,7 +737,9 @@ class TestNAT44(MethodHolder): interfaces = self.vapi.nat44_interface_addr_dump() for intf in interfaces: - self.vapi.nat44_add_interface_addr(intf.sw_if_index, is_add=0) + self.vapi.nat44_add_interface_addr(intf.sw_if_index, + twice_nat=intf.twice_nat, + is_add=0) self.vapi.nat_ipfix(enable=0, src_port=self.ipfix_src_port, domain_id=self.ipfix_domain_id) @@ -770,6 +772,7 @@ class TestNAT44(MethodHolder): addr_only=sm.addr_only, vrf_id=sm.vrf_id, protocol=sm.protocol, + twice_nat=sm.twice_nat, is_add=0) lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump() @@ -778,7 +781,8 @@ class TestNAT44(MethodHolder): lb_sm.external_addr, lb_sm.external_port, lb_sm.protocol, - lb_sm.vrf_id, + vrf_id=lb_sm.vrf_id, + twice_nat=lb_sm.twice_nat, is_add=0, local_num=0, locals=[]) @@ -798,6 +802,7 @@ class TestNAT44(MethodHolder): for addr in adresses: self.vapi.nat44_add_del_address_range(addr.ip_address, addr.ip_address, + twice_nat=addr.twice_nat, is_add=0) self.vapi.nat_set_reass() @@ -806,7 +811,7 @@ class TestNAT44(MethodHolder): def nat44_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, - proto=0): + proto=0, twice_nat=0): """ Add/delete NAT44 static mapping @@ -818,6 +823,7 @@ class TestNAT44(MethodHolder): :param is_add: 1 if add, 0 if delete (Default add) :param external_sw_if_index: External interface instead of IP address :param proto: IP protocol (Mandatory if port specified) + :param twice_nat: 1 if translate external host address and port """ addr_only = 1 if local_port and external_port: @@ -833,18 +839,21 @@ class TestNAT44(MethodHolder): addr_only, vrf_id, proto, + twice_nat, is_add) - def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF): + def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0): """ Add/delete NAT44 address :param ip: IP address :param is_add: 1 if add, 0 if delete (Default add) + :param twice_nat: twice NAT address for extenal hosts """ nat_addr = socket.inet_pton(socket.AF_INET, ip) self.vapi.nat44_add_del_address_range(nat_addr, nat_addr, is_add, - vrf_id=vrf_id) + vrf_id=vrf_id, + twice_nat=twice_nat) def test_dynamic(self): """ NAT44 dynamic translation test """ @@ -2857,6 +2866,164 @@ class TestNAT44(MethodHolder): self.logger.error(ppp("Unexpected or invalid packet:", p)) raise + def test_twice_nat(self): + """ Twice NAT44 """ + twice_nat_addr = '10.0.1.3' + port_in = 8080 + port_out = 80 + eh_port_out = 4567 + eh_port_in = 0 + self.nat44_add_address(self.nat_addr) + self.nat44_add_address(twice_nat_addr, twice_nat=1) + self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr, + port_in, port_out, proto=IP_PROTOS.tcp, + twice_nat=1) + self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index, + is_inside=0) + + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=eh_port_out, dport=port_out)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + p = capture[0] + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.dst, self.pg0.remote_ip4) + self.assertEqual(ip.src, twice_nat_addr) + self.assertEqual(tcp.dport, port_in) + self.assertNotEqual(tcp.sport, eh_port_out) + eh_port_in = tcp.sport + self.check_tcp_checksum(p) + self.check_ip_checksum(p) + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise + + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=twice_nat_addr) / + TCP(sport=port_in, dport=eh_port_in)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + p = capture[0] + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.dst, self.pg1.remote_ip4) + self.assertEqual(ip.src, self.nat_addr) + self.assertEqual(tcp.dport, eh_port_out) + self.assertEqual(tcp.sport, port_out) + self.check_tcp_checksum(p) + self.check_ip_checksum(p) + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise + + def test_twice_nat_lb(self): + """ Twice NAT44 local service load balancing """ + external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr) + twice_nat_addr = '10.0.1.3' + local_port = 8080 + external_port = 80 + eh_port_out = 4567 + eh_port_in = 0 + server1 = self.pg0.remote_hosts[0] + server2 = self.pg0.remote_hosts[1] + + locals = [{'addr': server1.ip4n, + 'port': local_port, + 'probability': 50}, + {'addr': server2.ip4n, + 'port': local_port, + 'probability': 50}] + + self.nat44_add_address(self.nat_addr) + self.nat44_add_address(twice_nat_addr, twice_nat=1) + + self.vapi.nat44_add_del_lb_static_mapping(external_addr_n, + external_port, + IP_PROTOS.tcp, + twice_nat=1, + local_num=len(locals), + locals=locals) + self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index, + is_inside=0) + + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=eh_port_out, dport=external_port)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg0.get_capture(1) + p = capture[0] + server = None + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.src, twice_nat_addr) + self.assertIn(ip.dst, [server1.ip4, server2.ip4]) + if ip.dst == server1.ip4: + server = server1 + else: + server = server2 + self.assertNotEqual(tcp.sport, eh_port_out) + eh_port_in = tcp.sport + self.assertEqual(tcp.dport, local_port) + self.check_tcp_checksum(p) + self.check_ip_checksum(p) + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise + + p = (Ether(src=server.mac, dst=self.pg0.local_mac) / + IP(src=server.ip4, dst=twice_nat_addr) / + TCP(sport=local_port, dport=eh_port_in)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(1) + p = capture[0] + try: + ip = p[IP] + tcp = p[TCP] + self.assertEqual(ip.src, self.nat_addr) + self.assertEqual(ip.dst, self.pg1.remote_ip4) + self.assertEqual(tcp.sport, external_port) + self.assertEqual(tcp.dport, eh_port_out) + self.check_tcp_checksum(p) + self.check_ip_checksum(p) + except: + self.logger.error(ppp("Unexpected or invalid packet:", p)) + raise + + def test_twice_nat_interface_addr(self): + """ Acquire twice NAT44 addresses from interface """ + self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index, twice_nat=1) + + # no address in NAT pool + adresses = self.vapi.nat44_address_dump() + self.assertEqual(0, len(adresses)) + + # configure interface address and check NAT address pool + self.pg7.config_ip4() + adresses = self.vapi.nat44_address_dump() + self.assertEqual(1, len(adresses)) + self.assertEqual(adresses[0].ip_address[0:4], self.pg7.local_ip4n) + self.assertEqual(adresses[0].twice_nat, 1) + + # remove interface address and check NAT address pool + self.pg7.unconfig_ip4() + adresses = self.vapi.nat44_address_dump() + self.assertEqual(0, len(adresses)) + def tearDown(self): super(TestNAT44, self).tearDown() if not self.vpp_dead: diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 338ca27eaa1..3644d3c6779 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1222,6 +1222,7 @@ class VppPapiProvider(object): addr_only=1, vrf_id=0, protocol=0, + twice_nat=0, is_add=1): """Add/delete NAT44 static mapping @@ -1233,6 +1234,7 @@ class VppPapiProvider(object): :param addr_only: 1 if address only mapping, 0 if address and port :param vrf_id: VRF ID :param protocol: IP protocol (Default value = 0) + :param twice_nat: 1 if translate external host address and port :param is_add: 1 if add, 0 if delete (Default value = 1) """ return self.api( @@ -1245,7 +1247,8 @@ class VppPapiProvider(object): 'external_port': external_port, 'external_sw_if_index': external_sw_if_index, 'vrf_id': vrf_id, - 'protocol': protocol}) + 'protocol': protocol, + 'twice_nat': twice_nat}) def nat44_add_del_identity_mapping( self, @@ -1281,12 +1284,14 @@ class VppPapiProvider(object): first_ip_address, last_ip_address, is_add=1, - vrf_id=0xFFFFFFFF): + vrf_id=0xFFFFFFFF, + twice_nat=0): """Add/del NAT44 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 twice_nat: twice NAT address for extenal hosts :param is_add: 1 if add, 0 if delete (Default value = 1) """ return self.api( @@ -1294,6 +1299,7 @@ class VppPapiProvider(object): {'first_ip_address': first_ip_address, 'last_ip_address': last_ip_address, 'vrf_id': vrf_id, + 'twice_nat': twice_nat, 'is_add': is_add}) def nat44_address_dump(self): @@ -1335,14 +1341,19 @@ class VppPapiProvider(object): def nat44_add_interface_addr( self, sw_if_index, + twice_nat=0, is_add=1): """Add/del NAT44 address from interface :param sw_if_index: Software index of the interface + :param twice_nat: twice NAT address for extenal hosts :param is_add: 1 if add, 0 if delete (Default value = 1) """ - return self.api(self.papi.nat44_add_del_interface_addr, - {'is_add': is_add, 'sw_if_index': sw_if_index}) + return self.api( + self.papi.nat44_add_del_interface_addr, + {'is_add': is_add, + 'sw_if_index': sw_if_index, + 'twice_nat': twice_nat}) def nat44_interface_addr_dump(self): """Dump NAT44 addresses interfaces @@ -1396,11 +1407,13 @@ class VppPapiProvider(object): external_port, protocol, vrf_id=0, + twice_nat=0, local_num=0, locals=[], is_add=1): """Add/delete NAT44 load balancing static mapping + :param twice_nat: 1 if translate external host address and port :param is_add - 1 if add, 0 if delete """ return self.api( @@ -1410,6 +1423,7 @@ class VppPapiProvider(object): 'external_port': external_port, 'protocol': protocol, 'vrf_id': vrf_id, + 'twice_nat': twice_nat, 'local_num': local_num, 'locals': locals}) |