Source Lookup progammable via API 11/8811/2
authorNeale Ranns <nranns@cisco.com>
Fri, 13 Oct 2017 12:15:07 +0000 (05:15 -0700)
committerDamjan Marion <dmarion.lists@gmail.com>
Sat, 14 Oct 2017 09:11:42 +0000 (09:11 +0000)
Change-Id: I5d5d4f22b6369d504455a644f73076d772fbcfb4
Signed-off-by: Neale Ranns <nranns@cisco.com>
12 files changed:
src/vnet/dpo/lookup_dpo.h
src/vnet/fib/fib_api.h
src/vnet/fib/fib_path.c
src/vnet/fib/fib_path.h
src/vnet/fib/fib_test.c
src/vnet/fib/fib_types.h
src/vnet/ip/ip.api
src/vnet/ip/ip_api.c
src/vnet/mpls/mpls_api.c
test/test_ip4.py
test/vpp_ip_route.py
test/vpp_papi_provider.py

index 7dfd038..4ebd605 100644 (file)
@@ -42,8 +42,8 @@ typedef enum lookup_table_t_ {
 } __attribute__ ((packed)) lookup_table_t;
 
 #define LOOKUP_TABLES {                                   \
-    [LOOKUP_INPUT_SRC_ADDR] = "table-input-interface",    \
-    [LOOKUP_INPUT_DST_ADDR] = "table-configured",         \
+    [LOOKUP_TABLE_FROM_INPUT_INTERFACE] = "table-input-interface",    \
+    [LOOKUP_TABLE_FROM_CONFIG] = "table-configured",         \
 }
 
 /**
index c369e8f..e5b94e1 100644 (file)
@@ -41,6 +41,7 @@ add_del_route_t_handler (u8 is_multipath,
                         u8 is_interface_rx,
                          u8 is_rpf_id,
                          u8 is_l2_bridged,
+                         u8 is_source_lookup,
                         u32 fib_index,
                         const fib_prefix_t * prefix,
                         dpo_proto_t next_hop_proto,
index 889d17d..7b713a4 100644 (file)
@@ -1054,6 +1054,8 @@ fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
        cfg_flags |= FIB_PATH_CFG_FLAG_EXCLUSIVE;
     if (rpath->frp_flags & FIB_ROUTE_PATH_DROP)
        cfg_flags |= FIB_PATH_CFG_FLAG_DROP;
+    if (rpath->frp_flags & FIB_ROUTE_PATH_SOURCE_LOOKUP)
+       cfg_flags |= FIB_PATH_CFG_FLAG_DEAG_SRC;
 
     return (cfg_flags);
 }
@@ -1695,16 +1697,20 @@ fib_path_resolve (fib_node_index_t path_index)
         * Resolve via a lookup DPO.
          * FIXME. control plane should add routes with a table ID
         */
+        lookup_input_t input;
         lookup_cast_t cast;
-        
+
         cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ?
                 LOOKUP_MULTICAST :
                 LOOKUP_UNICAST);
+        input = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DEAG_SRC ?
+                LOOKUP_INPUT_SRC_ADDR :
+                LOOKUP_INPUT_DST_ADDR);
 
         lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
                                            path->fp_nh_proto,
                                            cast,
-                                           LOOKUP_INPUT_DST_ADDR,
+                                           input,
                                            LOOKUP_TABLE_FROM_CONFIG,
                                            &path->fp_dpo);
        break;
index f986e43..3a0544c 100644 (file)
@@ -79,14 +79,13 @@ typedef enum fib_path_cfg_attribute_t_ {
      */
     FIB_PATH_CFG_ATTRIBUTE_LOCAL,
     /**
-     * The path is L2. i.e. the parameters therein are to be interpreted as
-     * pertaining to L2 config.
+     * The deag path does a source lookup
      */
-    FIB_PATH_CFG_ATTRIBUTE_L2,
+    FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC,
     /**
      * Marker. Add new types before this one, then update it.
      */
-    FIB_PATH_CFG_ATTRIBUTE_LAST = FIB_PATH_CFG_ATTRIBUTE_LOCAL,
+    FIB_PATH_CFG_ATTRIBUTE_LAST = FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC,
 } __attribute__ ((packed)) fib_path_cfg_attribute_t;
 
 /**
@@ -103,7 +102,7 @@ typedef enum fib_path_cfg_attribute_t_ {
     [FIB_PATH_CFG_ATTRIBUTE_ATTACHED] = "attached",    \
     [FIB_PATH_CFG_ATTRIBUTE_INTF_RX] = "interface-rx", \
     [FIB_PATH_CFG_ATTRIBUTE_RPF_ID] = "rpf-id",         \
-    [FIB_PATH_CFG_ATTRIBUTE_L2] = "l2",         \
+    [FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC] = "deag-src",     \
 }
 
 #define FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(_item) \
@@ -124,7 +123,7 @@ typedef enum fib_path_cfg_flags_t_ {
     FIB_PATH_CFG_FLAG_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_ATTACHED),
     FIB_PATH_CFG_FLAG_INTF_RX = (1 << FIB_PATH_CFG_ATTRIBUTE_INTF_RX),
     FIB_PATH_CFG_FLAG_RPF_ID = (1 << FIB_PATH_CFG_ATTRIBUTE_RPF_ID),
-    FIB_PATH_CFG_FLAG_L2 = (1 << FIB_PATH_CFG_ATTRIBUTE_L2),
+    FIB_PATH_CFG_FLAG_DEAG_SRC = (1 << FIB_PATH_CFG_ATTRIBUTE_DEAG_SRC),
 } __attribute__ ((packed)) fib_path_cfg_flags_t;
 
 
index 03c9ee7..da517b0 100644 (file)
@@ -3543,6 +3543,49 @@ fib_test_v4 (void)
             "4.4.4.4/32 is deag in %d %U",
              lkd->lkd_fib_index,
              format_dpo_id, dpo, 0);
+    FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
+            "4.4.4.4/32 is source deag in %d %U",
+             lkd->lkd_input,
+             format_dpo_id, dpo, 0);
+
+    fib_table_entry_delete(fib_index,
+                          &pfx_4_4_4_4_s_32,
+                          FIB_SOURCE_API);
+    FIB_TEST(FIB_NODE_INDEX_INVALID ==
+            fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
+            "4.4.4.4/32 removed");
+    vec_free(r_paths);
+
+    /*
+     * A route deag route in a source lookup table
+     */
+    fib_table_entry_path_add(fib_index,
+                            &pfx_4_4_4_4_s_32,
+                            FIB_SOURCE_API,
+                            FIB_ENTRY_FLAG_NONE,
+                            DPO_PROTO_IP4,
+                            &zero_addr,
+                            ~0,
+                            fib_index,
+                            1,
+                            NULL,
+                            FIB_ROUTE_PATH_SOURCE_LOOKUP);
+
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
+    FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
+
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
+    lkd = lookup_dpo_get(dpo->dpoi_index);
+
+    FIB_TEST((fib_index == lkd->lkd_fib_index),
+            "4.4.4.4/32 is deag in %d %U",
+             lkd->lkd_fib_index,
+             format_dpo_id, dpo, 0);
+    FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
+            "4.4.4.4/32 is source deag in %d %U",
+             lkd->lkd_input,
+             format_dpo_id, dpo, 0);
 
     fib_table_entry_delete(fib_index,
                           &pfx_4_4_4_4_s_32,
index b5d4ec9..7eadbb9 100644 (file)
@@ -303,6 +303,10 @@ typedef enum fib_route_path_flags_t_
      * A local path with a RPF-ID => multicast traffic
      */
     FIB_ROUTE_PATH_RPF_ID = (1 << 7),
+    /**
+     * A deag path using the packet's source not destination address.
+     */
+    FIB_ROUTE_PATH_SOURCE_LOOKUP = (1 << 8),
 } fib_route_path_flags_t;
 
 /**
index df9ce6e..f534166 100644 (file)
@@ -370,6 +370,9 @@ autoreply define sw_interface_ip6_set_link_local_address
     @param is_local - 
     @param is_classify - 
     @param is_multipath - Set to 1 if this is a multipath route, else 0
+    @param is_source_lookup - The the path is a deaggregate path (i.e. a lookup
+                             in another table) is the lookup on the packet's
+                             source address or destination.
     @param not_last - Is last or not last msg in group of multiple add/del msgs
     @param next_hop_weight - 
     @param dst_address_length - 
@@ -398,6 +401,7 @@ autoreply define ip_add_del_route
   u8 is_resolve_host;
   u8 is_resolve_attached;
   u8 is_l2_bridged;
+  u8 is_source_lookup;
   /* Is last/not-last message in group of multiple add/del messages. */
   u8 not_last;
   u8 next_hop_weight;
index f3712d3..8a3ceb2 100644 (file)
@@ -830,6 +830,7 @@ add_del_route_t_handler (u8 is_multipath,
                         u8 is_interface_rx,
                         u8 is_rpf_id,
                         u8 is_l2_bridged,
+                        u8 is_source_lookup,
                         u32 fib_index,
                         const fib_prefix_t * prefix,
                         dpo_proto_t next_hop_proto,
@@ -877,6 +878,8 @@ add_del_route_t_handler (u8 is_multipath,
     path_flags |= FIB_ROUTE_PATH_INTF_RX;
   if (is_rpf_id)
     path_flags |= FIB_ROUTE_PATH_RPF_ID;
+  if (is_source_lookup)
+    path_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
   if (is_multicast)
     entry_flags |= FIB_ENTRY_FLAG_MULTICAST;
 
@@ -1076,6 +1079,7 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
                                   mp->is_resolve_host,
                                   mp->is_resolve_attached, 0, 0,
                                   mp->is_l2_bridged,
+                                  mp->is_source_lookup,
                                   fib_index, &pfx, DPO_PROTO_IP4,
                                   &nh,
                                   ntohl (mp->next_hop_sw_if_index),
@@ -1136,6 +1140,7 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
                                   mp->is_resolve_host,
                                   mp->is_resolve_attached, 0, 0,
                                   mp->is_l2_bridged,
+                                  mp->is_source_lookup,
                                   fib_index, &pfx, DPO_PROTO_IP6,
                                   &nh, ntohl (mp->next_hop_sw_if_index),
                                   next_hop_fib_index,
index e41466e..c47e94d 100644 (file)
@@ -219,11 +219,21 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm,
        label_stack[ii] = ntohl (mp->mr_next_hop_out_label_stack[ii]);
     }
 
-  return (add_del_route_t_handler (mp->mr_is_multipath, mp->mr_is_add, 0,      // mp->is_drop,
+  /* *INDENT-OFF* */
+  return (add_del_route_t_handler (mp->mr_is_multipath, mp->mr_is_add,
+                                   0,  // mp->is_drop,
                                   0,   // mp->is_unreach,
                                   0,   // mp->is_prohibit,
                                   0,   // mp->is_local,
-                                  mp->mr_is_multicast, mp->mr_is_classify, mp->mr_classify_table_index, mp->mr_is_resolve_host, mp->mr_is_resolve_attached, mp->mr_is_interface_rx, mp->mr_is_rpf_id, 0,       // l2_bridged
+                                  mp->mr_is_multicast,
+                                   mp->mr_is_classify,
+                                   mp->mr_classify_table_index,
+                                   mp->mr_is_resolve_host,
+                                   mp->mr_is_resolve_attached,
+                                   mp->mr_is_interface_rx,
+                                   mp->mr_is_rpf_id,
+                                   0,  // l2_bridged
+                                   0,   // is source_lookup
                                   fib_index, &pfx,
                                   mp->mr_next_hop_proto,
                                   &nh, ntohl (mp->mr_next_hop_sw_if_index),
@@ -232,6 +242,7 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm,
                                   mp->mr_next_hop_preference,
                                   ntohl (mp->mr_next_hop_via_label),
                                   label_stack));
+  /* *INDENT-ON* */
 }
 
 void
index 5bd50ce..42fd116 100644 (file)
@@ -7,7 +7,7 @@ from framework import VppTestCase, VppTestRunner
 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
-    VppMplsTable
+    VppMplsTable, VppIpTable
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, Dot1Q, ARP
@@ -1119,5 +1119,113 @@ class TestIPPunt(VppTestCase):
                                    is_add=0)
 
 
+class TestIPDeag(VppTestCase):
+    """ IPv4 Deaggregate Routes """
+
+    def setUp(self):
+        super(TestIPDeag, self).setUp()
+
+        self.create_pg_interfaces(range(3))
+
+        for i in self.pg_interfaces:
+            i.admin_up()
+            i.config_ip4()
+            i.resolve_arp()
+
+    def tearDown(self):
+        super(TestIPDeag, self).tearDown()
+        for i in self.pg_interfaces:
+            i.unconfig_ip4()
+            i.admin_down()
+
+    def send_and_expect(self, input, pkts, output):
+        self.vapi.cli("clear trace")
+        input.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = output.get_capture(len(pkts))
+        return rx
+
+    def send_and_assert_no_replies(self, intf, pkts, remark):
+        self.vapi.cli("clear trace")
+        intf.add_stream(pkts)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        for i in self.pg_interfaces:
+            i.get_capture(0)
+            i.assert_nothing_captured(remark=remark)
+
+    def test_ip_deag(self):
+        """ IP Deag Routes """
+
+        #
+        # Create a table to be used for:
+        #  1 - another destination address lookup
+        #  2 - a source address lookup
+        #
+        table_dst = VppIpTable(self, 1)
+        table_src = VppIpTable(self, 2)
+        table_dst.add_vpp_config()
+        table_src.add_vpp_config()
+
+        #
+        # Add a route in the default table to point to a deag/
+        # second lookup in each of these tables
+        #
+        route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
+                                  [VppRoutePath("0.0.0.0",
+                                                0xffffffff,
+                                                nh_table_id=1)])
+        route_to_src = VppIpRoute(self, "1.1.1.2", 32,
+                                  [VppRoutePath("0.0.0.0",
+                                                0xffffffff,
+                                                nh_table_id=2,
+                                                is_source_lookup=1)])
+        route_to_dst.add_vpp_config()
+        route_to_src.add_vpp_config()
+
+        #
+        # packets to these destination are dropped, since they'll
+        # hit the respective default routes in the second table
+        #
+        p_dst = (Ether(src=self.pg0.remote_mac,
+                       dst=self.pg0.local_mac) /
+                 IP(src="5.5.5.5", dst="1.1.1.1") /
+                 TCP(sport=1234, dport=1234) /
+                 Raw('\xa5' * 100))
+        p_src = (Ether(src=self.pg0.remote_mac,
+                       dst=self.pg0.local_mac) /
+                 IP(src="2.2.2.2", dst="1.1.1.2") /
+                 TCP(sport=1234, dport=1234) /
+                 Raw('\xa5' * 100))
+        pkts_dst = p_dst * 257
+        pkts_src = p_src * 257
+
+        self.send_and_assert_no_replies(self.pg0, pkts_dst,
+                                        "IP in dst table")
+        self.send_and_assert_no_replies(self.pg0, pkts_src,
+                                        "IP in src table")
+
+        #
+        # add a route in the dst table to forward via pg1
+        #
+        route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
+                                  [VppRoutePath(self.pg1.remote_ip4,
+                                                self.pg1.sw_if_index)],
+                                  table_id=1)
+        route_in_dst.add_vpp_config()
+        self.send_and_expect(self.pg0, pkts_dst, self.pg1)
+
+        #
+        # add a route in the src table to forward via pg2
+        #
+        route_in_src = VppIpRoute(self, "2.2.2.2", 32,
+                                  [VppRoutePath(self.pg2.remote_ip4,
+                                                self.pg2.sw_if_index)],
+                                  table_id=2)
+        route_in_src.add_vpp_config()
+        self.send_and_expect(self.pg0, pkts_src, self.pg2)
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index e670230..7501146 100644 (file)
@@ -107,6 +107,7 @@ class VppRoutePath(object):
             is_interface_rx=0,
             is_resolve_host=0,
             is_resolve_attached=0,
+            is_source_lookup=0,
             proto=DpoProto.DPO_PROTO_IP4):
         self.nh_itf = nh_sw_if_index
         self.nh_table_id = nh_table_id
@@ -124,6 +125,7 @@ class VppRoutePath(object):
         self.is_resolve_host = is_resolve_host
         self.is_resolve_attached = is_resolve_attached
         self.is_interface_rx = is_interface_rx
+        self.is_source_lookup = is_source_lookup
         self.is_rpf_id = 0
         if rpf_id != 0:
             self.is_rpf_id = 1
@@ -197,6 +199,7 @@ class VppIpRoute(VppObject):
                     if path.proto == DpoProto.DPO_PROTO_ETHERNET else 0,
                     is_resolve_host=path.is_resolve_host,
                     is_resolve_attached=path.is_resolve_attached,
+                    is_source_lookup=path.is_source_lookup,
                     is_multipath=1 if len(self.paths) > 1 else 0)
         self._test.registry.register(self, self._test.logger)
 
index 3d6a318..f7047ea 100644 (file)
@@ -747,6 +747,7 @@ class VppPapiProvider(object):
             is_classify=0,
             is_multipath=0,
             is_l2_bridged=0,
+            is_source_lookup=0,
             not_last=0):
         """
 
@@ -766,6 +767,8 @@ class VppPapiProvider(object):
         :param is_multipath:  (Default value = 0)
         :param is_resolve_host:  (Default value = 0)
         :param is_resolve_attached:  (Default value = 0)
+        :param is_l2_bridged:  (Default value = 0)
+        :param is_source_lookup:  (Default value = 0)
         :param not_last:  (Default value = 0)
         :param next_hop_weight:  (Default value = 1)
 
@@ -788,6 +791,7 @@ class VppPapiProvider(object):
              'is_resolve_host': is_resolve_host,
              'is_resolve_attached': is_resolve_attached,
              'is_l2_bridged': is_l2_bridged,
+             'is_source_lookup': is_source_lookup,
              'not_last': not_last,
              'next_hop_weight': next_hop_weight,
              'dst_address_length': dst_address_length,