summaryrefslogtreecommitdiff
path: root/zebra/zebra_nhg.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_nhg.c')
-rw-r--r--zebra/zebra_nhg.c478
1 files changed, 262 insertions, 216 deletions
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 8616b14050..934b8ba0db 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -72,25 +72,13 @@ static uint32_t nhg_get_next_id(void)
while (1) {
id_counter++;
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: ID %u checking", __func__, id_counter);
-
if (id_counter == ZEBRA_NHG_PROTO_LOWER) {
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: ID counter wrapped", __func__);
-
id_counter = 0;
continue;
}
- if (zebra_nhg_lookup_id(id_counter)) {
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: ID already exists", __func__);
-
- continue;
- }
-
- break;
+ if (!zebra_nhg_lookup_id(id_counter))
+ break;
}
return id_counter;
@@ -321,8 +309,10 @@ static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
{
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
nhe->ifp = ifp;
- if_nhg_dependents_add(ifp, nhe);
+ nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe);
}
static void
@@ -690,12 +680,6 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
struct nhg_hash_entry *newnhe, *backup_nhe;
struct nexthop *nh = NULL;
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug(
- "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s",
- __func__, lookup->id, lookup, lookup->vrf_id,
- lookup->type, nhg_depends,
- (from_dplane ? " (from dplane)" : ""));
if (lookup->id)
(*nhe) = zebra_nhg_lookup_id(lookup->id);
@@ -703,7 +687,10 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
(*nhe) = hash_lookup(zrouter.nhgs, lookup);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: lookup => %p (%pNG)", __func__, *nhe, *nhe);
+ zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p%s => Found %p(%pNG)",
+ __func__, lookup->id, lookup, lookup->vrf_id,
+ lookup->type, nhg_depends,
+ (from_dplane ? " (from dplane)" : ""), *nhe, *nhe);
/* If we found an existing object, we're done */
if (*nhe)
@@ -1046,31 +1033,25 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
return ctx;
}
-static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
-{
- struct nhg_connected *rb_node_dep;
-
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
-
- frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
- zebra_nhg_set_valid(rb_node_dep->nhe);
-}
-
-static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
+static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid)
{
struct nhg_connected *rb_node_dep;
- UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ if (valid)
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ else {
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
- /* If we're in shutdown, this interface event needs to clean
- * up installed NHGs, so don't clear that flag directly.
- */
- if (!zebra_router_in_shutdown())
- UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ /* If we're in shutdown, this interface event needs to clean
+ * up installed NHGs, so don't clear that flag directly.
+ */
+ if (!zebra_router_in_shutdown())
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ }
/* Update validity of nexthops depending on it */
frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
- zebra_nhg_check_valid(rb_node_dep->nhe);
+ zebra_nhg_set_valid(rb_node_dep->nhe, valid);
}
void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
@@ -1082,15 +1063,11 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
valid = true;
- goto done;
+ break;
}
}
-done:
- if (valid)
- zebra_nhg_set_valid(nhe);
- else
- zebra_nhg_set_invalid(nhe);
+ zebra_nhg_set_valid(nhe, valid);
}
static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe)
@@ -1098,8 +1075,11 @@ static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe)
/* Remove it from any lists it may be on */
zebra_nhg_depends_release(nhe);
zebra_nhg_dependents_release(nhe);
- if (nhe->ifp)
- if_nhg_dependents_del(nhe->ifp, nhe);
+ if (nhe->ifp) {
+ struct zebra_if *zif = nhe->ifp->info;
+
+ nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe);
+ }
}
static void zebra_nhg_release(struct nhg_hash_entry *nhe)
@@ -1125,13 +1105,23 @@ static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
zebra_nhg_free(nhe);
}
-static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe)
+static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install)
{
/* Update validity of groups depending on it */
struct nhg_connected *rb_node_dep;
- frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
- zebra_nhg_set_valid(rb_node_dep->nhe);
+ frr_each_safe (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
+ zebra_nhg_set_valid(rb_node_dep->nhe, true);
+ /* install dependent NHG into kernel */
+ if (install) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug(
+ "%s nh id %u (flags 0x%x) associated dependent NHG %pNG install",
+ __func__, nhe->id, nhe->flags,
+ rb_node_dep->nhe);
+ zebra_nhg_install_kernel(rb_node_dep->nhe);
+ }
+ }
}
/*
@@ -1300,6 +1290,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx)
break;
case NHG_CTX_OP_DEL:
ret = nhg_ctx_process_del(ctx);
+ break;
case NHG_CTX_OP_NONE:
break;
}
@@ -1515,19 +1506,23 @@ zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
{
struct nhg_hash_entry *nhe = NULL;
- if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
+ if (!rt_nhe) {
flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
- "No nexthop passed to %s", __func__);
+ "No nhg_hash_entry passed to %s", __func__);
return NULL;
}
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: rt_nhe %p (%pNG)", __func__, rt_nhe, rt_nhe);
+ if (!rt_nhe->nhg.nexthop) {
+ flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
+ "No nexthop passed to %s", __func__);
+ return NULL;
+ }
zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
+ zlog_debug("%s: rt_nhe %p(%pNG) => nhe %p(%pNG)", __func__,
+ rt_nhe, rt_nhe, nhe, nhe);
return nhe;
}
@@ -1858,11 +1853,18 @@ static struct nexthop *nexthop_set_resolved(afi_t afi,
labels);
if (nexthop->nh_srv6) {
- nexthop_add_srv6_seg6local(resolved_hop,
- nexthop->nh_srv6->seg6local_action,
- &nexthop->nh_srv6->seg6local_ctx);
- nexthop_add_srv6_seg6(resolved_hop,
- &nexthop->nh_srv6->seg6_segs);
+ if (nexthop->nh_srv6->seg6local_action !=
+ ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
+ nexthop_add_srv6_seg6local(resolved_hop,
+ nexthop->nh_srv6
+ ->seg6local_action,
+ &nexthop->nh_srv6
+ ->seg6local_ctx);
+ if (nexthop->nh_srv6->seg6_segs)
+ nexthop_add_srv6_seg6(resolved_hop,
+ &nexthop->nh_srv6->seg6_segs->seg[0],
+ nexthop->nh_srv6->seg6_segs
+ ->num_segs);
}
resolved_hop->rparent = nexthop;
@@ -2111,7 +2113,8 @@ zebra_nhg_connected_ifindex(struct route_node *rn, struct route_entry *match,
* of those ifindexes match as well.
*/
RNODE_FOREACH_RE (rn, re) {
- if (re->type != ZEBRA_ROUTE_CONNECT)
+ if (re->type != ZEBRA_ROUTE_CONNECT &&
+ re->type != ZEBRA_ROUTE_LOCAL)
continue;
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
@@ -2171,11 +2174,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
case NEXTHOP_TYPE_IFINDEX:
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 the interface exists and its operative, it's active */
if (ifp && (if_is_operative(ifp)))
return 1;
else
@@ -2234,20 +2233,6 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
return 1;
}
- if (top &&
- ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN &&
- nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) ||
- (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN &&
- memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) ==
- 0)) &&
- nexthop->vrf_id == vrf_id) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " :%s: Attempting to install a max prefixlength route through itself",
- __func__);
- return 0;
- }
-
/* Validation for ipv4 mapped ipv6 nexthop. */
if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
afi = AFI_IP;
@@ -2350,7 +2335,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
zlog_debug(
" %s: Matched against ourself and prefix length is not max bit length",
__func__);
- return 0;
+ goto continue_up_tree;
}
/* Pick up selected route. */
@@ -2360,60 +2345,58 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
if (is_default_prefix(&rn->p)
&& !rnh_resolve_via_default(zvrf, p.family)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " :%s: Resolved against default route",
- __func__);
+ zlog_debug(" :%s: %pFX Resolved against default route",
+ __func__, &p);
return 0;
}
dest = rib_dest_from_rnode(rn);
- if (dest && dest->selected_fib
- && !CHECK_FLAG(dest->selected_fib->status,
- ROUTE_ENTRY_REMOVED)
- && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
+ if (dest && dest->selected_fib &&
+ (!CHECK_FLAG(dest->selected_fib->status,
+ ROUTE_ENTRY_REMOVED) ||
+ CHECK_FLAG(dest->selected_fib->status,
+ ROUTE_ENTRY_ROUTE_REPLACING)) &&
+ dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
match = dest->selected_fib;
/* If there is no selected route or matched route is EGP, go up
* tree.
*/
- if (!match) {
- do {
- rn = rn->parent;
- } while (rn && rn->info == NULL);
- if (rn)
- route_lock_node(rn);
-
- continue;
- }
- if ((match->type == ZEBRA_ROUTE_CONNECT) ||
- (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) {
+ /* If the candidate match's type is considered "connected",
+ * we consider it first.
+ */
+ if (match && (RIB_CONNECTED_ROUTE(match) ||
+ (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type)))) {
match = zebra_nhg_connected_ifindex(rn, match,
nexthop->ifindex);
newhop = match->nhe->nhg.nexthop;
- if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
- nexthop->type == NEXTHOP_TYPE_IPV6)
+ if (nexthop->type == NEXTHOP_TYPE_IPV4) {
+ nexthop->ifindex = newhop->ifindex;
+ nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ } else if (nexthop->type == NEXTHOP_TYPE_IPV6) {
nexthop->ifindex = newhop->ifindex;
- else if (nexthop->ifindex != newhop->ifindex) {
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ } else if (nexthop->ifindex != newhop->ifindex) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
"%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv",
__func__, nexthop, newhop);
- /*
- * NEXTHOP_TYPE_*_IFINDEX but ifindex
- * doesn't match what we found.
- */
- return 0;
+ goto continue_up_tree;
}
+ /* NHRP special case: need to indicate onlink */
+ if (match->type == ZEBRA_ROUTE_NHRP)
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
"%s: CONNECT match %p (%pNG), newhop %pNHv",
__func__, match, match->nhe, newhop);
return 1;
- } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
+ } else if (match && CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
struct nexthop_group *nhg;
struct nexthop *resolver;
struct backup_nh_map_s map = {};
@@ -2449,6 +2432,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
"%s: match %p (%pNG) not installed or being Route Replaced",
__func__, match, match->nhe);
+ if (CHECK_FLAG(match->status,
+ ROUTE_ENTRY_QUEUED))
+ goto continue_up_tree;
+
goto done_with_match;
}
@@ -2517,25 +2504,37 @@ done_with_match:
if (pmtu)
*pmtu = match->mtu;
- } else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " %s: Recursion failed to find",
- __func__);
-
- return resolved;
- } else {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- zlog_debug(
- " %s: Route Type %s has not turned on recursion",
- __func__, zebra_route_string(type));
- if (type == ZEBRA_ROUTE_BGP
- && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
+ } else {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
+ " %s: Recursion failed to find while looking at %pRN",
+ __func__, rn);
+ goto continue_up_tree;
}
- return 0;
+
+ return 1;
+ } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ zlog_debug(
+ " %s: Route Type %s has not turned on recursion %pRN failed to match",
+ __func__, zebra_route_string(type), rn);
+ if (type == ZEBRA_ROUTE_BGP
+ && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
+ zlog_debug(
+ " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
}
+
+ continue_up_tree:
+ /*
+ * If there is no selected route or matched route is EGP, go up
+ * tree.
+ */
+ do {
+ rn = rn->parent;
+ } while (rn && rn->info == NULL);
+ if (rn)
+ route_lock_node(rn);
}
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(" %s: Nexthop did not lookup in table",
__func__);
@@ -2576,6 +2575,8 @@ static unsigned nexthop_active_check(struct route_node *rn,
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
+ vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn)));
+
/*
* If this is a kernel route, then if the interface is *up* then
* by golly gee whiz it's a good route.
@@ -2585,13 +2586,12 @@ static unsigned nexthop_active_check(struct route_node *rn,
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
- if (ifp && (if_is_operative(ifp) || if_is_up(ifp))) {
+ if (ifp && ifp->vrf->vrf_id == vrf_id && if_is_up(ifp)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
goto skip_check;
}
}
- vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn)));
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
@@ -2686,8 +2686,7 @@ skip_check:
}
/* It'll get set if required inside */
- ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
- zvrf, re->tag);
+ ret = zebra_route_map_check(family, re, p, nexthop, zvrf);
if (ret == RMAP_DENYMATCH) {
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
@@ -3080,19 +3079,26 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
/* Resolve it first */
nhe = zebra_nhg_resolve(nhe);
+ if (zebra_nhg_set_valid_if_active(nhe)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: valid flag set for nh %pNG", __func__,
+ nhe);
+ }
+
/* Make sure all depends are installed/queued */
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
zebra_nhg_install_kernel(rb_node_dep->nhe);
}
- if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)
- && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
- && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) &&
+ (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) ||
+ CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL)) &&
+ !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
/* Change its type to us since we are installing it */
if (!ZEBRA_NHG_CREATED(nhe))
nhe->type = ZEBRA_ROUTE_NHG;
- int ret = dplane_nexthop_add(nhe);
+ enum zebra_dplane_result ret = dplane_nexthop_add(nhe);
switch (ret) {
case ZEBRA_DPLANE_REQUEST_QUEUED:
@@ -3105,8 +3111,9 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
nhe);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
- zebra_nhg_handle_install(nhe);
+ flog_err(EC_ZEBRA_DP_INVALID_RC,
+ "DPlane returned an invalid result code for attempt of installation of %pNG into the kernel",
+ nhe);
break;
}
}
@@ -3153,8 +3160,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
"Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
ctx, dplane_op2str(op), id, dplane_res2str(status));
- switch (op) {
- case DPLANE_OP_NH_DELETE:
+ if (op == DPLANE_OP_NH_DELETE) {
if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
flog_err(
EC_ZEBRA_DP_DELETE_FAIL,
@@ -3162,32 +3168,32 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
id);
/* We already free'd the data, nothing to do */
- break;
- case DPLANE_OP_NH_INSTALL:
- case DPLANE_OP_NH_UPDATE:
+ } else if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) {
nhe = zebra_nhg_lookup_id(id);
if (!nhe) {
if (IS_ZEBRA_DEBUG_NHG)
- zlog_debug(
- "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
- dplane_op2str(op), id);
+ zlog_debug("%s operation performed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
+ dplane_op2str(op), id);
- break;
+ return;
}
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
- if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL);
+ switch (status) {
+ case ZEBRA_DPLANE_REQUEST_SUCCESS:
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
- zebra_nhg_handle_install(nhe);
+ zebra_nhg_handle_install(nhe, true);
/* If daemon nhg, send it an update */
if (PROTO_OWNED(nhe))
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
nhe->zapi_session, nhe->id,
ZAPI_NHG_INSTALLED);
- } else {
+ break;
+ case ZEBRA_DPLANE_REQUEST_FAILURE:
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
/* If daemon nhg, send it an update */
if (PROTO_OWNED(nhe))
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
@@ -3200,61 +3206,13 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
EC_ZEBRA_DP_INSTALL_FAIL,
"Failed to install Nexthop (%pNG) into the kernel",
nhe);
+ break;
+ case ZEBRA_DPLANE_REQUEST_QUEUED:
+ flog_err(EC_ZEBRA_DP_INVALID_RC,
+ "Dplane returned an invalid result code for a result from the dplane for %pNG into the kernel",
+ nhe);
+ break;
}
- break;
-
- case DPLANE_OP_ROUTE_INSTALL:
- case DPLANE_OP_ROUTE_UPDATE:
- case DPLANE_OP_ROUTE_DELETE:
- case DPLANE_OP_ROUTE_NOTIFY:
- case DPLANE_OP_LSP_INSTALL:
- case DPLANE_OP_LSP_UPDATE:
- case DPLANE_OP_LSP_DELETE:
- case DPLANE_OP_LSP_NOTIFY:
- case DPLANE_OP_PW_INSTALL:
- case DPLANE_OP_PW_UNINSTALL:
- case DPLANE_OP_SYS_ROUTE_ADD:
- case DPLANE_OP_SYS_ROUTE_DELETE:
- case DPLANE_OP_ADDR_INSTALL:
- case DPLANE_OP_ADDR_UNINSTALL:
- case DPLANE_OP_MAC_INSTALL:
- case DPLANE_OP_MAC_DELETE:
- case DPLANE_OP_NEIGH_INSTALL:
- case DPLANE_OP_NEIGH_UPDATE:
- case DPLANE_OP_NEIGH_DELETE:
- case DPLANE_OP_NEIGH_IP_INSTALL:
- case DPLANE_OP_NEIGH_IP_DELETE:
- case DPLANE_OP_VTEP_ADD:
- case DPLANE_OP_VTEP_DELETE:
- case DPLANE_OP_RULE_ADD:
- case DPLANE_OP_RULE_DELETE:
- case DPLANE_OP_RULE_UPDATE:
- case DPLANE_OP_NEIGH_DISCOVER:
- case DPLANE_OP_BR_PORT_UPDATE:
- case DPLANE_OP_NONE:
- case DPLANE_OP_IPTABLE_ADD:
- case DPLANE_OP_IPTABLE_DELETE:
- case DPLANE_OP_IPSET_ADD:
- case DPLANE_OP_IPSET_DELETE:
- case DPLANE_OP_IPSET_ENTRY_ADD:
- case DPLANE_OP_IPSET_ENTRY_DELETE:
- case DPLANE_OP_NEIGH_TABLE_UPDATE:
- case DPLANE_OP_GRE_SET:
- case DPLANE_OP_INTF_ADDR_ADD:
- case DPLANE_OP_INTF_ADDR_DEL:
- case DPLANE_OP_INTF_NETCONFIG:
- case DPLANE_OP_INTF_INSTALL:
- case DPLANE_OP_INTF_UPDATE:
- case DPLANE_OP_INTF_DELETE:
- case DPLANE_OP_TC_QDISC_INSTALL:
- case DPLANE_OP_TC_QDISC_UNINSTALL:
- case DPLANE_OP_TC_CLASS_ADD:
- case DPLANE_OP_TC_CLASS_DELETE:
- case DPLANE_OP_TC_CLASS_UPDATE:
- case DPLANE_OP_TC_FILTER_ADD:
- case DPLANE_OP_TC_FILTER_DELETE:
- case DPLANE_OP_TC_FILTER_UPDATE:
- break;
}
}
@@ -3397,6 +3355,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
struct nhg_connected *rb_node_dep = NULL;
struct nexthop *newhop;
bool replace = false;
+ int ret = 0;
if (!nhg->nexthop) {
if (IS_ZEBRA_DEBUG_NHG)
@@ -3494,22 +3453,31 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED))
zebra_nhg_increment_ref(old);
- rib_handle_nhg_replace(old, new);
+ ret = rib_handle_nhg_replace(old, new);
+ if (ret)
+ /*
+ * if ret > 0, some previous re->nhe has freed the
+ * address to which old_entry is pointing. Hence mark
+ * the old NHE as NULL
+ */
+ old = NULL;
+ else {
+ /* We have to decrement its singletons
+ * because some might not exist in NEW.
+ */
+ if (!zebra_nhg_depends_is_empty(old)) {
+ frr_each (nhg_connected_tree, &old->nhg_depends,
+ rb_node_dep)
+ zebra_nhg_decrement_ref(
+ rb_node_dep->nhe);
+ }
- /* We have to decrement its singletons
- * because some might not exist in NEW.
- */
- if (!zebra_nhg_depends_is_empty(old)) {
- frr_each (nhg_connected_tree, &old->nhg_depends,
- rb_node_dep)
- zebra_nhg_decrement_ref(rb_node_dep->nhe);
+ /* Dont call the dec API, we dont want to uninstall the ID */
+ old->refcnt = 0;
+ EVENT_OFF(old->timer);
+ zebra_nhg_free(old);
+ old = NULL;
}
-
- /* Dont call the dec API, we dont want to uninstall the ID */
- old->refcnt = 0;
- EVENT_OFF(old->timer);
- zebra_nhg_free(old);
- old = NULL;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
@@ -3614,7 +3582,18 @@ unsigned long zebra_nhg_score_proto(int type)
* This should be the last ref if we remove client routes too,
* and thus should remove and free them.
*/
- zebra_nhg_decrement_ref(nhe);
+ if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED))
+ zebra_nhg_decrement_ref(nhe);
+ else {
+
+ /* protocol sends explicit delete of nhg, the
+ * nhe->refcount is decremented in zread_nhg_del()
+ */
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug(
+ "%s: nhe %u (%p) refcount %u already decremented in zread_nhg_del",
+ __func__, nhe->id, nhe, nhe->refcnt);
+ }
}
count = iter.found->count;
@@ -3651,3 +3630,70 @@ static ssize_t printfrr_nhghe(struct fbuf *buf, struct printfrr_eargs *ea,
ret += bputs(buf, "]");
return ret;
}
+
+/*
+ * On interface add the nexthop that resolves to this intf needs
+ * a re-install. There are following scenarios when the nexthop group update
+ * gets skipped:
+ * 1. When upper level protocol sends removal of NHG, there is
+ * timer running to keep NHG for 180 seconds, during this interval, same route
+ * with same set of nexthops installation is given , the same NHG is used
+ * but since NHG is not reinstalled on interface address add, it is not aware
+ * in Dplan/Kernel.
+ * 2. Due to a quick port flap due to interface add and delete
+ * to be processed in same queue one after another. Zebra believes that
+ * there is no change in nhg in this case. Hence this re-install will
+ * make sure the nexthop group gets updated to Dplan/Kernel.
+ */
+void zebra_interface_nhg_reinstall(struct interface *ifp)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+ struct zebra_if *zif = ifp->info;
+ struct nexthop *nh;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug(
+ "%s: Installing interface %s associated NHGs into kernel",
+ __func__, ifp->name);
+
+ frr_each (nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) {
+ nh = rb_node_dep->nhe->nhg.nexthop;
+ if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug(
+ "%s: Setting the valid flag for nhe %pNG, interface: %s",
+ __func__, rb_node_dep->nhe, ifp->name);
+ }
+ /* Check for singleton NHG associated to interface */
+ if (nexthop_is_ifindex_type(nh) &&
+ zebra_nhg_depends_is_empty(rb_node_dep->nhe)) {
+ struct nhg_connected *rb_node_dependent;
+
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s install nhe %pNG nh type %u flags 0x%x",
+ __func__, rb_node_dep->nhe, nh->type,
+ rb_node_dep->nhe->flags);
+ zebra_nhg_install_kernel(rb_node_dep->nhe);
+
+ /* Don't need to modify dependents if installed */
+ if (CHECK_FLAG(rb_node_dep->nhe->flags,
+ NEXTHOP_GROUP_INSTALLED))
+ continue;
+
+ /* mark dependent uninstalled; when interface associated
+ * singleton is installed, install dependent
+ */
+ frr_each_safe (nhg_connected_tree,
+ &rb_node_dep->nhe->nhg_dependents,
+ rb_node_dependent) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s dependent nhe %pNG Setting Reinstall flag",
+ __func__,
+ rb_node_dependent->nhe);
+ SET_FLAG(rb_node_dependent->nhe->flags,
+ NEXTHOP_GROUP_REINSTALL);
+ }
+ }
+ }
+}