From 521a8d7df423a0b5aaf259d49ca9230705bc25ee Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 6 Dec 2018 13:46:49 +0000 Subject: FIB recusrion loop checks traverse midchain adjacencies if a tunnel's destination address is reachable through the tunnel (see example config belwo) then search for and detect a recursion loop and don't stack the adjacency. Otherwise this results in a nasty surprise. DBGvpp# loop cre DBGvpp# set int state loop0 up DBGvpp# set int ip addr loop0 10.0.0.1/24 DBGvpp# create gre tunnel src 10.0.0.1 dst 1.1.1.1 DBGvpp# set int state gre0 up DBGvpp# set int unnum gre0 use loop0 DBGvpp# ip route 1.1.1.1/32 via gre0 DBGvpp# sh ip fib 1.1.1.1 ipv4-VRF:0, fib_index:0, flow hash:[src dst sport dport proto ] locks:[src:plugin-hi:2, src:default-route:1, ] 1.1.1.1/32 fib:0 index:11 locks:4 <<< this is entry #11 src:CLI refs:1 entry-flags:attached, src-flags:added,contributing,active, path-list:[14] locks:2 flags:shared,looped, uPRF-list:12 len:1 itfs:[2, ] path:[14] pl-index:14 ip4 weight=1 pref=0 attached-nexthop: oper-flags:recursive-loop,resolved, cfg-flags:attached, 1.1.1.1 gre0 (p2p) [@0]: ipv4 via 0.0.0.0 gre0: mtu:9000 4500000000000000fe2fb0cc0a0000010101010100000800 stacked-on entry:11: <<<< and the midchain forwards via entry #11 [@2]: dpo-drop ip4 src:recursive-resolution refs:1 src-flags:added, cover:-1 forwarding: unicast-ip4-chain [@0]: dpo-load-balance: [proto:ip4 index:13 buckets:1 uRPF:12 to:[0:0]] [0] [@6]: ipv4 via 0.0.0.0 gre0: mtu:9000 4500000000000000fe2fb0cc0a0000010101010100000800 stacked-on entry:11: [@2]: dpo-drop ip4 DBGvpp# sh adj 1 [@1] ipv4 via 0.0.0.0 gre0: mtu:9000 4500000000000000fe2fb0cc0a0000010101010100000800 stacked-on entry:11: [@2]: dpo-drop ip4 flags:midchain-ip-stack midchain-looped <<<<< this is a loop counts:[0:0] locks:4 delegates: children: {path:14} Change-Id: I39b82bd1ea439be4611c88b130d40289fa0c1b59 Signed-off-by: Neale Ranns --- src/vnet/adj/adj.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) (limited to 'src/vnet/adj/adj.c') diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c index 8740bb41465..b844073ecfb 100644 --- a/src/vnet/adj/adj.c +++ b/src/vnet/adj/adj.c @@ -45,6 +45,11 @@ const ip46_address_t ADJ_BCAST_ADDR = { }, }; +/** + * Adj flag names + */ +static const char *adj_attr_names[] = ADJ_ATTR_NAMES; + always_inline void adj_poison (ip_adjacency_t * adj) { @@ -95,6 +100,28 @@ adj_index_is_special (adj_index_t adj_index) return (0); } +u8* +format_adj_flags (u8 * s, va_list * args) +{ + adj_flags_t af; + adj_attr_t at; + + af = va_arg (*args, int); + + if (ADJ_FLAG_NONE == af) + { + return (format(s, "None")); + } + FOR_EACH_ADJ_ATTR(at) + { + if (af & (1 << at)) + { + s = format(s, "%s ", adj_attr_names[at]); + } + } + return (s); +} + /** * @brief Pretty print helper function for formatting specific adjacencies. * @param s - input string to format @@ -113,10 +140,11 @@ format_ip_adjacency (u8 * s, va_list * args) adj_index = va_arg (*args, u32); fiaf = va_arg (*args, format_ip_adjacency_flags_t); adj = adj_get(adj_index); - + switch (adj->lookup_next_index) { case IP_LOOKUP_NEXT_REWRITE: + case IP_LOOKUP_NEXT_BCAST: s = format (s, "%U", format_adj_nbr, adj_index, 0); break; case IP_LOOKUP_NEXT_ARP: @@ -134,8 +162,12 @@ format_ip_adjacency (u8 * s, va_list * args) case IP_LOOKUP_NEXT_MCAST_MIDCHAIN: s = format (s, "%U", format_adj_mcast_midchain, adj_index, 0); break; - default: - break; + case IP_LOOKUP_NEXT_DROP: + case IP_LOOKUP_NEXT_PUNT: + case IP_LOOKUP_NEXT_LOCAL: + case IP_LOOKUP_NEXT_ICMP_ERROR: + case IP_LOOKUP_N_NEXT: + break; } if (fiaf & FORMAT_IP_ADJACENCY_DETAIL) @@ -143,6 +175,7 @@ format_ip_adjacency (u8 * s, va_list * args) vlib_counter_t counts; vlib_get_combined_counter(&adjacency_counters, adj_index, &counts); + s = format (s, "\n flags:%U", format_adj_flags, adj->ia_flags); s = format (s, "\n counts:[%Ld:%Ld]", counts.packets, counts.bytes); s = format (s, "\n locks:%d", adj->ia_node.fn_locks); s = format(s, "\n delegates:\n "); @@ -159,6 +192,39 @@ format_ip_adjacency (u8 * s, va_list * args) return s; } +int +adj_recursive_loop_detect (adj_index_t ai, + fib_node_index_t **entry_indicies) +{ + ip_adjacency_t * adj; + + adj = adj_get(ai); + + switch (adj->lookup_next_index) + { + case IP_LOOKUP_NEXT_REWRITE: + case IP_LOOKUP_NEXT_ARP: + case IP_LOOKUP_NEXT_GLEAN: + case IP_LOOKUP_NEXT_MCAST: + case IP_LOOKUP_NEXT_BCAST: + case IP_LOOKUP_NEXT_DROP: + case IP_LOOKUP_NEXT_PUNT: + case IP_LOOKUP_NEXT_LOCAL: + case IP_LOOKUP_NEXT_ICMP_ERROR: + case IP_LOOKUP_N_NEXT: + /* + * these adjcencey types are terminal graph nodes, so there's no + * possibility of a loop down here. + */ + break; + case IP_LOOKUP_NEXT_MIDCHAIN: + case IP_LOOKUP_NEXT_MCAST_MIDCHAIN: + return (adj_ndr_midchain_recursive_loop_detect(ai, entry_indicies)); + } + + return (0); +} + /* * adj_last_lock_gone * @@ -403,7 +469,7 @@ adj_get_link_type (adj_index_t ai) adj = adj_get(ai); - return (adj->ia_link); + return (adj->ia_link); } /** -- cgit 1.2.3-korg