Adjacency refinement; check the cover's interface against the adjacency's 16/5716/2
authorNeale Ranns <nranns@cisco.com>
Fri, 10 Mar 2017 19:53:27 +0000 (11:53 -0800)
committerOle Trøan <otroan@employees.org>
Fri, 17 Mar 2017 08:13:12 +0000 (08:13 +0000)
Change-Id: I3fa2f35056b74e479288bb956f2713f727a81c72
Signed-off-by: Neale Ranns <nranns@cisco.com>
src/vnet/fib/fib_entry_src_adj.c
src/vnet/fib/fib_test.c
test/test_neighbor.py

index 64f82a7..9990223 100644 (file)
@@ -48,7 +48,7 @@ fib_entry_src_adj_remove (fib_entry_src_t *src)
 
 /*
  * Source activate. 
- * Called when the source is teh new longer best source on the entry
+ * Called when the source is the new longer best source on the entry
  */
 static int
 fib_entry_src_adj_activate (fib_entry_src_t *src,
@@ -75,8 +75,8 @@ fib_entry_src_adj_activate (fib_entry_src_t *src,
                              fib_entry_get_index(fib_entry));
 
     /*
-     * if the ocver is attached then this adj source entry can install, 
-     * via the adj. otherwise install a drop.
+     * if the cover is attached on the same interface as this adj source then
+     * install the FIB entry via the adj. otherwise install a drop.
      * This prevents ARP/ND entries that on interface X that do not belong
      * on X's subnet from being added to the FIB. To do so would allow
      * nefarious gratuitous ARP requests from attracting traffic to the sender.
@@ -86,7 +86,33 @@ fib_entry_src_adj_activate (fib_entry_src_t *src,
      *   ip route add 10.0.0.0/24 Eth0
      * is attached. and we want adj-fibs to install on Eth0.
      */
-    return (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover));
+    if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
+    {
+        u32 cover_itf = fib_entry_get_resolving_interface(src->adj.fesa_cover);
+        u32 adj_itf = fib_path_list_get_resolving_interface(src->fes_pl);
+
+        if (cover_itf == adj_itf)
+        {
+            return (1);
+        }
+        else
+        {
+            /*
+             * if the interface the adj is on is unnumbered to the
+             * cover's, then allow that too.
+             */
+            vnet_sw_interface_t *swif;
+
+            swif = vnet_get_sw_interface (vnet_get_main(), adj_itf);
+
+            if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
+                cover_itf == swif->unnumbered_sw_if_index)
+            {
+                return (1);
+            }
+        }
+    }
+    return (0);
 }
 
 /*
index 1c4a63a..1a9cce2 100644 (file)
@@ -3556,6 +3556,73 @@ fib_test_v4 (void)
 
     fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
 
+    /*
+     * An adj-fib that fails the refinement criteria - no connected cover
+     */
+    fib_prefix_t pfx_12_10_10_2_s_32 = {
+       .fp_len = 32,
+       .fp_proto = FIB_PROTOCOL_IP4,
+       .fp_addr = {
+           /* 12.10.10.2 */
+           .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
+       },
+    };
+
+    fib_table_entry_update_one_path(fib_index,
+                                   &pfx_12_10_10_2_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_ATTACHED,
+                                   FIB_PROTOCOL_IP4,
+                                   &pfx_12_10_10_2_s_32.fp_addr,
+                                   tm->hw[0]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    FIB_TEST(!dpo_id_is_valid(dpo),
+            "no connected cover adj-fib fails refinement");
+
+    fib_table_entry_delete(fib_index,
+                          &pfx_12_10_10_2_s_32,
+                          FIB_SOURCE_ADJ);
+
+    /*
+     * An adj-fib that fails the refinement criteria - cover is connected
+     * but on a different interface
+     */
+    fib_prefix_t pfx_10_10_10_127_s_32 = {
+       .fp_len = 32,
+       .fp_proto = FIB_PROTOCOL_IP4,
+       .fp_addr = {
+           /* 10.10.10.127 */
+           .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
+       },
+    };
+
+    fib_table_entry_update_one_path(fib_index,
+                                   &pfx_10_10_10_127_s_32,
+                                   FIB_SOURCE_ADJ,
+                                   FIB_ENTRY_FLAG_ATTACHED,
+                                   FIB_PROTOCOL_IP4,
+                                   &pfx_10_10_10_127_s_32.fp_addr,
+                                   tm->hw[1]->sw_if_index,
+                                   ~0, // invalid fib index
+                                   1,
+                                   NULL,
+                                   FIB_ROUTE_PATH_FLAG_NONE);
+
+    fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
+    dpo = fib_entry_contribute_ip_forwarding(fei);
+    FIB_TEST(!dpo_id_is_valid(dpo),
+            "wrong interface adj-fib fails refinement");
+
+    fib_table_entry_delete(fib_index,
+                          &pfx_10_10_10_127_s_32,
+                          FIB_SOURCE_ADJ);
+
     /*
      * CLEANUP
      *    remove adj-fibs: 
index 1dfae24..a97a63f 100644 (file)
@@ -115,7 +115,7 @@ class ARPTestCase(VppTestCase):
         #
         # Generate some hosts on the LAN
         #
-        self.pg1.generate_remote_hosts(5)
+        self.pg1.generate_remote_hosts(6)
 
         #
         # Send IP traffic to one of these unresolved hosts.
@@ -250,6 +250,57 @@ class ARPTestCase(VppTestCase):
                                  self.pg1.sw_if_index,
                                  self.pg1._remote_hosts[3].ip4))
 
+        #
+        # A neighbor entry that has no associated FIB-entry
+        #
+        arp_no_fib = VppNeighbor(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1.remote_hosts[4].mac,
+                                 self.pg1.remote_hosts[4].ip4,
+                                 is_no_fib_entry=1)
+        arp_no_fib.add_vpp_config()
+
+        #
+        # check we have the neighbor, but no route
+        #
+        self.assertTrue(find_nbr(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1._remote_hosts[4].ip4))
+        self.assertFalse(find_route(self,
+                                    self.pg1._remote_hosts[4].ip4,
+                                    32))
+        #
+        # Unnumbered pg2 to pg1
+        #
+        self.pg2.set_unnumbered(self.pg1.sw_if_index)
+
+        #
+        # now we can form adjacencies out of pg2 from within pg1's subnet
+        #
+        arp_unnum = VppNeighbor(self,
+                                self.pg2.sw_if_index,
+                                self.pg1.remote_hosts[5].mac,
+                                self.pg1.remote_hosts[5].ip4)
+        arp_unnum.add_vpp_config()
+
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IP(src=self.pg0.remote_ip4,
+                dst=self.pg1._remote_hosts[5].ip4) /
+             UDP(sport=1234, dport=1234) /
+             Raw())
+
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        rx = self.pg2.get_capture(1)
+
+        self.verify_ip(rx[0],
+                       self.pg2.local_mac,
+                       self.pg1.remote_hosts[5].mac,
+                       self.pg0.remote_ip4,
+                       self.pg1._remote_hosts[5].ip4)
+
         #
         # ERROR Cases
         #  1 - don't respond to ARP request for address not within the
@@ -301,29 +352,11 @@ class ARPTestCase(VppTestCase):
                                         "ARP req for non-local source")
 
         #
-        # A neighbor entry that has no associated FIB-entry
-        #
-        arp_no_fib = VppNeighbor(self,
-                                 self.pg1.sw_if_index,
-                                 self.pg1.remote_hosts[4].mac,
-                                 self.pg1.remote_hosts[4].ip4,
-                                 is_no_fib_entry=1)
-        arp_no_fib.add_vpp_config()
-
-        #
-        # check we have the neighbor, but no route
-        #
-        self.assertTrue(find_nbr(self,
-                                 self.pg1.sw_if_index,
-                                 self.pg1._remote_hosts[4].ip4))
-        self.assertFalse(find_route(self,
-                                    self.pg1._remote_hosts[4].ip4,
-                                    32))
-        #
         # cleanup
         #
         dyn_arp.remove_vpp_config()
         static_arp.remove_vpp_config()
+        self.pg2.unset_unnumbered(self.pg1.sw_if_index)
 
     def test_proxy_arp(self):
         """ Proxy ARP """