Sub-net broadcast addresses for IPv4 95/5895/2
authorNeale Ranns <nranns@cisco.com>
Sun, 26 Mar 2017 17:56:33 +0000 (10:56 -0700)
committerDamjan Marion <dmarion.lists@gmail.com>
Wed, 29 Mar 2017 12:06:13 +0000 (12:06 +0000)
Change-Id: Ib2189d01e8bc61de57404159690fb70f89c47277
Signed-off-by: Neale Ranns <nranns@cisco.com>
src/vnet/classify/vnet_classify.c
src/vnet/fib/fib_entry_src_interface.c
src/vnet/ip/ip4_forward.c
test/framework.py
test/test_ip4.py

index b651a1f..98842a4 100644 (file)
@@ -1499,7 +1499,7 @@ static u8 * format_vnet_classify_table (u8 * s, va_list * args)
   s = format (s, "%10u%10d%10d%10d", index, t->active_elements,
               t->next_table_index, t->miss_next_index);
 
-  s = format (s, "\n  Heap: %U", format_mheap, t->mheap, 0 /*verbose*/); 
+  s = format (s, "\n  Heap: %U", format_mheap, t->mheap, 0 /*verbose*/);
 
   s = format (s, "\n  nbuckets %d, skip %d match %d flag %d offset %d",
               t->nbuckets, t->skip_n_vectors, t->match_n_vectors,
index ca04716..bb87818 100644 (file)
@@ -31,6 +31,25 @@ fib_entry_src_interface_init (fib_entry_src_t *src)
     src->interface.fesi_sibling = FIB_NODE_INDEX_INVALID;
 }
 
+static void
+fib_entry_src_interface_add (fib_entry_src_t *src,
+                             const fib_entry_t *entry,
+                             fib_entry_flag_t flags,
+                             fib_protocol_t proto,
+                             const dpo_id_t *dpo)
+{
+    src->fes_pl = fib_path_list_create_special(
+                      proto,
+                      fib_entry_src_flags_2_path_list_flags(flags),
+                      dpo);
+}
+
+static void
+fib_entry_src_interface_remove (fib_entry_src_t *src)
+{
+    src->fes_pl = FIB_NODE_INDEX_INVALID;
+}
+
 static void
 fib_entry_src_interface_path_swap (fib_entry_src_t *src,
                                   const fib_entry_t *entry,
@@ -176,6 +195,8 @@ fib_entry_src_interface_format (fib_entry_src_t *src,
 
 const static fib_entry_src_vft_t interface_src_vft = {
     .fesv_init = fib_entry_src_interface_init,
+    .fesv_add = fib_entry_src_interface_add,
+    .fesv_remove = fib_entry_src_interface_remove,
     .fesv_path_swap = fib_entry_src_interface_path_swap,
     .fesv_activate = fib_entry_src_interface_activate,
     .fesv_deactivate = fib_entry_src_interface_deactivate,
index f2bc2a7..bbba4b7 100644 (file)
@@ -745,8 +745,9 @@ ip4_add_interface_routes (u32 sw_if_index,
 
   a->neighbor_probe_adj_index = ~0;
 
-  if (pfx.fp_len < 32)
+  if (pfx.fp_len <= 30)
     {
+      /* a /30 or shorter - add a glean for the network address */
       fib_node_index_t fei;
 
       fei = fib_table_entry_update_one_path (fib_index, &pfx,
@@ -764,8 +765,50 @@ ip4_add_interface_routes (u32 sw_if_index,
                                              NULL,
                                             FIB_ROUTE_PATH_FLAG_NONE);
       a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
-    }
 
+      /* Add the two broadcast addresses as drop */
+      fib_prefix_t net_pfx = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
+      };
+      if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
+        fib_table_entry_special_add(fib_index,
+                                    &net_pfx,
+                                    FIB_SOURCE_INTERFACE,
+                                    (FIB_ENTRY_FLAG_DROP |
+                                     FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
+                                    ADJ_INDEX_INVALID);
+      net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
+      if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
+        fib_table_entry_special_add(fib_index,
+                                    &net_pfx,
+                                    FIB_SOURCE_INTERFACE,
+                                    (FIB_ENTRY_FLAG_DROP |
+                                     FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
+                                    ADJ_INDEX_INVALID);
+    }
+  else if (pfx.fp_len == 31)
+    {
+      u32 mask = clib_host_to_net_u32(1);
+      fib_prefix_t net_pfx = pfx;
+
+      net_pfx.fp_len = 32;
+      net_pfx.fp_addr.ip4.as_u32 ^= mask;
+
+      /* a /31 - add the other end as an attached host */
+      fib_table_entry_update_one_path (fib_index, &net_pfx,
+                                       FIB_SOURCE_INTERFACE,
+                                       (FIB_ENTRY_FLAG_ATTACHED),
+                                       FIB_PROTOCOL_IP4,
+                                       &net_pfx.fp_addr,
+                                       sw_if_index,
+                                       // invalid FIB index
+                                       ~0,
+                                       1,
+                                       NULL,
+                                       FIB_ROUTE_PATH_FLAG_NONE);
+    }
   pfx.fp_len = 32;
 
   if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
@@ -813,10 +856,34 @@ ip4_del_interface_routes (ip4_main_t * im,
     .fp_addr.ip4 = *address,
   };
 
-  if (pfx.fp_len < 32)
+  if (pfx.fp_len <= 30)
     {
+      fib_prefix_t net_pfx = {
+        .fp_len = 32,
+        .fp_proto = FIB_PROTOCOL_IP4,
+        .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
+      };
+      if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
+        fib_table_entry_special_remove(fib_index,
+                                       &net_pfx,
+                                       FIB_SOURCE_INTERFACE);
+      net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
+      if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
+        fib_table_entry_special_remove(fib_index,
+                                       &net_pfx,
+                                       FIB_SOURCE_INTERFACE);
       fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
     }
+    else if (pfx.fp_len == 31)
+    {
+      u32 mask = clib_host_to_net_u32(1);
+      fib_prefix_t net_pfx = pfx;
+
+      net_pfx.fp_len = 32;
+      net_pfx.fp_addr.ip4.as_u32 ^= mask;
+
+      fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
+    }
 
   pfx.fp_len = 32;
   fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
index eb3a9d7..fbd21d2 100644 (file)
@@ -359,7 +359,7 @@ class VppTestCase(unittest.TestCase):
                            self._testMethodDoc))
         if not self.vpp_dead:
             self.logger.debug(self.vapi.cli("show trace"))
-            self.logger.info(self.vapi.ppcli("show int"))
+            self.logger.info(self.vapi.ppcli("show interfaces"))
             self.logger.info(self.vapi.ppcli("show hardware"))
             self.logger.info(self.vapi.ppcli("show error"))
             self.logger.info(self.vapi.ppcli("show run"))
index 79af549..ed364b6 100644 (file)
@@ -9,7 +9,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags
 
 from scapy.packet import Raw
-from scapy.layers.l2 import Ether, Dot1Q
+from scapy.layers.l2 import Ether, Dot1Q, ARP
 from scapy.layers.inet import IP, UDP, ICMP, icmptypes, icmpcodes
 from util import ppp
 
@@ -643,5 +643,128 @@ class TestIPDisabled(VppTestCase):
         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
 
 
+class TestIPSubNets(VppTestCase):
+    """ IPv4 Subnets """
+
+    def setUp(self):
+        super(TestIPSubNets, self).setUp()
+
+        # create a 2 pg interfaces
+        self.create_pg_interfaces(range(2))
+
+        # pg0 we will use to experiemnt
+        self.pg0.admin_up()
+
+        # pg1 is setup normally
+        self.pg1.admin_up()
+        self.pg1.config_ip4()
+        self.pg1.resolve_arp()
+
+    def tearDown(self):
+        super(TestIPSubNets, self).tearDown()
+        for i in self.pg_interfaces:
+            i.admin_down()
+
+    def send_and_assert_no_replies(self, intf, pkts, remark):
+        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_sub_nets(self):
+        """ IP Sub Nets """
+
+        #
+        # Configure a covering route to forward so we know
+        # when we are dropping
+        #
+        cover_route = VppIpRoute(self, "10.0.0.0", 8,
+                                 [VppRoutePath(self.pg1.remote_ip4,
+                                               self.pg1.sw_if_index)])
+        cover_route.add_vpp_config()
+
+        p = (Ether(src=self.pg1.remote_mac,
+                   dst=self.pg1.local_mac) /
+             IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
+             UDP(sport=1234, dport=1234) /
+             Raw('\xa5' * 100))
+
+        self.pg1.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg1.get_capture(1)
+
+        #
+        # Configure some non-/24 subnets on an IP interface
+        #
+        ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
+
+        self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
+                                               ip_addr_n,
+                                               16)
+
+        pn = (Ether(src=self.pg1.remote_mac,
+                    dst=self.pg1.local_mac) /
+              IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw('\xa5' * 100))
+        pb = (Ether(src=self.pg1.remote_mac,
+                    dst=self.pg1.local_mac) /
+              IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw('\xa5' * 100))
+
+        self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
+        self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
+
+        # remove the sub-net and we are forwarding via the cover again
+        self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
+                                               ip_addr_n,
+                                               16,
+                                               is_add=0)
+        self.pg1.add_stream(pn)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg1.get_capture(1)
+        self.pg1.add_stream(pb)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg1.get_capture(1)
+
+        #
+        # A /31 is a special case where the 'other-side' is an attached host
+        # packets to that peer generate ARP requests
+        #
+        ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
+
+        self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
+                                               ip_addr_n,
+                                               31)
+
+        pn = (Ether(src=self.pg1.remote_mac,
+                    dst=self.pg1.local_mac) /
+              IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw('\xa5' * 100))
+
+        self.pg1.add_stream(pn)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg0.get_capture(1)
+        rx[ARP]
+
+        # remove the sub-net and we are forwarding via the cover again
+        self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
+                                               ip_addr_n,
+                                               31,
+                                               is_add=0)
+        self.pg1.add_stream(pn)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg1.get_capture(1)
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)