loop counter to prevent infiinte number of look ups per-packet
Change-Id: I59235d11baac18785a4c90cdaf14e8f3ddf06dab Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
This commit is contained in:
@ -42,6 +42,9 @@ format_vnet_buffer (u8 * s, va_list * args)
|
||||
a = format (a, "qos %d.%d ",
|
||||
vnet_buffer2 (b)->qos.bits, vnet_buffer2 (b)->qos.source);
|
||||
|
||||
if (b->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)
|
||||
a = format (a, "loop-counter %d ", vnet_buffer2 (b)->loop_counter);
|
||||
|
||||
s = format (s, "%U", format_vlib_buffer, b);
|
||||
if (a)
|
||||
s = format (s, "\n%U%v", format_white_space, indent, a);
|
||||
|
@ -51,6 +51,7 @@
|
||||
_( 3, VLAN_2_DEEP, "vlan-2-deep") \
|
||||
_( 4, VLAN_1_DEEP, "vlan-1-deep") \
|
||||
_( 5, SPAN_CLONE, "span-clone") \
|
||||
_( 6, LOOP_COUNTER_VALID, 0) \
|
||||
_( 7, LOCALLY_ORIGINATED, "local") \
|
||||
_( 8, IS_IP4, "ip4") \
|
||||
_( 9, IS_IP6, "ip6") \
|
||||
@ -357,7 +358,8 @@ typedef struct
|
||||
u8 source;
|
||||
} qos;
|
||||
|
||||
u8 __unused[2];
|
||||
u8 loop_counter;
|
||||
u8 __unused[1];
|
||||
|
||||
/* Group Based Policy */
|
||||
struct
|
||||
|
@ -28,6 +28,12 @@
|
||||
static const char *const lookup_input_names[] = LOOKUP_INPUTS;
|
||||
static const char *const lookup_cast_names[] = LOOKUP_CASTS;
|
||||
|
||||
/**
|
||||
* If a packet encounters a lookup DPO more than the many times
|
||||
* then we assume there is a loop in the forward graph and drop the packet
|
||||
*/
|
||||
#define MAX_LUKPS_PER_PACKET 4
|
||||
|
||||
/**
|
||||
* @brief Enumeration of the lookup subtypes
|
||||
*/
|
||||
@ -471,6 +477,23 @@ lookup_dpo_ip4_inline (vlib_main_t * vm,
|
||||
(cm, thread_index, lbi1, 1,
|
||||
vlib_buffer_length_in_chain (vm, b1));
|
||||
|
||||
if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b0)->loop_counter = 0;
|
||||
b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
if (!(b1->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b1)->loop_counter = 0;
|
||||
b1->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
|
||||
vnet_buffer2(b0)->loop_counter++;
|
||||
vnet_buffer2(b1)->loop_counter++;
|
||||
|
||||
if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next0 = IP_LOOKUP_NEXT_DROP;
|
||||
if (PREDICT_FALSE(vnet_buffer2(b1)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next1 = IP_LOOKUP_NEXT_DROP;
|
||||
|
||||
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
|
||||
{
|
||||
lookup_trace_t *tr = vlib_add_trace (vm, node,
|
||||
@ -572,6 +595,16 @@ lookup_dpo_ip4_inline (vlib_main_t * vm,
|
||||
(cm, thread_index, lbi0, 1,
|
||||
vlib_buffer_length_in_chain (vm, b0));
|
||||
|
||||
if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b0)->loop_counter = 0;
|
||||
b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
|
||||
vnet_buffer2(b0)->loop_counter++;
|
||||
|
||||
if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next0 = IP_LOOKUP_NEXT_DROP;
|
||||
|
||||
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
|
||||
{
|
||||
lookup_trace_t *tr = vlib_add_trace (vm, node,
|
||||
@ -780,6 +813,23 @@ lookup_dpo_ip6_inline (vlib_main_t * vm,
|
||||
hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
|
||||
hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
|
||||
|
||||
if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b0)->loop_counter = 0;
|
||||
b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
if (!(b1->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b1)->loop_counter = 0;
|
||||
b1->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
|
||||
vnet_buffer2(b0)->loop_counter++;
|
||||
vnet_buffer2(b1)->loop_counter++;
|
||||
|
||||
if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next0 = IP_LOOKUP_NEXT_DROP;
|
||||
if (PREDICT_FALSE(vnet_buffer2(b1)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next1 = IP_LOOKUP_NEXT_DROP;
|
||||
|
||||
if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
|
||||
{
|
||||
flow_hash_config0 = lb0->lb_hash_config;
|
||||
@ -910,6 +960,16 @@ lookup_dpo_ip6_inline (vlib_main_t * vm,
|
||||
next0 = dpo0->dpoi_next_node;
|
||||
vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
|
||||
|
||||
if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b0)->loop_counter = 0;
|
||||
b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
|
||||
vnet_buffer2(b0)->loop_counter++;
|
||||
|
||||
if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next0 = IP_LOOKUP_NEXT_DROP;
|
||||
|
||||
vlib_increment_combined_counter
|
||||
(cm, thread_index, lbi0, 1,
|
||||
vlib_buffer_length_in_chain (vm, b0));
|
||||
@ -1085,11 +1145,21 @@ lookup_dpo_mpls_inline (vlib_main_t * vm,
|
||||
vlib_buffer_length_in_chain (vm, b0));
|
||||
}
|
||||
|
||||
vnet_buffer (b0)->mpls.ttl = ((char*)hdr0)[3];
|
||||
vnet_buffer (b0)->mpls.ttl = ((char*)hdr0)[3];
|
||||
vnet_buffer (b0)->mpls.exp = (((char*)hdr0)[2] & 0xe) >> 1;
|
||||
vnet_buffer (b0)->mpls.first = 1;
|
||||
vlib_buffer_advance(b0, sizeof(*hdr0));
|
||||
|
||||
if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b0)->loop_counter = 0;
|
||||
b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
|
||||
vnet_buffer2(b0)->loop_counter++;
|
||||
|
||||
if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next0 = MPLS_LOOKUP_NEXT_DROP;
|
||||
|
||||
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
|
||||
{
|
||||
lookup_trace_t *tr = vlib_add_trace (vm, node,
|
||||
@ -1163,6 +1233,7 @@ VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = {
|
||||
VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_itf_node, lookup_mpls_dst_itf)
|
||||
|
||||
typedef enum lookup_ip_dst_mcast_next_t_ {
|
||||
LOOKUP_IP_DST_MCAST_NEXT_DROP,
|
||||
LOOKUP_IP_DST_MCAST_NEXT_RPF,
|
||||
LOOKUP_IP_DST_MCAST_N_NEXT,
|
||||
} mfib_forward_lookup_next_t;
|
||||
@ -1249,6 +1320,16 @@ lookup_dpo_ip_dst_mcast_inline (vlib_main_t * vm,
|
||||
|
||||
vnet_buffer (b0)->ip.adj_index[VLIB_TX] = mfei0;
|
||||
|
||||
if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
|
||||
vnet_buffer2(b0)->loop_counter = 0;
|
||||
b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
|
||||
}
|
||||
|
||||
vnet_buffer2(b0)->loop_counter++;
|
||||
|
||||
if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
|
||||
next0 = LOOKUP_IP_DST_MCAST_NEXT_DROP;
|
||||
|
||||
vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
|
||||
n_left_to_next, bi0, next0);
|
||||
}
|
||||
@ -1273,6 +1354,7 @@ VLIB_REGISTER_NODE (lookup_ip4_dst_mcast_node) = {
|
||||
.format_trace = format_lookup_trace,
|
||||
.n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
|
||||
.next_nodes = {
|
||||
[LOOKUP_IP_DST_MCAST_NEXT_DROP] = "ip4-drop",
|
||||
[LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip4-mfib-forward-rpf",
|
||||
},
|
||||
};
|
||||
@ -1295,6 +1377,7 @@ VLIB_REGISTER_NODE (lookup_ip6_dst_mcast_node) = {
|
||||
.format_trace = format_lookup_trace,
|
||||
.n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
|
||||
.next_nodes = {
|
||||
[LOOKUP_IP_DST_MCAST_NEXT_DROP] = "ip6-drop",
|
||||
[LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip6-mfib-forward-rpf",
|
||||
},
|
||||
};
|
||||
|
@ -696,7 +696,7 @@ VLIB_REGISTER_NODE (mpls_load_balance_node) = {
|
||||
.n_next_nodes = 1,
|
||||
.next_nodes =
|
||||
{
|
||||
[0] = "mpls-drop",
|
||||
[MPLS_LOOKUP_NEXT_DROP] = "mpls-drop",
|
||||
},
|
||||
|
||||
};
|
||||
|
@ -24,6 +24,14 @@
|
||||
*/
|
||||
u32 mpls_lookup_to_replicate_edge;
|
||||
|
||||
/**
|
||||
* Enum of statically configred MPLS lookup next nodes
|
||||
*/
|
||||
typedef enum mpls_lookup_next_t_
|
||||
{
|
||||
MPLS_LOOKUP_NEXT_DROP = 0,
|
||||
} mpls_lookup_next_t;
|
||||
|
||||
/*
|
||||
* Compute flow hash.
|
||||
* We'll use it to select which adjacency to use for this flow. And other things.
|
||||
|
@ -1246,6 +1246,24 @@ class TestIPDeag(VppTestCase):
|
||||
route_in_src.add_vpp_config()
|
||||
self.send_and_expect(self.pg0, pkts_src, self.pg2)
|
||||
|
||||
#
|
||||
# loop in the lookup DP
|
||||
#
|
||||
route_loop = VppIpRoute(self, "2.2.2.3", 32,
|
||||
[VppRoutePath("0.0.0.0",
|
||||
0xffffffff,
|
||||
nh_table_id=0)])
|
||||
route_loop.add_vpp_config()
|
||||
|
||||
p_l = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IP(src="2.2.2.4", dst="2.2.2.3") /
|
||||
TCP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
self.send_and_assert_no_replies(self.pg0, p_l * 257,
|
||||
"IP lookup loop")
|
||||
|
||||
|
||||
class TestIPInput(VppTestCase):
|
||||
""" IPv4 Input Exceptions """
|
||||
|
121
test/test_ip6.py
121
test/test_ip6.py
@ -9,7 +9,7 @@ from vpp_sub_interface import VppSubInterface, VppDot1QSubint
|
||||
from vpp_pg_interface import is_ipv6_misc
|
||||
from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \
|
||||
VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
|
||||
VppMplsRoute, DpoProto, VppMplsTable
|
||||
VppMplsRoute, DpoProto, VppMplsTable, VppIpTable
|
||||
from vpp_neighbor import find_nbr, VppNeighbor
|
||||
|
||||
from scapy.packet import Raw
|
||||
@ -1957,6 +1957,125 @@ class TestIP6Punt(VppTestCase):
|
||||
is_ip6=1)
|
||||
|
||||
|
||||
class TestIPDeag(VppTestCase):
|
||||
""" IPv6 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_ip6()
|
||||
i.resolve_ndp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestIPDeag, self).tearDown()
|
||||
for i in self.pg_interfaces:
|
||||
i.unconfig_ip6()
|
||||
i.admin_down()
|
||||
|
||||
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, is_ip6=1)
|
||||
table_src = VppIpTable(self, 2, is_ip6=1)
|
||||
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", 128,
|
||||
[VppRoutePath("::",
|
||||
0xffffffff,
|
||||
nh_table_id=1,
|
||||
proto=DpoProto.DPO_PROTO_IP6)],
|
||||
is_ip6=1)
|
||||
route_to_src = VppIpRoute(self, "1::2", 128,
|
||||
[VppRoutePath("::",
|
||||
0xffffffff,
|
||||
nh_table_id=2,
|
||||
is_source_lookup=1,
|
||||
proto=DpoProto.DPO_PROTO_IP6)],
|
||||
is_ip6=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) /
|
||||
IPv6(src="5::5", dst="1::1") /
|
||||
TCP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
p_src = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IPv6(src="2::2", dst="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", 128,
|
||||
[VppRoutePath(self.pg1.remote_ip6,
|
||||
self.pg1.sw_if_index,
|
||||
proto=DpoProto.DPO_PROTO_IP6)],
|
||||
is_ip6=1,
|
||||
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", 128,
|
||||
[VppRoutePath(self.pg2.remote_ip6,
|
||||
self.pg2.sw_if_index,
|
||||
proto=DpoProto.DPO_PROTO_IP6)],
|
||||
is_ip6=1,
|
||||
table_id=2)
|
||||
route_in_src.add_vpp_config()
|
||||
self.send_and_expect(self.pg0, pkts_src, self.pg2)
|
||||
|
||||
#
|
||||
# loop in the lookup DP
|
||||
#
|
||||
route_loop = VppIpRoute(self, "3::3", 128,
|
||||
[VppRoutePath("::",
|
||||
0xffffffff,
|
||||
proto=DpoProto.DPO_PROTO_IP6)],
|
||||
is_ip6=1)
|
||||
route_loop.add_vpp_config()
|
||||
|
||||
p_l = (Ether(src=self.pg0.remote_mac,
|
||||
dst=self.pg0.local_mac) /
|
||||
IPv6(src="3::4", dst="3::3") /
|
||||
TCP(sport=1234, dport=1234) /
|
||||
Raw('\xa5' * 100))
|
||||
|
||||
self.send_and_assert_no_replies(self.pg0, p_l * 257,
|
||||
"IP lookup loop")
|
||||
|
||||
|
||||
class TestIP6Input(VppTestCase):
|
||||
""" IPv6 Input Exceptions """
|
||||
|
||||
|
Reference in New Issue
Block a user