summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2017-12-18 05:38:24 -0800
committerOle Trøan <otroan@employees.org>2017-12-19 10:34:07 +0000
commitb932d26ea48ba8aa7677dc3b6ffd5d4729176c8f (patch)
treed4349f5f528814032502dac7fde65d16a44834cc /test
parentf13f6a4dc9b68d6972ffbfb1dd94912d66887358 (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.py177
-rw-r--r--test/vpp_papi_provider.py22
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})