zebra: fix resolving nexthop through itself

Problems reported with zebra nht oscillating when a nexthop is resolved
using the same address to reach the  nexthop (for example, 10.0.0.8 is
resolved via 10.0.0.8/32.)  This fix removes this attempt to resolve
thru itself unless the route being resolved is also a host route.
This fix also walks up the tree looking for a less specific route to
reach the nexthop if needed.  Smoke testing completed successfully.

Ticket: CM-8192
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
Reviewed-by: CCR-6583
Testing done: Manual testing successful, bgp-min completed successfully
l3-smoke completed with two test changes required.
This commit is contained in:
Don Slice 2017-11-01 13:39:16 +00:00
parent 0db8196a96
commit fd7fd9e5c4
2 changed files with 120 additions and 44 deletions

View File

@ -449,9 +449,15 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
while (rn) { while (rn) {
route_unlock_node(rn); route_unlock_node(rn);
/* If lookup self prefix return immediately. */ /* Lookup should halt if we've matched against ourselves ('top',
if (rn == top) * if specified) - i.e., we cannot have a nexthop NH1 is
return 0; * resolved by a route NH1. The exception is if the route is a
* host route.
*/
if (top && rn == top)
if (((afi == AFI_IP) && (rn->p.prefixlen != 32)) ||
((afi == AFI_IP6) && (rn->p.prefixlen != 128)))
return 0;
/* Pick up selected route. */ /* Pick up selected route. */
/* However, do not resolve over default route unless explicitly /* However, do not resolve over default route unless explicitly

View File

@ -370,10 +370,12 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn,
} }
/* /*
* Determine appropriate route (RE entry) resolving a tracked entry * Determine appropriate route (RE entry) resolving a tracked BGP route
* (nexthop or BGP route for import). * for BGP route for import.
*/ */
static struct route_entry *zebra_rnh_resolve_entry(vrf_id_t vrfid, int family, static
struct route_entry *zebra_rnh_resolve_import_entry(vrf_id_t vrfid,
int family,
rnh_type_t type, rnh_type_t type,
struct route_node *nrn, struct route_node *nrn,
struct rnh *rnh, struct rnh *rnh,
@ -393,48 +395,25 @@ static struct route_entry *zebra_rnh_resolve_entry(vrf_id_t vrfid, int family,
if (!rn) if (!rn)
return NULL; return NULL;
/* Unlock route node - we don't need to lock when walking the tree. */
route_unlock_node(rn);
/* When resolving nexthops, do not resolve via the default route unless /* When resolving nexthops, do not resolve via the default route unless
* 'ip nht resolve-via-default' is configured. * 'ip nht resolve-via-default' is configured.
*/ */
if ((type == RNH_NEXTHOP_TYPE) if (((is_default_prefix(&rn->p)) ||
&& (is_default_prefix(&rn->p) ((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) &&
&& !nh_resolve_via_default(rn->p.family))) !prefix_same(&nrn->p, &rn->p))))
re = NULL; return NULL;
else if ((type == RNH_IMPORT_CHECK_TYPE)
&& CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)
&& !prefix_same(&nrn->p, &rn->p))
re = NULL;
else {
/* Identify appropriate route entry. */
RNODE_FOREACH_RE (rn, re) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
continue;
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
continue;
if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { /* Identify appropriate route entry. */
if (re->type == ZEBRA_ROUTE_CONNECT) RNODE_FOREACH_RE(rn, re) {
break; if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) &&
if (re->type == ZEBRA_ROUTE_NHRP) { CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) &&
struct nexthop *nexthop; (re->type != ZEBRA_ROUTE_BGP))
for (nexthop = re->nexthop; nexthop; break;
nexthop = nexthop->next)
if (nexthop->type
== NEXTHOP_TYPE_IFINDEX)
break;
if (nexthop)
break;
}
} else if ((type == RNH_IMPORT_CHECK_TYPE)
&& (re->type == ZEBRA_ROUTE_BGP))
continue;
else
break;
}
} }
/* Need to unlock route node */
route_unlock_node(rn);
if (re) if (re)
*prn = rn; *prn = rn;
return re; return re;
@ -650,6 +629,86 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
} }
} }
/*
* Determine appropriate route (route entry) resolving a tracked
* nexthop.
*/
static struct route_entry *zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid,
int family,
struct route_node *nrn,
struct rnh *rnh,
struct route_node **prn)
{
struct route_table *route_table;
struct route_node *rn;
struct route_entry *re;
*prn = NULL;
route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
if (!route_table)
return NULL;
rn = route_node_match(route_table, &nrn->p);
if (!rn)
return NULL;
/* Unlock route node - we don't need to lock when walking the tree. */
route_unlock_node(rn);
/* While resolving nexthops, we may need to walk up the tree from the
* most-specific match. Do similar logic as in zebra_rib.c
*/
while (rn) {
/* Do not resolve over default route unless allowed &&
* match route to be exact if so specified
*/
if (is_default_prefix(&rn->p) &&
!nh_resolve_via_default(rn->p.family))
return NULL;
/* Identify appropriate route entry. */
RNODE_FOREACH_RE(rn, re) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
continue;
if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
continue;
if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
if ((re->type == ZEBRA_ROUTE_CONNECT)
|| (re->type == ZEBRA_ROUTE_STATIC))
break;
if (re->type == ZEBRA_ROUTE_NHRP) {
struct nexthop *nexthop;
for (nexthop = re->nexthop;
nexthop;
nexthop = nexthop->next)
if (nexthop->type
== NEXTHOP_TYPE_IFINDEX)
break;
if (nexthop)
break;
}
} else
break;
}
/* Route entry found, we're done; else, walk up the tree. */
if (re) {
*prn = rn;
return re;
}
if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
rn = rn->parent;
else
return NULL;
}
return NULL;
}
static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh) static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh)
{ {
struct zebra_pw *pw; struct zebra_pw *pw;
@ -724,7 +783,12 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force,
rnh = nrn->info; rnh = nrn->info;
/* Identify route entry (RE) resolving this tracked entry. */ /* Identify route entry (RE) resolving this tracked entry. */
re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); if (type == RNH_IMPORT_CHECK_TYPE)
re = zebra_rnh_resolve_import_entry(vrfid, family, type, nrn,
rnh, &prn);
else
re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
&prn);
/* If the entry cannot be resolved and that is also the existing state, /* If the entry cannot be resolved and that is also the existing state,
* there is nothing further to do. * there is nothing further to do.
@ -759,7 +823,13 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
rnh = nrn->info; rnh = nrn->info;
re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); /* Identify route entry (RIB) resolving this tracked entry. */
if (type == RNH_IMPORT_CHECK_TYPE)
re = zebra_rnh_resolve_import_entry(vrfid, family, type, nrn,
rnh, &prn);
else
re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh,
&prn);
if (re) { if (re) {
UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);