aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-03-26 10:56:33 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2017-03-29 12:06:13 +0000
commit9a69a6095f67b8979a02f128f44e449889454273 (patch)
tree8fca4f2c4b91326dff94e56766d0c20e7598e0ef
parent8424af7bd5daf0d754daeb8f49c57c760b9c5baa (diff)
Sub-net broadcast addresses for IPv4
Change-Id: Ib2189d01e8bc61de57404159690fb70f89c47277 Signed-off-by: Neale Ranns <nranns@cisco.com>
-rw-r--r--src/vnet/classify/vnet_classify.c2
-rw-r--r--src/vnet/fib/fib_entry_src_interface.c21
-rw-r--r--src/vnet/ip/ip4_forward.c73
-rw-r--r--test/framework.py2
-rw-r--r--test/test_ip4.py125
5 files changed, 217 insertions, 6 deletions
diff --git a/src/vnet/classify/vnet_classify.c b/src/vnet/classify/vnet_classify.c
index b651a1f1eb3..98842a481b8 100644
--- a/src/vnet/classify/vnet_classify.c
+++ b/src/vnet/classify/vnet_classify.c
@@ -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,
diff --git a/src/vnet/fib/fib_entry_src_interface.c b/src/vnet/fib/fib_entry_src_interface.c
index ca04716ed8f..bb87818fe4b 100644
--- a/src/vnet/fib/fib_entry_src_interface.c
+++ b/src/vnet/fib/fib_entry_src_interface.c
@@ -32,6 +32,25 @@ fib_entry_src_interface_init (fib_entry_src_t *src)
}
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,
fib_path_list_flags_t pl_flags,
@@ -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,
diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c
index f2bc2a71851..bbba4b70e01 100644
--- a/src/vnet/ip/ip4_forward.c
+++ b/src/vnet/ip/ip4_forward.c
@@ -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);
diff --git a/test/framework.py b/test/framework.py
index eb3a9d7e6cc..fbd21d2370f 100644
--- a/test/framework.py
+++ b/test/framework.py
@@ -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"))
diff --git a/test/test_ip4.py b/test/test_ip4.py
index 79af5492e18..ed364b62cbb 100644
--- a/test/test_ip4.py
+++ b/test/test_ip4.py
@@ -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)