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.c94
1 files changed, 84 insertions, 10 deletions
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 7edf022892..47651318a4 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -845,6 +845,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
done:
+ /* Reset time since last update */
+ (*nhe)->uptime = monotime(NULL);
return created;
}
@@ -990,7 +992,7 @@ static struct nhg_ctx *nhg_ctx_new(void)
return new;
}
-static void nhg_ctx_free(struct nhg_ctx **ctx)
+void nhg_ctx_free(struct nhg_ctx **ctx)
{
struct nexthop *nh;
@@ -1191,6 +1193,13 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: nhe %p (%u) is new", __func__, nhe, nhe->id);
+ /*
+ * If daemon nhg from the kernel, add a refcnt here to indicate the
+ * daemon owns it.
+ */
+ if (PROTO_OWNED(nhe))
+ zebra_nhg_increment_ref(nhe);
+
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
@@ -1233,7 +1242,7 @@ static int queue_add(struct nhg_ctx *ctx)
if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
return 0;
- if (rib_queue_nhg_add(ctx)) {
+ if (rib_queue_nhg_ctx_add(ctx)) {
nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
return -1;
}
@@ -1811,12 +1820,11 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop,
int i, j, idx;
const struct nexthop *bnh;
struct nexthop *nh, *newnh;
+ mpls_label_t labels[MPLS_MAX_LABELS];
+ uint8_t num_labels;
assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
- if (resolve_nhe->backup_info->nhe == NULL)
- resolve_nhe->backup_info->nhe = zebra_nhg_alloc();
-
/* Locate backups from the original nexthop's backup index and nhe */
for (i = 0; i < nexthop->backup_num; i++) {
idx = nexthop->backup_idx[i];
@@ -1832,6 +1840,8 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop,
map->map[j].new_idx;
resolved->backup_num++;
+ SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%s: found map idx orig %d, new %d",
__func__, map->map[j].orig_idx,
@@ -1856,9 +1866,46 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop,
if (bnh == NULL)
continue;
+ if (resolve_nhe->backup_info == NULL)
+ resolve_nhe->backup_info = zebra_nhg_backup_alloc();
+
/* Update backup info in the resolving nexthop and its nhe */
newnh = nexthop_dup_no_recurse(bnh, NULL);
+ /* We may need some special handling for mpls labels: the new
+ * backup needs to carry the recursive nexthop's labels,
+ * if any: they may be vrf labels e.g.
+ * The original/inner labels are in the stack of 'resolve_nhe',
+ * if that is longer than the stack in 'nexthop'.
+ */
+ if (newnh->nh_label && resolved->nh_label &&
+ nexthop->nh_label) {
+ if (resolved->nh_label->num_labels >
+ nexthop->nh_label->num_labels) {
+ /* Prepare new label stack */
+ num_labels = 0;
+ for (j = 0; j < newnh->nh_label->num_labels;
+ j++) {
+ labels[j] = newnh->nh_label->label[j];
+ num_labels++;
+ }
+
+ /* Include inner labels */
+ for (j = nexthop->nh_label->num_labels;
+ j < resolved->nh_label->num_labels;
+ j++) {
+ labels[num_labels] =
+ resolved->nh_label->label[j];
+ num_labels++;
+ }
+
+ /* Replace existing label stack in the backup */
+ nexthop_del_labels(newnh);
+ nexthop_add_labels(newnh, bnh->nh_label_type,
+ num_labels, labels);
+ }
+ }
+
/* Need to compute the new backup index in the new
* backup list, and add to map struct.
*/
@@ -1871,6 +1918,7 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop,
}
nh->next = newnh;
+ j++;
} else /* First one */
resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
@@ -1879,6 +1927,8 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop,
resolved->backup_idx[resolved->backup_num] = j;
resolved->backup_num++;
+ SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%s: added idx orig %d, new %d",
__func__, idx, j);
@@ -2559,7 +2609,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
struct nhg_hash_entry *curr_nhe;
uint32_t curr_active = 0, backup_active = 0;
- if (re->nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ if (PROTO_OWNED(re->nhe))
return proto_nhg_nexthop_active_update(&re->nhe->nhg);
afi_t rt_afi = family2afi(rn->p.family);
@@ -2861,13 +2911,13 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
zebra_nhg_handle_install(nhe);
/* If daemon nhg, send it an update */
- if (nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ if (PROTO_OWNED(nhe))
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
nhe->zapi_session, nhe->id,
ZAPI_NHG_INSTALLED);
} else {
/* If daemon nhg, send it an update */
- if (nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ if (PROTO_OWNED(nhe))
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
nhe->zapi_session, nhe->id,
ZAPI_NHG_FAIL_INSTALL);
@@ -2927,7 +2977,31 @@ static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
nhe = (struct nhg_hash_entry *)bucket->data;
- /* If its being ref'd, just let it be uninstalled via a route removal */
+ /*
+ * same logic as with routes.
+ *
+ * If older than startup time, we know we read them in from the
+ * kernel and have not gotten and update for them since startup
+ * from an upper level proto.
+ */
+ if (zrouter.startup_time < nhe->uptime)
+ return;
+
+ /*
+ * If it's proto-owned and not being used by a route, remove it since
+ * we haven't gotten an update about it from the proto since startup.
+ * This means that either the config for it was removed or the daemon
+ * didn't get started. This handles graceful restart & retain scenario.
+ */
+ if (PROTO_OWNED(nhe) && nhe->refcnt == 1) {
+ zebra_nhg_decrement_ref(nhe);
+ return;
+ }
+
+ /*
+ * If its being ref'd by routes, just let it be uninstalled via a route
+ * removal.
+ */
if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
zebra_nhg_uninstall_kernel(nhe);
}
@@ -3201,7 +3275,7 @@ static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg)
iter = arg;
/* Needs to match type and outside zebra ID space */
- if (nhe->type == iter->type && nhe->id >= ZEBRA_NHG_PROTO_LOWER) {
+ if (nhe->type == iter->type && PROTO_OWNED(nhe)) {
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
"%s: found nhe %p (%u), vrf %d, type %s after client disconnect",