mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-29 18:41:56 +00:00
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:
parent
0db8196a96
commit
fd7fd9e5c4
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user