map: honor pre-resolve param in map-t 61/24961/3
authorAlexander Chernavin <achernavin@netgate.com>
Tue, 11 Feb 2020 14:57:09 +0000 (09:57 -0500)
committerOle Trøan <otroan@employees.org>
Thu, 20 Feb 2020 09:04:26 +0000 (09:04 +0000)
With this commit, forward the translated packet directly to the
specified next-hop if pre-resolve param is enabled in MAP-T.

Type: fix

Change-Id: Ie26080c7820318c7982599577a4af6e4d01a0574
Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
src/plugins/map/ip4_map.c
src/plugins/map/ip4_map_t.c
src/plugins/map/ip6_map.c
src/plugins/map/ip6_map_t.c
src/plugins/map/map.h
src/plugins/map/test/test_map.py

index 68c3d73..ea63901 100644 (file)
@@ -78,20 +78,6 @@ ip4_map_vtcfl (ip4_header_t * ip4, vlib_buffer_t * p)
   return (clib_host_to_net_u32 (vtcfl));
 }
 
-static_always_inline bool
-ip4_map_ip6_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip)
-{
-#ifdef MAP_SKIP_IP6_LOOKUP
-  if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP6].fei)
-    {
-      vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
-       pre_resolved[FIB_PROTOCOL_IP6].dpo.dpoi_index;
-      return (true);
-    }
-#endif
-  return (false);
-}
-
 /*
  * ip4_map_ttl
  */
index bb5aa45..e9882e7 100644 (file)
@@ -30,6 +30,7 @@ typedef enum
 typedef enum
 {
   IP4_MAPT_ICMP_NEXT_IP6_LOOKUP,
+  IP4_MAPT_ICMP_NEXT_IP6_REWRITE,
   IP4_MAPT_ICMP_NEXT_IP6_FRAG,
   IP4_MAPT_ICMP_NEXT_DROP,
   IP4_MAPT_ICMP_N_NEXT
@@ -38,6 +39,7 @@ typedef enum
 typedef enum
 {
   IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP,
+  IP4_MAPT_TCP_UDP_NEXT_IP6_REWRITE,
   IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG,
   IP4_MAPT_TCP_UDP_NEXT_DROP,
   IP4_MAPT_TCP_UDP_N_NEXT
@@ -46,6 +48,7 @@ typedef enum
 typedef enum
 {
   IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP,
+  IP4_MAPT_FRAGMENTED_NEXT_IP6_REWRITE,
   IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG,
   IP4_MAPT_FRAGMENTED_NEXT_DROP,
   IP4_MAPT_FRAGMENTED_N_NEXT
@@ -173,6 +176,11 @@ ip4_map_t_icmp (vlib_main_t * vm,
              vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP6_LOOKUP;
              next0 = IP4_MAPT_ICMP_NEXT_IP6_FRAG;
            }
+         else
+           {
+             next0 = ip4_map_ip6_lookup_bypass (p0, NULL) ?
+               IP4_MAPT_ICMP_NEXT_IP6_REWRITE : next0;
+           }
        err0:
          if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
            {
@@ -292,6 +300,11 @@ ip4_map_t_fragmented (vlib_main_t * vm,
                    IP_FRAG_NEXT_IP6_LOOKUP;
                  next0 = IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG;
                }
+             else
+               {
+                 next0 = ip4_map_ip6_lookup_bypass (p0, NULL) ?
+                   IP4_MAPT_FRAGMENTED_NEXT_IP6_REWRITE : next0;
+               }
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
@@ -458,6 +471,11 @@ ip4_map_t_tcp_udp (vlib_main_t * vm,
                    IP_FRAG_NEXT_IP6_LOOKUP;
                  next0 = IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG;
                }
+             else
+               {
+                 next0 = ip4_map_ip6_lookup_bypass (p0, NULL) ?
+                   IP4_MAPT_TCP_UDP_NEXT_IP6_REWRITE : next0;
+               }
            }
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                           to_next, n_left_to_next, pi0,
@@ -689,6 +707,7 @@ VLIB_REGISTER_NODE(ip4_map_t_fragmented_node) = {
   .n_next_nodes = IP4_MAPT_FRAGMENTED_N_NEXT,
   .next_nodes = {
       [IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP] = "ip6-lookup",
+      [IP4_MAPT_FRAGMENTED_NEXT_IP6_REWRITE] = "ip6-load-balance",
       [IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
       [IP4_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
   },
@@ -709,6 +728,7 @@ VLIB_REGISTER_NODE(ip4_map_t_icmp_node) = {
   .n_next_nodes = IP4_MAPT_ICMP_N_NEXT,
   .next_nodes = {
       [IP4_MAPT_ICMP_NEXT_IP6_LOOKUP] = "ip6-lookup",
+      [IP4_MAPT_ICMP_NEXT_IP6_REWRITE] = "ip6-load-balance",
       [IP4_MAPT_ICMP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
       [IP4_MAPT_ICMP_NEXT_DROP] = "error-drop",
   },
@@ -729,6 +749,7 @@ VLIB_REGISTER_NODE(ip4_map_t_tcp_udp_node) = {
   .n_next_nodes = IP4_MAPT_TCP_UDP_N_NEXT,
   .next_nodes = {
       [IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP] = "ip6-lookup",
+      [IP4_MAPT_TCP_UDP_NEXT_IP6_REWRITE] = "ip6-load-balance",
       [IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
       [IP4_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
   },
index 899371e..136f548 100644 (file)
@@ -155,20 +155,6 @@ ip6_map_security_check (map_domain_t * d, vlib_buffer_t * b0,
     }
 }
 
-static_always_inline bool
-ip6_map_ip4_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip)
-{
-#ifdef MAP_SKIP_IP6_LOOKUP
-  if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP4].fei)
-    {
-      vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
-       pre_resolved[FIB_PROTOCOL_IP4].dpo.dpoi_index;
-      return (true);
-    }
-#endif
-  return (false);
-}
-
 /*
  * ip6_map
  */
index 5a9c9af..01bf0f9 100644 (file)
@@ -31,6 +31,7 @@ typedef enum
 typedef enum
 {
   IP6_MAPT_ICMP_NEXT_IP4_LOOKUP,
+  IP6_MAPT_ICMP_NEXT_IP4_REWRITE,
   IP6_MAPT_ICMP_NEXT_IP4_FRAG,
   IP6_MAPT_ICMP_NEXT_DROP,
   IP6_MAPT_ICMP_N_NEXT
@@ -39,6 +40,7 @@ typedef enum
 typedef enum
 {
   IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP,
+  IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE,
   IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG,
   IP6_MAPT_TCP_UDP_NEXT_DROP,
   IP6_MAPT_TCP_UDP_N_NEXT
@@ -47,6 +49,7 @@ typedef enum
 typedef enum
 {
   IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP,
+  IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE,
   IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG,
   IP6_MAPT_FRAGMENTED_NEXT_DROP,
   IP6_MAPT_FRAGMENTED_N_NEXT
@@ -174,6 +177,11 @@ ip6_map_t_icmp (vlib_main_t * vm,
              vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP4_LOOKUP;
              next0 = IP6_MAPT_ICMP_NEXT_IP4_FRAG;
            }
+         else
+           {
+             next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
+               IP6_MAPT_ICMP_NEXT_IP4_REWRITE : next0;
+           }
        err0:
          if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
            {
@@ -274,8 +282,7 @@ ip6_map_t_fragmented (vlib_main_t * vm,
          n_left_from -= 1;
          to_next += 1;
          n_left_to_next -= 1;
-
-         next0 = IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP;
+         next0 = IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP;
          p0 = vlib_get_buffer (vm, pi0);
 
          if (map_ip6_to_ip4_fragmented (vm, p0))
@@ -293,6 +300,11 @@ ip6_map_t_fragmented (vlib_main_t * vm,
                    IP_FRAG_NEXT_IP4_LOOKUP;
                  next0 = IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG;
                }
+             else
+               {
+                 next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
+                   IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE : next0;
+               }
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
@@ -459,6 +471,11 @@ ip6_map_t_tcp_udp (vlib_main_t * vm,
                    IP_FRAG_NEXT_IP4_LOOKUP;
                  next0 = IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG;
                }
+             else
+               {
+                 next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
+                   IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE : next0;
+               }
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
@@ -679,6 +696,7 @@ VLIB_REGISTER_NODE(ip6_map_t_fragmented_node) = {
   .next_nodes =
   {
     [IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE] = "ip4-load-balance",
     [IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     [IP6_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
   },
@@ -700,6 +718,7 @@ VLIB_REGISTER_NODE(ip6_map_t_icmp_node) = {
   .next_nodes =
   {
     [IP6_MAPT_ICMP_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IP6_MAPT_ICMP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     [IP6_MAPT_ICMP_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     [IP6_MAPT_ICMP_NEXT_DROP] = "error-drop",
   },
@@ -721,6 +740,7 @@ VLIB_REGISTER_NODE(ip6_map_t_tcp_udp_node) = {
   .next_nodes =
   {
     [IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     [IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     [IP6_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
   },
index 1f51a59..16fc604 100644 (file)
@@ -494,6 +494,34 @@ map_mss_clamping (tcp_header_t * tcp, ip_csum_t * sum, u16 mss_clamping)
     }
 }
 
+static_always_inline bool
+ip4_map_ip6_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip)
+{
+#ifdef MAP_SKIP_IP6_LOOKUP
+  if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP6].fei)
+    {
+      vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
+       pre_resolved[FIB_PROTOCOL_IP6].dpo.dpoi_index;
+      return (true);
+    }
+#endif
+  return (false);
+}
+
+static_always_inline bool
+ip6_map_ip4_lookup_bypass (vlib_buffer_t * p0, ip4_header_t * ip)
+{
+#ifdef MAP_SKIP_IP6_LOOKUP
+  if (FIB_NODE_INDEX_INVALID != pre_resolved[FIB_PROTOCOL_IP4].fei)
+    {
+      vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
+       pre_resolved[FIB_PROTOCOL_IP4].dpo.dpoi_index;
+      return (true);
+    }
+#endif
+  return (false);
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index c64341b..fd8b168 100644 (file)
@@ -37,6 +37,8 @@ class TestMAP(VppTestCase):
         self.pg0.admin_up()
         self.pg0.config_ip4()
         self.pg0.resolve_arp()
+        self.pg0.generate_remote_hosts(2)
+        self.pg0.configure_ipv4_neighbors()
 
         # pg1 is 'outside' IPv6
         self.pg1.admin_up()
@@ -777,5 +779,86 @@ class TestMAP(VppTestCase):
         p6 = (p_ether6 / p_ip6 / payload)
         self.send_and_assert_no_replies(self.pg1, p6*1)
 
+    def test_map_t_pre_resolve(self):
+        """ MAP-T pre-resolve"""
+
+        # Add a domain that maps from pg0 to pg1
+        map_dst = '2001:db8::/32'
+        map_src = '1234:5678:90ab:cdef::/64'
+        ip4_pfx = '192.168.0.0/24'
+        tag = 'MAP-T Test Domain.'
+
+        self.vapi.map_add_domain(ip6_prefix=map_dst,
+                                 ip4_prefix=ip4_pfx,
+                                 ip6_src=map_src,
+                                 ea_bits_len=16,
+                                 psid_offset=6,
+                                 psid_length=4,
+                                 mtu=1500,
+                                 tag=tag)
+
+        # Enable MAP-T on interfaces.
+        self.vapi.map_if_enable_disable(is_enable=1,
+                                        sw_if_index=self.pg0.sw_if_index,
+                                        is_translation=1)
+        self.vapi.map_if_enable_disable(is_enable=1,
+                                        sw_if_index=self.pg1.sw_if_index,
+                                        is_translation=1)
+
+        # Enable pre-resolve option
+        self.vapi.map_param_add_del_pre_resolve(ip4_nh_address="10.1.2.3",
+                                                ip6_nh_address="4001::1",
+                                                is_add=1)
+
+        # Add a route to 4001::1 and expect the translated traffic to be
+        # sent via that route next-hop.
+        pre_res_route6 = VppIpRoute(self, "4001::1", 128,
+                                    [VppRoutePath(self.pg1.remote_hosts[2].ip6,
+                                                  self.pg1.sw_if_index)])
+        pre_res_route6.add_vpp_config()
+
+        # Add a route to 10.1.2.3 and expect the "untranslated" traffic to be
+        # sent via that route next-hop.
+        pre_res_route4 = VppIpRoute(self, "10.1.2.3", 32,
+                                    [VppRoutePath(self.pg0.remote_hosts[1].ip4,
+                                                  self.pg0.sw_if_index)])
+        pre_res_route4.add_vpp_config()
+
+        # Send an IPv4 packet that will be translated
+        p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
+        p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1')
+        payload = TCP(sport=0xabcd, dport=0xabcd)
+        p4 = (p_ether / p_ip4 / payload)
+
+        p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0",
+                              dst="2001:db8:1f0::c0a8:1:f") / payload)
+        p6_translated.hlim -= 1
+
+        rx = self.send_and_expect(self.pg0, p4*1, self.pg1)
+        for p in rx:
+            self.assertEqual(p[Ether].dst, self.pg1.remote_hosts[2].mac)
+            self.validate(p[1], p6_translated)
+
+        # Send back an IPv6 packet that will be "untranslated"
+        p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
+        p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f',
+                     dst='1234:5678:90ab:cdef:ac:1001:200:0')
+        p6 = (p_ether6 / p_ip6 / payload)
+
+        p4_translated = (IP(src='192.168.0.1',
+                            dst=self.pg0.remote_ip4) / payload)
+        p4_translated.id = 0
+        p4_translated.ttl -= 1
+
+        rx = self.send_and_expect(self.pg1, p6*1, self.pg0)
+        for p in rx:
+            self.assertEqual(p[Ether].dst, self.pg0.remote_hosts[1].mac)
+            self.validate(p[1], p4_translated)
+
+        # Cleanup pre-resolve option
+        self.vapi.map_param_add_del_pre_resolve(ip4_nh_address="10.1.2.3",
+                                                ip6_nh_address="4001::1",
+                                                is_add=0)
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)