NAT44: identity NAT (VPP-1073)

Identity mapping translate an IP address to itself.

Change-Id: Icc0ca5102d32547a4b0c75720b5f5bf41ed69c71
Signed-off-by: Matus Fabian <matfabia@cisco.com>
diff --git a/test/test_nat.py b/test/test_nat.py
index 6eb54dd..0448fae 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -783,6 +783,17 @@
                 local_num=0,
                 locals=[])
 
+        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        for id_m in identity_mappings:
+            self.vapi.nat44_add_del_identity_mapping(
+                addr_only=id_m.addr_only,
+                ip=id_m.ip_address,
+                port=id_m.port,
+                sw_if_index=id_m.sw_if_index,
+                vrf_id=id_m.vrf_id,
+                protocol=id_m.protocol,
+                is_add=0)
+
         adresses = self.vapi.nat44_address_dump()
         for addr in adresses:
             self.vapi.nat44_add_del_address_range(addr.ip_address,
@@ -1190,6 +1201,35 @@
         self.pg_start()
         self.pg3.assert_nothing_captured()
 
+    def test_identity_nat(self):
+        """ Identity NAT """
+
+        self.vapi.nat44_add_del_identity_mapping(ip=self.pg0.remote_ip4n)
+        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.pg0.remote_ip4) /
+             TCP(sport=12345, dport=56789))
+        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, self.pg1.remote_ip4)
+            self.assertEqual(tcp.dport, 56789)
+            self.assertEqual(tcp.sport, 12345)
+            self.check_tcp_checksum(p)
+            self.check_ip_checksum(p)
+        except:
+            self.logger.error(ppp("Unexpected or invalid packet:", p))
+            raise
+
     def test_static_lb(self):
         """ NAT44 local service load balancing """
         external_addr_n = socket.inet_pton(socket.AF_INET, self.nat_addr)
@@ -1785,6 +1825,38 @@
         static_mappings = self.vapi.nat44_static_mapping_dump()
         self.assertEqual(0, len(static_mappings))
 
+    def test_interface_addr_identity_nat(self):
+        """ Identity NAT with addresses from interface """
+
+        port = 53053
+        self.vapi.nat44_add_interface_addr(self.pg7.sw_if_index)
+        self.vapi.nat44_add_del_identity_mapping(
+            sw_if_index=self.pg7.sw_if_index,
+            port=port,
+            protocol=IP_PROTOS.tcp,
+            addr_only=0)
+
+        # identity mappings with external interface
+        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        self.assertEqual(1, len(identity_mappings))
+        self.assertEqual(self.pg7.sw_if_index,
+                         identity_mappings[0].sw_if_index)
+
+        # configure interface address and check identity mappings
+        self.pg7.config_ip4()
+        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        self.assertEqual(1, len(identity_mappings))
+        self.assertEqual(identity_mappings[0].ip_address,
+                         self.pg7.local_ip4n)
+        self.assertEqual(0xFFFFFFFF, identity_mappings[0].sw_if_index)
+        self.assertEqual(port, identity_mappings[0].port)
+        self.assertEqual(IP_PROTOS.tcp, identity_mappings[0].protocol)
+
+        # remove interface address and check identity mappings
+        self.pg7.unconfig_ip4()
+        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        self.assertEqual(0, len(identity_mappings))
+
     def test_ipfix_nat44_sess(self):
         """ IPFIX logging NAT44 session created/delted """
         self.ipfix_domain_id = 10
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 3dd3482..f8bca82 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -1247,6 +1247,35 @@
              'vrf_id': vrf_id,
              'protocol': protocol})
 
+    def nat44_add_del_identity_mapping(
+            self,
+            ip='0',
+            sw_if_index=0xFFFFFFFF,
+            port=0,
+            addr_only=1,
+            vrf_id=0,
+            protocol=0,
+            is_add=1):
+        """Add/delete NAT44 identity mapping
+
+        :param ip: IP address (Default value = 0)
+        :param sw_if_index: Interface instead of IP address
+        :param port: Port number (Default value = 0)
+        :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 is_add: 1 if add, 0 if delete (Default value = 1)
+        """
+        return self.api(
+            self.papi.nat44_add_del_identity_mapping,
+            {'is_add': is_add,
+             'addr_only': addr_only,
+             'ip_address': ip,
+             'port': port,
+             'sw_if_index': sw_if_index,
+             'vrf_id': vrf_id,
+             'protocol': protocol})
+
     def nat44_add_del_address_range(
             self,
             first_ip_address,
@@ -1291,6 +1320,12 @@
         """
         return self.api(self.papi.nat44_static_mapping_dump, {})
 
+    def nat44_identity_mapping_dump(self):
+        """Dump NAT44 identity mappings
+        :return: Dictionary of NAT44 identity mappings
+        """
+        return self.api(self.papi.nat44_identity_mapping_dump, {})
+
     def nat_show_config(self):
         """Show NAT plugin config
         :return: NAT plugin config parameters