Merge pull request #7993 from mjstapp/reorg_resolve

zebra: reorg nexthop resolution code
This commit is contained in:
Stephen Worley 2021-03-16 11:34:33 -04:00 committed by GitHub
commit 0a7edab036
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 68 deletions

View File

@ -371,8 +371,8 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
*/ */
if (nh && (nh->next == NULL)) { if (nh && (nh->next == NULL)) {
switch (nh->type) { switch (nh->type) {
case (NEXTHOP_TYPE_IFINDEX): case NEXTHOP_TYPE_IFINDEX:
case (NEXTHOP_TYPE_BLACKHOLE): case NEXTHOP_TYPE_BLACKHOLE:
/* /*
* This switch case handles setting the afi different * This switch case handles setting the afi different
* for ipv4/v6 routes. Ifindex/blackhole nexthop * for ipv4/v6 routes. Ifindex/blackhole nexthop
@ -383,12 +383,12 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
*/ */
nhe->afi = afi; nhe->afi = afi;
break; break;
case (NEXTHOP_TYPE_IPV4_IFINDEX): case NEXTHOP_TYPE_IPV4_IFINDEX:
case (NEXTHOP_TYPE_IPV4): case NEXTHOP_TYPE_IPV4:
nhe->afi = AFI_IP; nhe->afi = AFI_IP;
break; break;
case (NEXTHOP_TYPE_IPV6_IFINDEX): case NEXTHOP_TYPE_IPV6_IFINDEX:
case (NEXTHOP_TYPE_IPV6): case NEXTHOP_TYPE_IPV6:
nhe->afi = AFI_IP6; nhe->afi = AFI_IP6;
break; break;
} }
@ -1789,8 +1789,9 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
* if at all possible. Set the nexthop->ifindex and resolved_id * if at all possible. Set the nexthop->ifindex and resolved_id
* as appropriate * as appropriate
*/ */
static int nexthop_active(afi_t afi, struct route_entry *re, static int nexthop_active(afi_t afi, struct nexthop *nexthop,
struct nexthop *nexthop, struct route_node *top) const struct prefix *top, int type, uint32_t flags,
uint32_t *pmtu)
{ {
struct prefix p; struct prefix p;
struct route_table *table; struct route_table *table;
@ -1805,32 +1806,57 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
struct in_addr local_ipv4; struct in_addr local_ipv4;
struct in_addr *ipv4; struct in_addr *ipv4;
/* Reset some nexthop attributes that we'll recompute if necessary */
if ((nexthop->type == NEXTHOP_TYPE_IPV4) if ((nexthop->type == NEXTHOP_TYPE_IPV4)
|| nexthop->type == NEXTHOP_TYPE_IPV6) || (nexthop->type == NEXTHOP_TYPE_IPV6))
nexthop->ifindex = 0; nexthop->ifindex = 0;
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
nexthops_free(nexthop->resolved); nexthops_free(nexthop->resolved);
nexthop->resolved = NULL; nexthop->resolved = NULL;
re->nexthop_mtu = 0;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p, nexthop %pNHv",
__func__, re, nexthop);
/* /*
* If the kernel has sent us a NEW route, then * Some nexthop types get special handling, possibly skipping
* by golly gee whiz it's a good route. * the normal processing.
*
* If its an already INSTALLED route we have already handled, then the
* kernel route's nexthop might have became unreachable
* and we have to handle that.
*/ */
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) switch (nexthop->type) {
&& (re->type == ZEBRA_ROUTE_KERNEL case NEXTHOP_TYPE_IFINDEX:
|| re->type == ZEBRA_ROUTE_SYSTEM)) ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
/*
* If the interface exists and its operative or its a kernel
* route and interface is up, its active. We trust kernel routes
* to be good.
*/
if (ifp
&& (if_is_operative(ifp)
|| (if_is_up(ifp)
&& (type == ZEBRA_ROUTE_KERNEL
|| type == ZEBRA_ROUTE_SYSTEM))))
return 1; return 1;
else
return 0;
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
ifp = if_lookup_by_index(nexthop->ifindex,
nexthop->vrf_id);
if (ifp && if_is_operative(ifp))
return 1;
else
return 0;
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
return 1;
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV6:
default:
break;
}
/* /*
* If the nexthop has been marked as 'onlink' we just need to make * If the nexthop has been marked as 'onlink' we just need to make
@ -1853,10 +1879,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
return 1; return 1;
} }
if ((top->p.family == AF_INET && top->p.prefixlen == 32 if (top &&
&& nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr) ((top->family == AF_INET && top->prefixlen == 32
|| (top->p.family == AF_INET6 && top->p.prefixlen == 128 && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr)
&& memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) { || (top->family == AF_INET6 && top->prefixlen == 128
&& memcmp(&nexthop->gate.ipv6, &top->u.prefix6, 16) == 0))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED) if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug( zlog_debug(
" :%s: Attempting to install a max prefixlength route through itself", " :%s: Attempting to install a max prefixlength route through itself",
@ -1873,6 +1900,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
ipv4 = &nexthop->gate.ipv4; ipv4 = &nexthop->gate.ipv4;
} }
/* Processing for nexthops with SR 'color' attribute, using
* the corresponding SR policy object.
*/
if (nexthop->srte_color) { if (nexthop->srte_color) {
struct ipaddr endpoint = {0}; struct ipaddr endpoint = {0};
struct zebra_sr_policy *policy; struct zebra_sr_policy *policy;
@ -1950,7 +1980,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
* resolved by a route NH1. The exception is if the route is a * resolved by a route NH1. The exception is if the route is a
* host route. * host route.
*/ */
if (rn == top) if (prefix_same(&rn->p, top))
if (((afi == AFI_IP) && (rn->p.prefixlen != 32)) if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
|| ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) { || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED) if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@ -2020,7 +2050,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
match->nhe->id, newhop); match->nhe->id, newhop);
return 1; return 1;
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
struct nexthop_group *nhg; struct nexthop_group *nhg;
resolved = 0; resolved = 0;
@ -2079,10 +2109,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
NULL); NULL);
resolved = 1; resolved = 1;
} }
done_with_match: done_with_match:
if (resolved) /* Capture resolving mtu */
re->nexthop_mtu = match->mtu; if (resolved) {
else if (IS_ZEBRA_DEBUG_RIB_DETAILED) if (pmtu)
*pmtu = match->mtu;
} else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug( zlog_debug(
" %s: Recursion failed to find", " %s: Recursion failed to find",
__func__); __func__);
@ -2092,9 +2126,9 @@ done_with_match:
if (IS_ZEBRA_DEBUG_RIB_DETAILED) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
zlog_debug( zlog_debug(
" %s: Route Type %s has not turned on recursion", " %s: Route Type %s has not turned on recursion",
__func__, zebra_route_string(re->type)); __func__, zebra_route_string(type));
if (re->type == ZEBRA_ROUTE_BGP if (type == ZEBRA_ROUTE_BGP
&& !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
zlog_debug( zlog_debug(
" EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
} }
@ -2113,20 +2147,17 @@ done_with_match:
* appropriately as well. An existing route map can turn an * appropriately as well. An existing route map can turn an
* otherwise active nexthop into inactive, but not vice versa. * otherwise active nexthop into inactive, but not vice versa.
* *
* If it finds a nexthop recursively, set the resolved_id
* to match that nexthop's nhg_hash_entry ID;
*
* The return value is the final value of 'ACTIVE' flag. * The return value is the final value of 'ACTIVE' flag.
*/ */
static unsigned nexthop_active_check(struct route_node *rn, static unsigned nexthop_active_check(struct route_node *rn,
struct route_entry *re, struct route_entry *re,
struct nexthop *nexthop) struct nexthop *nexthop)
{ {
struct interface *ifp;
route_map_result_t ret = RMAP_PERMITMATCH; route_map_result_t ret = RMAP_PERMITMATCH;
afi_t family; afi_t family;
const struct prefix *p, *src_p; const struct prefix *p, *src_p;
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
uint32_t mtu = 0;
srcdest_rnode_prefixes(rn, &p, &src_p); srcdest_rnode_prefixes(rn, &p, &src_p);
@ -2137,19 +2168,28 @@ static unsigned nexthop_active_check(struct route_node *rn,
else else
family = 0; family = 0;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
/*
* If the kernel has sent us a NEW route, then
* by golly gee whiz it's a good route.
*
* If its an already INSTALLED route we have already handled, then the
* kernel route's nexthop might have became unreachable
* and we have to handle that.
*/
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) &&
(re->type == ZEBRA_ROUTE_KERNEL ||
re->type == ZEBRA_ROUTE_SYSTEM)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
goto skip_check;
}
switch (nexthop->type) { switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); if (nexthop_active(AFI_IP, nexthop, &rn->p, re->type,
/* re->flags, &mtu))
* If the interface exists and its operative or its a kernel
* route and interface is up, its active. We trust kernel routes
* to be good.
*/
if (ifp
&& (if_is_operative(ifp)
|| (if_is_up(ifp)
&& (re->type == ZEBRA_ROUTE_KERNEL
|| re->type == ZEBRA_ROUTE_SYSTEM))))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@ -2157,14 +2197,16 @@ static unsigned nexthop_active_check(struct route_node *rn,
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP; family = AFI_IP;
if (nexthop_active(AFI_IP, re, nexthop, rn)) if (nexthop_active(AFI_IP, nexthop, &rn->p, re->type,
re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break; break;
case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6:
family = AFI_IP6; family = AFI_IP6;
if (nexthop_active(AFI_IP6, re, nexthop, rn)) if (nexthop_active(AFI_IP6, nexthop, &rn->p, re->type,
re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@ -2173,19 +2215,12 @@ static unsigned nexthop_active_check(struct route_node *rn,
/* RFC 5549, v4 prefix with v6 NH */ /* RFC 5549, v4 prefix with v6 NH */
if (rn->p.family != AF_INET) if (rn->p.family != AF_INET)
family = AFI_IP6; family = AFI_IP6;
if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
ifp = if_lookup_by_index(nexthop->ifindex, if (nexthop_active(AFI_IP6, nexthop, &rn->p, re->type,
nexthop->vrf_id); re->flags, &mtu))
if (ifp && if_is_operative(ifp))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
} else {
if (nexthop_active(AFI_IP6, re, nexthop, rn))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
break; break;
case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_BLACKHOLE:
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@ -2194,6 +2229,8 @@ static unsigned nexthop_active_check(struct route_node *rn,
break; break;
} }
skip_check:
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED) if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(" %s: Unable to find active nexthop", zlog_debug(" %s: Unable to find active nexthop",
@ -2201,6 +2238,18 @@ static unsigned nexthop_active_check(struct route_node *rn,
return 0; return 0;
} }
/* Capture recursive nexthop mtu.
* TODO -- the code used to just reset the re's value to zero
* for each nexthop, and then jam any resolving route's mtu value in,
* whether or not that was zero, or lt/gt any existing value? The
* way this is used appears to be as a floor value, so let's try
* using it that way here.
*/
if (mtu > 0) {
if (re->nexthop_mtu == 0 || re->nexthop_mtu > mtu)
re->nexthop_mtu = mtu;
}
/* XXX: What exactly do those checks do? Do we support /* XXX: What exactly do those checks do? Do we support
* e.g. IPv4 routes with IPv6 nexthops or vice versa? * e.g. IPv4 routes with IPv6 nexthops or vice versa?
*/ */
@ -2214,7 +2263,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
* Possibly it may be better to use only the rib_table_info * Possibly it may be better to use only the rib_table_info
* in every case. * in every case.
*/ */
if (!family) { if (family == 0) {
struct rib_table_info *info; struct rib_table_info *info;
info = srcdest_rnode_table_info(rn); info = srcdest_rnode_table_info(rn);
@ -2292,6 +2341,9 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
nexthop = nhg->nexthop; nexthop = nhg->nexthop;
/* Init recursive nh mtu */
re->nexthop_mtu = 0;
/* Process nexthops one-by-one */ /* Process nexthops one-by-one */
for ( ; nexthop; nexthop = nexthop->next) { for ( ; nexthop; nexthop = nexthop->next) {

View File

@ -180,8 +180,9 @@ struct nhg_ctx {
vrf_id_t vrf_id; vrf_id_t vrf_id;
afi_t afi; afi_t afi;
/* /*
* This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel * This should only ever be ZEBRA_ROUTE_NHG unless we get a a kernel
* created nexthop not made by us. * created nexthop not made by us.
*/ */
int type; int type;