From 9bea8fb0b0b6377fbead21f4ff6bceb50080329e Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 3 Feb 2017 04:34:01 -0800 Subject: Next node frame over-flow after replication Change-Id: I25077dd0739787de4f7512e5a70a62e8c34c28e4 Signed-off-by: Neale Ranns --- src/vnet/dpo/replicate_dpo.c | 18 ++++++++++++++++-- test/test_ip_mcast.py | 16 ++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/vnet/dpo/replicate_dpo.c b/src/vnet/dpo/replicate_dpo.c index 8bad75ee..c779516f 100644 --- a/src/vnet/dpo/replicate_dpo.c +++ b/src/vnet/dpo/replicate_dpo.c @@ -664,6 +664,20 @@ replicate_inline (vlib_main_t * vm, /* ship copies to the rest of the buckets */ for (bucket = 1; bucket < rep0->rep_n_buckets; bucket++) { + /* + * After the enqueue of the first buffer, and of all subsequent + * buffers in this loop, it is possible that we over-flow the + * frame of the to-next node. When this happens we need to 'put' + * that full frame to the node and get a fresh empty one. + * Note that these are macros with side effects that change + * to_next & n_left_to_next + */ + if (PREDICT_FALSE(0 == n_left_to_next)) + { + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + } + /* Make a copy */ c0 = vlib_buffer_copy(vm, b0); ci0 = vlib_get_buffer_index(vm, c0); @@ -676,9 +690,9 @@ replicate_inline (vlib_main_t * vm, next0 = dpo0->dpoi_next_node; vnet_buffer (c0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + if (PREDICT_FALSE(c0->flags & VLIB_BUFFER_IS_TRACED)) { - replicate_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + replicate_trace_t *t = vlib_add_trace (vm, node, c0, sizeof (*t)); t->rep_index = repi0; t->dpo = *dpo0; } diff --git a/test/test_ip_mcast.py b/test/test_ip_mcast.py index 028853d2..9b668e42 100644 --- a/test/test_ip_mcast.py +++ b/test/test_ip_mcast.py @@ -29,6 +29,14 @@ class MRouteEntryFlags: MFIB_ENTRY_FLAG_CONNECTED = 4 MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8 +# +# The number of packets sent is set to 90 so that when we replicate more than 3 +# times, which we do for some entries, we will generate more than 256 packets +# to the next node in the VLIB graph. Thus we are testing the code's correctness +# handling this over-flow +# +N_PKTS_IN_STREAM = 90 + class TestIPMcast(VppTestCase): """ IP Multicast Test Case """ @@ -49,7 +57,7 @@ class TestIPMcast(VppTestCase): def create_stream_ip4(self, src_if, src_ip, dst_ip): pkts = [] - for i in range(0, 65): + for i in range(0, N_PKTS_IN_STREAM): info = self.create_packet_info(src_if, src_if) payload = self.info_to_payload(info) p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / @@ -62,7 +70,7 @@ class TestIPMcast(VppTestCase): def create_stream_ip6(self, src_if, src_ip, dst_ip): pkts = [] - for i in range(0, 65): + for i in range(0, N_PKTS_IN_STREAM): info = self.create_packet_info(src_if, src_if) payload = self.info_to_payload(info) p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / @@ -82,7 +90,7 @@ class TestIPMcast(VppTestCase): return capture def verify_capture_ip4(self, src_if, sent): - rxd = self.pg1.get_capture(65) + rxd = self.pg1.get_capture(N_PKTS_IN_STREAM) try: capture = self.verify_filter(rxd, sent) @@ -112,7 +120,7 @@ class TestIPMcast(VppTestCase): raise def verify_capture_ip6(self, src_if, sent): - capture = self.pg1.get_capture(65) + capture = self.pg1.get_capture(N_PKTS_IN_STREAM) self.assertEqual(len(capture), len(sent)) -- cgit 1.2.3-korg