Do not translate packets destined for NAT64 inside interface (VPP-1331) 84/13384/3
authorJuraj Sloboda <jsloboda@cisco.com>
Mon, 9 Jul 2018 00:36:37 +0000 (02:36 +0200)
committerDamjan Marion <dmarion@me.com>
Tue, 10 Jul 2018 10:10:05 +0000 (10:10 +0000)
Change-Id: Ieb8020f57ed5ad20daf552cd62ae3fdd8c573926
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
src/plugins/nat/nat64_in2out.c
test/test_nat.py

index 603b30e..6ff428b 100644 (file)
@@ -116,6 +116,26 @@ typedef struct nat64_in2out_set_ctx_t_
   u32 thread_index;
 } nat64_in2out_set_ctx_t;
 
+static inline u8
+nat64_not_translate (u32 sw_if_index, ip6_address_t ip6_addr)
+{
+  ip6_address_t *addr;
+  ip6_main_t *im6 = &ip6_main;
+  ip_lookup_main_t *lm6 = &im6->lookup_main;
+  ip_interface_address_t *ia = 0;
+
+  /* *INDENT-OFF* */
+  foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
+  ({
+       addr = ip_interface_address_get_address (lm6, ia);
+       if (0 == ip6_address_compare (addr, &ip6_addr))
+               return 1;
+  }));
+  /* *INDENT-ON* */
+
+  return 0;
+}
+
 /**
  * @brief Check whether is a hairpinning.
  *
@@ -927,6 +947,7 @@ nat64_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          u8 l4_protocol0;
          u32 proto0;
          nat64_in2out_set_ctx_t ctx0;
+         u32 sw_if_index0;
 
          /* speculatively enqueue b0 to the current next frame */
          bi0 = from[0];
@@ -955,6 +976,14 @@ nat64_in2out_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              goto trace0;
            }
 
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+         if (nat64_not_translate (sw_if_index0, ip60->dst_address))
+           {
+             next0 = NAT64_IN2OUT_NEXT_IP6_LOOKUP;
+             goto trace0;
+           }
+
          proto0 = ip_proto_to_snat_proto (l4_protocol0);
 
          if (is_slow_path)
index 35e89e3..4ae2850 100644 (file)
@@ -9,7 +9,8 @@ import random
 from framework import VppTestCase, VppTestRunner, running_extended_tests
 from scapy.layers.inet import IP, TCP, UDP, ICMP
 from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
-from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply
+from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest, ICMPv6EchoReply, \
+    ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddr
 from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
 from scapy.layers.l2 import Ether, ARP, GRE
 from scapy.data import IP_PROTOS
@@ -5189,7 +5190,7 @@ class TestNAT64(MethodHolder):
             cls.ipfix_src_port = 4739
             cls.ipfix_domain_id = 1
 
-            cls.create_pg_interfaces(range(5))
+            cls.create_pg_interfaces(range(6))
             cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
             cls.ip6_interfaces.append(cls.pg_interfaces[2])
             cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
@@ -5216,10 +5217,67 @@ class TestNAT64(MethodHolder):
             cls.pg3.config_ip6()
             cls.pg3.configure_ipv6_neighbors()
 
+            cls.pg5.admin_up()
+            cls.pg5.config_ip6()
+
         except Exception:
             super(TestNAT64, cls).tearDownClass()
             raise
 
+    def test_nat64_inside_interface_handles_neighbor_advertisement(self):
+        """ NAT64 inside interface handles Neighbor Advertisement """
+
+        self.vapi.nat64_add_del_interface(self.pg5.sw_if_index)
+
+        # Try to send ping
+        ping = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
+                IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
+                ICMPv6EchoRequest())
+        pkts = [ping]
+        self.pg5.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        # Wait for Neighbor Solicitation
+        capture = self.pg5.get_capture(len(pkts))
+        self.assertEqual(1, len(capture))
+        packet = capture[0]
+        try:
+            self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
+            self.assertTrue(packet.haslayer(ICMPv6ND_NS))
+            tgt = packet[ICMPv6ND_NS].tgt
+        except:
+            self.logger.error(ppp("Unexpected or invalid packet:", packet))
+            raise
+
+        # Send Neighbor Advertisement
+        p = (Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac) /
+             IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6) /
+             ICMPv6ND_NA(tgt=tgt) /
+             ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac))
+        pkts = [p]
+        self.pg5.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        # Try to send ping again
+        pkts = [ping]
+        self.pg5.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        # Wait for ping reply
+        capture = self.pg5.get_capture(len(pkts))
+        self.assertEqual(1, len(capture))
+        packet = capture[0]
+        try:
+            self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
+            self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
+            self.assertTrue(packet.haslayer(ICMPv6EchoReply))
+        except:
+            self.logger.error(ppp("Unexpected or invalid packet:", packet))
+            raise
+
     def test_pool(self):
         """ Add/delete address to NAT64 pool """
         nat_addr = socket.inet_pton(socket.AF_INET, '1.2.3.4')