summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2020-07-10 10:54:59 -0400
committerGitHub <noreply@github.com>2020-07-10 10:54:59 -0400
commit373edbbc9975f2ebeae7d019eb386f48b53d2696 (patch)
treee0608f138ac01dc9d09557ea1123b8ffd40899a0
parentf24db7598ef269f269992e8ab8e38d370d60dfd2 (diff)
parentc3753405d5bbe8890711dd1bb50d9965cfb46e65 (diff)
Merge pull request #6530 from mjstapp/backup_nhg_notify
lib, zebra: async notifications for backup routes and LSPs
-rw-r--r--lib/nexthop.c22
-rw-r--r--lib/nexthop.h3
-rw-r--r--sharpd/sharp_zebra.c6
-rw-r--r--staticd/static_zebra.c1
-rw-r--r--tests/topotests/zebra_rib/r1/v4_route_1_static_override.json2
-rw-r--r--zebra/rib.h18
-rw-r--r--zebra/zapi_msg.c2
-rw-r--r--zebra/zebra_dplane.c69
-rw-r--r--zebra/zebra_dplane.h14
-rw-r--r--zebra/zebra_mpls.c504
-rw-r--r--zebra/zebra_mpls.h13
-rw-r--r--zebra/zebra_nhg.c68
-rw-r--r--zebra/zebra_pw.c4
-rw-r--r--zebra/zebra_rib.c282
-rw-r--r--zebra/zebra_rnh.c156
-rw-r--r--zebra/zebra_vty.c418
16 files changed, 973 insertions, 609 deletions
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 0d239e091b..3496081d47 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -187,35 +187,41 @@ int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2)
return ret;
}
-int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2)
+bool nexthop_same_firsthop(const struct nexthop *next1,
+ const struct nexthop *next2)
{
+ /* Map the TYPE_IPx types to TYPE_IPx_IFINDEX */
int type1 = NEXTHOP_FIRSTHOPTYPE(next1->type);
int type2 = NEXTHOP_FIRSTHOPTYPE(next2->type);
if (type1 != type2)
- return 0;
+ return false;
+
+ if (next1->vrf_id != next2->vrf_id)
+ return false;
+
switch (type1) {
case NEXTHOP_TYPE_IPV4_IFINDEX:
if (!IPV4_ADDR_SAME(&next1->gate.ipv4, &next2->gate.ipv4))
- return 0;
+ return false;
if (next1->ifindex != next2->ifindex)
- return 0;
+ return false;
break;
case NEXTHOP_TYPE_IFINDEX:
if (next1->ifindex != next2->ifindex)
- return 0;
+ return false;
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
- return 0;
+ return false;
if (next1->ifindex != next2->ifindex)
- return 0;
+ return false;
break;
default:
/* do nothing */
break;
}
- return 1;
+ return true;
}
/*
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 9b71262589..eda88efc08 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -208,7 +208,8 @@ extern int nexthop_g_addr_cmp(enum nexthop_types_t type,
extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type);
extern bool nexthop_labels_match(const struct nexthop *nh1,
const struct nexthop *nh2);
-extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2);
+extern bool nexthop_same_firsthop(const struct nexthop *next1,
+ const struct nexthop *next2);
extern const char *nexthop2str(const struct nexthop *nexthop,
char *str, int size);
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index c47f2105cb..7ab2d6ec22 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -435,6 +435,12 @@ static int sharp_debug_nexthops(struct zapi_route *api)
int i;
char buf[PREFIX_STRLEN];
+ if (api->nexthop_num == 0) {
+ zlog_debug(
+ " Not installed");
+ return 0;
+ }
+
for (i = 0; i < api->nexthop_num; i++) {
struct zapi_nexthop *znh = &api->nexthops[i];
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index 5cadf34365..c42f632ffb 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -363,6 +363,7 @@ extern void static_zebra_route_add(struct route_node *rn,
memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
}
SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
if (si_changed->distance) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
diff --git a/tests/topotests/zebra_rib/r1/v4_route_1_static_override.json b/tests/topotests/zebra_rib/r1/v4_route_1_static_override.json
index aa9522aff6..22e199f9aa 100644
--- a/tests/topotests/zebra_rib/r1/v4_route_1_static_override.json
+++ b/tests/topotests/zebra_rib/r1/v4_route_1_static_override.json
@@ -10,7 +10,7 @@
"installed":true,
"table":254,
"internalStatus":16,
- "internalFlags":72,
+ "internalFlags":73,
"internalNextHopNum":1,
"internalNextHopActiveNum":1,
"nexthops":[
diff --git a/zebra/rib.h b/zebra/rib.h
index a024b6dfaa..ec992974fa 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -94,9 +94,11 @@ struct route_entry {
struct nhg_hash_entry *nhe;
/* Nexthop group from FIB (optional), reflecting what is actually
- * installed in the FIB if that differs.
+ * installed in the FIB if that differs. The 'backup' group is used
+ * when backup nexthops are present in the route's nhg.
*/
struct nexthop_group fib_ng;
+ struct nexthop_group fib_backup_ng;
/* Nexthop group hash entry ID */
uint32_t nhe_id;
@@ -526,7 +528,7 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
/*
* Access active nexthop-group, either RIB or FIB version
*/
-static inline struct nexthop_group *rib_active_nhg(struct route_entry *re)
+static inline struct nexthop_group *rib_get_fib_nhg(struct route_entry *re)
{
if (re->fib_ng.nexthop)
return &(re->fib_ng);
@@ -534,6 +536,18 @@ static inline struct nexthop_group *rib_active_nhg(struct route_entry *re)
return &(re->nhe->nhg);
}
+/*
+ * Access active nexthop-group, either RIB or FIB version
+ */
+static inline struct nexthop_group *rib_get_fib_backup_nhg(
+ struct route_entry *re)
+{
+ if (re->fib_backup_ng.nexthop)
+ return &(re->fib_backup_ng);
+ else
+ return zebra_nhg_get_backup_nhg(re->nhe);
+}
+
extern void zebra_vty_init(void);
extern pid_t pid;
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index a40aa8b643..dc7c595d26 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2485,7 +2485,7 @@ static void zread_vrf_label(ZAPI_HANDLER_ARGS)
if (really_remove)
mpls_lsp_uninstall(def_zvrf, ltype, zvrf->label[afi],
NEXTHOP_TYPE_IFINDEX, NULL,
- ifp->ifindex);
+ ifp->ifindex, false /*backup*/);
}
if (nlabel != MPLS_LABEL_NONE) {
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 64383fc81c..e34b6f23ff 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -1149,6 +1149,37 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
}
+/*
+ * Set the list of backup nexthops; their ordering is preserved (they're not
+ * re-sorted.)
+ */
+void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
+ const struct nexthop_group *nhg)
+{
+ struct nexthop *nh, *last_nh, *nexthop;
+
+ DPLANE_CTX_VALID(ctx);
+
+ if (ctx->u.rinfo.backup_ng.nexthop) {
+ nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
+ ctx->u.rinfo.backup_ng.nexthop = NULL;
+ }
+
+ last_nh = NULL;
+
+ /* Be careful to preserve the order of the backup list */
+ for (nh = nhg->nexthop; nh; nh = nh->next) {
+ nexthop = nexthop_dup(nh, NULL);
+
+ if (last_nh)
+ NEXTHOP_APPEND(last_nh, nexthop);
+ else
+ ctx->u.rinfo.backup_ng.nexthop = nexthop;
+
+ last_nh = nexthop;
+ }
+}
+
uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -1303,7 +1334,7 @@ const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list(
zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
enum lsp_types_t lsp_type,
enum nexthop_types_t nh_type,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
mpls_label_t *out_labels)
@@ -1322,7 +1353,7 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
zebra_nhlfe_t *dplane_ctx_add_backup_nhlfe(struct zebra_dplane_ctx *ctx,
enum lsp_types_t lsp_type,
enum nexthop_types_t nh_type,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
mpls_label_t *out_labels)
@@ -1921,18 +1952,12 @@ done:
/*
* Capture information for an LSP update in a dplane context.
*/
-static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx,
- enum dplane_op_e op,
- zebra_lsp_t *lsp)
+int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ zebra_lsp_t *lsp)
{
int ret = AOK;
zebra_nhlfe_t *nhlfe, *new_nhlfe;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
- dplane_op2str(op), lsp->ile.in_label,
- lsp->num_ecmp);
-
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
@@ -1944,6 +1969,20 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx,
nhlfe_list_init(&(ctx->u.lsp.nhlfe_list));
nhlfe_list_init(&(ctx->u.lsp.backup_nhlfe_list));
+
+ /* This may be called to create/init a dplane context, not necessarily
+ * to copy an lsp object.
+ */
+ if (lsp == NULL) {
+ ret = AOK;
+ goto done;
+ }
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
+ dplane_op2str(op), lsp->ile.in_label,
+ lsp->num_ecmp);
+
ctx->u.lsp.ile = lsp->ile;
ctx->u.lsp.addr_family = lsp->addr_family;
ctx->u.lsp.num_ecmp = lsp->num_ecmp;
@@ -2012,6 +2051,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
struct route_table *table;
struct route_node *rn;
struct route_entry *re;
+ const struct nexthop_group *nhg;
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
@@ -2062,10 +2102,11 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
break;
}
- if (re)
+ if (re) {
+ nhg = rib_get_fib_nhg(re);
copy_nexthops(&(ctx->u.pw.nhg.nexthop),
- re->nhe->nhg.nexthop, NULL);
-
+ nhg->nexthop, NULL);
+ }
route_unlock_node(rn);
}
}
@@ -2442,7 +2483,7 @@ dplane_route_notif_update(struct route_node *rn,
new_ctx->u.rinfo.zd_ng.nexthop = NULL;
copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
- (rib_active_nhg(re))->nexthop, NULL);
+ (rib_get_fib_nhg(re))->nexthop, NULL);
for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 9e07231fea..8e873886df 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -283,6 +283,8 @@ void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
+void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
+ const struct nexthop_group *nhg);
uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx);
const struct nexthop_group *dplane_ctx_get_ng(
@@ -308,6 +310,14 @@ dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx);
uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx);
/* Accessors for LSP information */
+
+/* Init the internal LSP data struct - necessary before adding to it.
+ * If 'lsp' is non-NULL, info will be copied from it to the internal
+ * context data area.
+ */
+int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ zebra_lsp_t *lsp);
+
mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx,
mpls_label_t label);
@@ -325,7 +335,7 @@ const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list(
zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
enum lsp_types_t lsp_type,
enum nexthop_types_t nh_type,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
mpls_label_t *out_labels);
@@ -333,7 +343,7 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
zebra_nhlfe_t *dplane_ctx_add_backup_nhlfe(struct zebra_dplane_ctx *ctx,
enum lsp_types_t lsp_type,
enum nexthop_types_t nh_type,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
mpls_label_t *out_labels);
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 8ee8601689..e741268ebb 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -110,17 +110,14 @@ static zebra_nhlfe_t *nhlfe_find(struct nhlfe_list_head *list,
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
enum nexthop_types_t gtype,
const union g_addr *gate, ifindex_t ifindex,
- uint8_t num_labels, const mpls_label_t *labels);
+ uint8_t num_labels, const mpls_label_t *labels,
+ bool is_backup);
static int nhlfe_del(zebra_nhlfe_t *nhlfe);
static void nhlfe_free(zebra_nhlfe_t *nhlfe);
static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
struct mpls_label_stack *nh_label);
static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
enum lsp_types_t type);
-static int lsp_backup_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
- mpls_label_t in_label,
- enum nexthop_types_t gtype,
- const union g_addr *gate, ifindex_t ifindex);
static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
mpls_label_t in_label);
static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty);
@@ -167,6 +164,15 @@ static void clear_nhlfe_installed(zebra_lsp_t *lsp)
UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
+
+ frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
+ nexthop = nhlfe->nexthop;
+ if (!nexthop)
+ continue;
+
+ UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
}
/*
@@ -240,7 +246,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type,
&nexthop->gate, nexthop->ifindex,
nexthop->nh_label->num_labels,
- nexthop->nh_label->label);
+ nexthop->nh_label->label,
+ false /*backup*/);
if (!nhlfe)
return -1;
@@ -797,8 +804,7 @@ static void lsp_select_best_nhlfe(zebra_lsp_t *lsp)
/*
* First compute the best path, after checking nexthop status. We are
- * only
- * concerned with non-deleted NHLFEs.
+ * only concerned with non-deleted NHLFEs.
*/
frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
/* Clear selection flags. */
@@ -816,6 +822,14 @@ static void lsp_select_best_nhlfe(zebra_lsp_t *lsp)
if (!lsp->best_nhlfe)
return;
+ /*
+ * Check the active status of backup nhlfes also
+ */
+ frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
+ if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
+ (void)nhlfe_nexthop_active(nhlfe);
+ }
+
/* Mark best NHLFE as selected. */
SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
@@ -910,9 +924,9 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
if (IS_ZEBRA_DEBUG_MPLS) {
if (oldbest)
- nhlfe2str(oldbest, buf, BUFSIZ);
+ nhlfe2str(oldbest, buf, sizeof(buf));
if (newbest)
- nhlfe2str(newbest, buf2, BUFSIZ);
+ nhlfe2str(newbest, buf2, sizeof(buf2));
zlog_debug(
"Process LSP in-label %u oldbest %s newbest %s "
"flags 0x%x ecmp# %d",
@@ -1310,13 +1324,14 @@ static zebra_nhlfe_t *nhlfe_alloc(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
}
/*
- * Add NHLFE. Base entry must have been created and duplicate
- * check done.
+ * Add primary or backup NHLFE. Base entry must have been created and
+ * duplicate check done.
*/
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
enum nexthop_types_t gtype,
const union g_addr *gate, ifindex_t ifindex,
- uint8_t num_labels, const mpls_label_t *labels)
+ uint8_t num_labels, const mpls_label_t *labels,
+ bool is_backup)
{
zebra_nhlfe_t *nhlfe;
@@ -1327,36 +1342,12 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
labels);
- /* Enqueue to LSP, at head of list. */
- nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
-
- return nhlfe;
-}
-
-/*
- * Add backup NHLFE. Base entry must have been created and duplicate
- * check done.
- */
-static zebra_nhlfe_t *nhlfe_backup_add(zebra_lsp_t *lsp,
- enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype,
- const union g_addr *gate,
- ifindex_t ifindex, uint8_t num_labels,
- const mpls_label_t *labels)
-{
- zebra_nhlfe_t *nhlfe;
-
- if (!lsp)
- return NULL;
-
- /* Allocate new object */
- nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
- labels);
-
- SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
-
- /* Enqueue to LSP, at tail of list. */
- nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
+ /* Enqueue to LSP: primaries at head of list, backups at tail */
+ if (is_backup) {
+ SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
+ nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
+ } else
+ nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
return nhlfe;
}
@@ -1590,6 +1581,9 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
break;
}
vty_out(vty, "%s",
+ CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
+ : "");
+ vty_out(vty, "%s",
CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
: "");
vty_out(vty, "\n");
@@ -1616,6 +1610,7 @@ static void lsp_print(struct vty *vty, zebra_lsp_t *lsp)
/* Find backup in backup list */
i = 0;
+ backup = NULL;
frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
if (i == nhlfe->nexthop->backup_idx)
break;
@@ -1933,23 +1928,27 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
/* TODO -- Confirm that this result is still 'current' */
- if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
- /* Update zebra object */
- SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
- frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
- nexthop = nhlfe->nexthop;
- if (!nexthop)
- continue;
-
- SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
- } else {
+ if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
clear_nhlfe_installed(lsp);
flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
"LSP Install Failure: in-label %u",
lsp->ile.in_label);
+ break;
+ }
+
+ /* Update zebra object */
+ SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+ frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
+ nexthop = nhlfe->nexthop;
+ if (!nexthop)
+ continue;
+
+ if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
+ SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
}
break;
@@ -1970,53 +1969,23 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
}
/*
- * Process async dplane notifications.
+ * Process LSP installation info from two sets of nhlfes: a set from
+ * a dplane notification, and a set from the zebra LSP object. Update
+ * counters of installed nexthops, and return whether the LSP has changed.
*/
-void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
+static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
+ struct nhlfe_list_head *nhlfe_head,
+ int *start_counter, int *end_counter)
{
- struct zebra_vrf *zvrf;
- zebra_ile_t tmp_ile;
- struct hash *lsp_table;
- zebra_lsp_t *lsp;
zebra_nhlfe_t *nhlfe;
- const struct nhlfe_list_head *head;
const zebra_nhlfe_t *ctx_nhlfe;
struct nexthop *nexthop;
const struct nexthop *ctx_nexthop;
- int start_count = 0, end_count = 0; /* Installed counts */
+ int start_count = 0, end_count = 0;
bool changed_p = false;
bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
- if (is_debug)
- zlog_debug("LSP dplane notif, in-label %u",
- dplane_ctx_get_in_label(ctx));
-
- /* Look for zebra LSP object */
- zvrf = vrf_info_lookup(VRF_DEFAULT);
- if (zvrf == NULL)
- goto done;
-
- lsp_table = zvrf->lsp_table;
-
- tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
- lsp = hash_lookup(lsp_table, &tmp_ile);
- if (lsp == NULL) {
- if (is_debug)
- zlog_debug("dplane LSP notif: in-label %u not found",
- dplane_ctx_get_in_label(ctx));
- goto done;
- }
-
- /*
- * The dataplane/forwarding plane is notifying zebra about the state
- * of the nexthops associated with this LSP. First, we take a
- * pre-scan pass to determine whether the LSP has transitioned
- * from installed -> uninstalled. In that case, we need to have
- * the existing state of the LSP objects available before making
- * any changes.
- */
- head = dplane_ctx_get_nhlfe_list(ctx);
- frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
+ frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
char buf[NEXTHOP_STRLEN];
nexthop = nhlfe->nexthop;
@@ -2026,8 +1995,9 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
start_count++;
+ ctx_nhlfe = NULL;
ctx_nexthop = NULL;
- frr_each(nhlfe_list_const, head, ctx_nhlfe) {
+ frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
ctx_nexthop = ctx_nhlfe->nexthop;
if (!ctx_nexthop)
continue;
@@ -2085,32 +2055,39 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
}
}
- if (is_debug)
- zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
- start_count, end_count,
- changed_p ? ", changed" : "");
+ if (start_counter)
+ *start_counter += start_count;
+ if (end_counter)
+ *end_counter += end_count;
- /*
- * Has the LSP become uninstalled?
- */
- if (start_count > 0 && end_count == 0) {
- /* Inform other lfibs */
- dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
- }
+ return changed_p;
+}
- /*
- * Now we take a second pass and bring the zebra
- * nexthop state into sync with the forwarding-plane state.
- */
- frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
+/*
+ * Update an lsp nhlfe list from a dplane context, typically an async
+ * notification context. Update the LSP list to match the installed
+ * status from the context's list.
+ */
+static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
+ const struct nhlfe_list_head *ctx_head)
+{
+ int ret = 0;
+ zebra_nhlfe_t *nhlfe;
+ const zebra_nhlfe_t *ctx_nhlfe;
+ struct nexthop *nexthop;
+ const struct nexthop *ctx_nexthop;
+ bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
+
+ frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
char buf[NEXTHOP_STRLEN];
nexthop = nhlfe->nexthop;
if (!nexthop)
continue;
+ ctx_nhlfe = NULL;
ctx_nexthop = NULL;
- frr_each(nhlfe_list_const, head, ctx_nhlfe) {
+ frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
ctx_nexthop = ctx_nhlfe->nexthop;
if (!ctx_nexthop)
continue;
@@ -2130,10 +2107,16 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/* Bring zebra nhlfe install state into sync */
if (CHECK_FLAG(ctx_nhlfe->flags,
NHLFE_FLAG_INSTALLED)) {
+ if (is_debug)
+ zlog_debug("%s: matched lsp nhlfe %s (installed)",
+ __func__, buf);
SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
} else {
+ if (is_debug)
+ zlog_debug("%s: matched lsp nhlfe %s (not installed)",
+ __func__, buf);
UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
}
@@ -2153,13 +2136,101 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
} else {
/* Not mentioned in lfib set -> uninstalled */
-
+ if (is_debug)
+ zlog_debug("%s: no match for lsp nhlfe %s",
+ __func__, buf);
UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
}
+ return ret;
+}
+
+/*
+ * Process async dplane notifications.
+ */
+void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
+{
+ struct zebra_vrf *zvrf;
+ zebra_ile_t tmp_ile;
+ struct hash *lsp_table;
+ zebra_lsp_t *lsp;
+ const struct nhlfe_list_head *ctx_list;
+ int start_count = 0, end_count = 0; /* Installed counts */
+ bool changed_p = false;
+ bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
+
+ if (is_debug)
+ zlog_debug("LSP dplane notif, in-label %u",
+ dplane_ctx_get_in_label(ctx));
+
+ /* Look for zebra LSP object */
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (zvrf == NULL)
+ goto done;
+
+ lsp_table = zvrf->lsp_table;
+
+ tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
+ lsp = hash_lookup(lsp_table, &tmp_ile);
+ if (lsp == NULL) {
+ if (is_debug)
+ zlog_debug("dplane LSP notif: in-label %u not found",
+ dplane_ctx_get_in_label(ctx));
+ goto done;
+ }
+
+ /*
+ * The dataplane/forwarding plane is notifying zebra about the state
+ * of the nexthops associated with this LSP. First, we take a
+ * pre-scan pass to determine whether the LSP has transitioned
+ * from installed -> uninstalled. In that case, we need to have
+ * the existing state of the LSP objects available before making
+ * any changes.
+ */
+ ctx_list = dplane_ctx_get_nhlfe_list(ctx);
+
+ changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
+ &start_count, &end_count);
+
+ if (is_debug)
+ zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
+ start_count, end_count,
+ changed_p ? ", changed" : "");
+
+ ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
+
+ if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
+ &start_count, &end_count))
+ /* Avoid accidentally setting back to 'false' */
+ changed_p = true;
+
+ if (is_debug)
+ zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
+ start_count, end_count,
+ changed_p ? ", changed" : "");
+
+ /*
+ * Has the LSP become uninstalled? We need the existing state of the
+ * nexthops/nhlfes at this point so we know what to delete.
+ */
+ if (start_count > 0 && end_count == 0) {
+ /* Inform other lfibs */
+ dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
+ }
+
+ /*
+ * Now we take a second pass and bring the zebra
+ * nexthop state into sync with the forwarding-plane state.
+ */
+ ctx_list = dplane_ctx_get_nhlfe_list(ctx);
+ update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
+
+ ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
+ update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
+
if (end_count > 0) {
SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
@@ -2234,14 +2305,14 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
enum lsp_types_t lsp_type,
enum nexthop_types_t gtype,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
const mpls_label_t *out_labels)
{
/* Just a public pass-through to the internal implementation */
return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
- out_labels);
+ out_labels, false /*backup*/);
}
/*
@@ -2252,14 +2323,14 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
zebra_nhlfe_t *zebra_mpls_lsp_add_backup_nhlfe(zebra_lsp_t *lsp,
enum lsp_types_t lsp_type,
enum nexthop_types_t gtype,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
const mpls_label_t *out_labels)
{
/* Just a public pass-through to the internal implementation */
- return nhlfe_backup_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
- out_labels);
+ return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
+ out_labels, true);
}
/*
@@ -2275,7 +2346,8 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nh(zebra_lsp_t *lsp,
return NULL;
nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex,
- nh->nh_label->num_labels, nh->nh_label->label);
+ nh->nh_label->num_labels, nh->nh_label->label,
+ false /*backup*/);
return nhlfe;
}
@@ -2293,9 +2365,9 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_backup_nh(zebra_lsp_t *lsp,
if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
return NULL;
- nhlfe = nhlfe_backup_add(lsp, lsp_type, nh->type, &nh->gate,
+ nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate,
nh->ifindex, nh->nh_label->num_labels,
- nh->nh_label->label);
+ nh->nh_label->label, true);
return nhlfe;
}
@@ -2846,6 +2918,9 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+ /* This will create (or ref) a new nhe, so we will discard the local
+ * temporary nhe
+ */
mpls_zebra_nhe_update(re, afi, new_nhe);
zebra_nhg_free(new_nhe);
@@ -3013,7 +3088,8 @@ int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
else
ret = mpls_lsp_uninstall(zvrf, zl->type,
zl->local_label, znh->type,
- &znh->gate, znh->ifindex);
+ &znh->gate, znh->ifindex,
+ false);
if (ret < 0) {
if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) {
zapi_nexthop2str(znh, buf, sizeof(buf));
@@ -3055,10 +3131,10 @@ int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
if (add_p)
ret = lsp_backup_znh_install(lsp, zl->type, znh);
else
- ret = lsp_backup_uninstall(zvrf, zl->type,
- zl->local_label,
- znh->type, &znh->gate,
- znh->ifindex);
+ ret = mpls_lsp_uninstall(zvrf, zl->type,
+ zl->local_label,
+ znh->type, &znh->gate,
+ znh->ifindex, true);
if (ret < 0) {
if (IS_ZEBRA_DEBUG_RECV ||
@@ -3123,92 +3199,22 @@ static zebra_nhlfe_t *
lsp_add_nhlfe(zebra_lsp_t *lsp, enum lsp_types_t type,
uint8_t num_out_labels, const mpls_label_t *out_labels,
enum nexthop_types_t gtype, const union g_addr *gate,
- ifindex_t ifindex)
+ ifindex_t ifindex, bool is_backup)
{
zebra_nhlfe_t *nhlfe;
char buf[MPLS_LABEL_STRLEN];
+ const char *backup_str;
- nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate, ifindex);
- if (nhlfe) {
- struct nexthop *nh = nhlfe->nexthop;
-
- assert(nh);
- assert(nh->nh_label);
-
- /* Clear deleted flag (in case it was set) */
- UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
- if (nh->nh_label->num_labels == num_out_labels
- && !memcmp(nh->nh_label->label, out_labels,
- sizeof(mpls_label_t) * num_out_labels))
- /* No change */
- return nhlfe;
-
- if (IS_ZEBRA_DEBUG_MPLS) {
- char buf2[MPLS_LABEL_STRLEN];
- char buf3[MPLS_LABEL_STRLEN];
-
- nhlfe2str(nhlfe, buf, sizeof(buf));
- mpls_label2str(num_out_labels, out_labels, buf2,
- sizeof(buf2), 0);
- mpls_label2str(nh->nh_label->num_labels,
- nh->nh_label->label, buf3, sizeof(buf3),
- 0);
-
- zlog_debug("LSP in-label %u type %d nexthop %s out-label(s) changed to %s (old %s)",
- lsp->ile.in_label, type, buf, buf2, buf3);
- }
-
- /* Update out label(s), trigger processing. */
- if (nh->nh_label->num_labels == num_out_labels)
- memcpy(nh->nh_label->label, out_labels,
- sizeof(mpls_label_t) * num_out_labels);
- else {
- nexthop_del_labels(nh);
- nexthop_add_labels(nh, type, num_out_labels,
- out_labels);
- }
+ if (is_backup) {
+ nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
+ gate, ifindex);
+ backup_str = "backup ";
} else {
- /* Add LSP entry to this nexthop */
- nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex,
- num_out_labels, out_labels);
- if (!nhlfe)
- return NULL;
-
- if (IS_ZEBRA_DEBUG_MPLS) {
- char buf2[MPLS_LABEL_STRLEN];
-
- nhlfe2str(nhlfe, buf, sizeof(buf));
- mpls_label2str(num_out_labels, out_labels, buf2,
- sizeof(buf2), 0);
-
- zlog_debug("Add LSP in-label %u type %d nexthop %s out-label(s) %s",
- lsp->ile.in_label, type, buf, buf2);
- }
-
- lsp->addr_family = NHLFE_FAMILY(nhlfe);
+ nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
+ ifindex);
+ backup_str = "";
}
- /* Mark NHLFE, queue LSP for processing. */
- SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
-
- return nhlfe;
-}
-
-/*
- * Install/update a NHLFE for an LSP in the forwarding table. This may be
- * a new LSP entry or a new NHLFE for an existing in-label or an update of
- * the out-label for an existing NHLFE (update case).
- */
-static zebra_nhlfe_t *
-lsp_add_backup_nhlfe(zebra_lsp_t *lsp, enum lsp_types_t type,
- uint8_t num_out_labels, const mpls_label_t *out_labels,
- enum nexthop_types_t gtype, const union g_addr *gate,
- ifindex_t ifindex)
-{
- zebra_nhlfe_t *nhlfe;
- char buf[MPLS_LABEL_STRLEN];
-
- nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype, gate, ifindex);
if (nhlfe) {
struct nexthop *nh = nhlfe->nexthop;
@@ -3234,8 +3240,9 @@ lsp_add_backup_nhlfe(zebra_lsp_t *lsp, enum lsp_types_t type,
nh->nh_label->label, buf3, sizeof(buf3),
0);
- zlog_debug("LSP in-label %u type %d backup nexthop %s out-label(s) changed to %s (old %s)",
- lsp->ile.in_label, type, buf, buf2, buf3);
+ zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
+ lsp->ile.in_label, type, backup_str, buf,
+ buf2, buf3);
}
/* Update out label(s), trigger processing. */
@@ -3249,8 +3256,8 @@ lsp_add_backup_nhlfe(zebra_lsp_t *lsp, enum lsp_types_t type,
}
} else {
/* Add LSP entry to this nexthop */
- nhlfe = nhlfe_backup_add(lsp, type, gtype, gate, ifindex,
- num_out_labels, out_labels);
+ nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex,
+ num_out_labels, out_labels, is_backup);
if (!nhlfe)
return NULL;
@@ -3261,8 +3268,9 @@ lsp_add_backup_nhlfe(zebra_lsp_t *lsp, enum lsp_types_t type,
mpls_label2str(num_out_labels, out_labels, buf2,
sizeof(buf2), 0);
- zlog_debug("Add LSP in-label %u type %d backup nexthop %s out-label(s) %s",
- lsp->ile.in_label, type, buf, buf2);
+ zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
+ lsp->ile.in_label, type, backup_str, buf,
+ buf2);
}
lsp->addr_family = NHLFE_FAMILY(nhlfe);
@@ -3300,7 +3308,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
return -1;
nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype,
- gate, ifindex);
+ gate, ifindex, false /*backup*/);
if (nhlfe == NULL)
return -1;
@@ -3320,7 +3328,8 @@ static int lsp_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type,
zebra_nhlfe_t *nhlfe;
nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels,
- znh->type, &znh->gate, znh->ifindex);
+ znh->type, &znh->gate, znh->ifindex,
+ false /*backup*/);
if (nhlfe == NULL)
return -1;
@@ -3345,9 +3354,9 @@ static int lsp_backup_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type,
{
zebra_nhlfe_t *nhlfe;
- nhlfe = lsp_add_backup_nhlfe(lsp, type, znh->label_num,
- znh->labels, znh->type, &znh->gate,
- znh->ifindex);
+ nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num,
+ znh->labels, znh->type, &znh->gate,
+ znh->ifindex, true /*backup*/);
if (nhlfe == NULL) {
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug("%s: unable to add backup nhlfe, label: %u",
@@ -3368,13 +3377,14 @@ static int lsp_backup_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type,
*/
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- const union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex,
+ bool backup_p)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
zebra_lsp_t *lsp;
zebra_nhlfe_t *nhlfe;
- char buf[BUFSIZ];
+ char buf[NEXTHOP_STRLEN];
bool schedule_lsp = false;
/* Lookup table. */
@@ -3387,7 +3397,13 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
lsp = hash_lookup(lsp_table, &tmp_ile);
if (!lsp)
return 0;
- nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate, ifindex);
+
+ if (backup_p)
+ nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
+ gate, ifindex);
+ else
+ nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
+ ifindex);
if (!nhlfe)
return 0;
@@ -3420,56 +3436,6 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
return 0;
}
-/*
- * Uninstall a particular NHLFE in the forwarding table. If this is
- * the only NHLFE, the entire LSP forwarding entry has to be deleted.
- */
-static int lsp_backup_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
- mpls_label_t in_label,
- enum nexthop_types_t gtype,
- const union g_addr *gate, ifindex_t ifindex)
-{
- struct hash *lsp_table;
- zebra_ile_t tmp_ile;
- zebra_lsp_t *lsp;
- zebra_nhlfe_t *nhlfe;
- char buf[BUFSIZ];
-
- /* Lookup table. */
- lsp_table = zvrf->lsp_table;
- if (!lsp_table)
- return -1;
-
- /* If entry is not present, exit. */
- tmp_ile.in_label = in_label;
- lsp = hash_lookup(lsp_table, &tmp_ile);
- if (!lsp)
- return 0;
- nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype, gate, ifindex);
- if (!nhlfe)
- return 0;
-
- if (IS_ZEBRA_DEBUG_MPLS) {
- nhlfe2str(nhlfe, buf, BUFSIZ);
- zlog_debug("Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
- in_label, type, buf, nhlfe->flags);
- }
-
- /* Mark NHLFE for delete or directly delete, as appropriate. */
- if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
- UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
- SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
- if (lsp_processq_add(lsp))
- return -1;
- } else {
- nhlfe_del(nhlfe);
-
- /* Free LSP entry if no other NHLFEs and not scheduled. */
- lsp_check_free(lsp_table, &lsp);
- }
- return 0;
-}
-
int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label)
{
@@ -3754,7 +3720,7 @@ int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
/* Uninstall LSP from the main table. */
mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
- gate, ifindex);
+ gate, ifindex, false);
/* Delete static LSP NHLFE */
snhlfe_del(snhlfe);
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 9b5fb39573..07a8efeb8b 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -213,7 +213,7 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
enum lsp_types_t lsp_type,
enum nexthop_types_t gtype,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
const mpls_label_t *out_labels);
@@ -222,7 +222,7 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
zebra_nhlfe_t *zebra_mpls_lsp_add_backup_nhlfe(zebra_lsp_t *lsp,
enum lsp_types_t lsp_type,
enum nexthop_types_t gtype,
- union g_addr *gate,
+ const union g_addr *gate,
ifindex_t ifindex,
uint8_t num_labels,
const mpls_label_t *out_labels);
@@ -331,7 +331,8 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
*/
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- const union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex,
+ bool backup_p);
/*
* Uninstall all NHLFEs for a particular LSP forwarding entry.
@@ -339,12 +340,6 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label);
-/*
- * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry.
- * If no other NHLFEs exist, the entry would be deleted.
- */
-void mpls_sr_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt);
-
#if defined(HAVE_CUMULUS)
/*
* Check that the label values used in LSP creation are consistent. The
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 02ba69bd4d..f5e4a4e79e 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -1734,6 +1734,10 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
return false;
+ /* Must be ACTIVE */
+ if (!CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_ACTIVE))
+ return false;
+
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -1926,11 +1930,23 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
return 1;
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
+ struct nexthop_group *nhg;
+
resolved = 0;
- for (ALL_NEXTHOPS(match->nhe->nhg, newhop)) {
- if (!CHECK_FLAG(match->status,
- ROUTE_ENTRY_INSTALLED))
- continue;
+
+ /* Only useful if installed */
+ if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: match %p (%u) not installed",
+ __func__, match,
+ match->nhe->id);
+
+ goto done_with_match;
+ }
+
+ /* Examine installed nexthops */
+ nhg = &match->nhe->nhg;
+ for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
@@ -1945,25 +1961,21 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
resolved = 1;
}
- if (resolved)
- re->nexthop_mtu = match->mtu;
- else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " %s: Recursion failed to find",
- __func__);
+ /* Examine installed backup nexthops, if any. There
+ * are only installed backups *if* there is a
+ * dedicated fib list.
+ */
+ nhg = rib_get_fib_backup_nhg(match);
+ if (nhg == NULL ||
+ nhg == zebra_nhg_get_backup_nhg(match->nhe))
+ goto done_with_match;
- return resolved;
- } else if (re->type == ZEBRA_ROUTE_STATIC) {
- resolved = 0;
- for (ALL_NEXTHOPS(match->nhe->nhg, newhop)) {
- if (!CHECK_FLAG(match->status,
- ROUTE_ENTRY_INSTALLED))
- continue;
+ for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%s: STATIC match %p (%u), newhop %pNHv",
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: RECURSIVE match backup %p (%u), newhop %pNHv",
__func__, match,
match->nhe->id, newhop);
@@ -1972,13 +1984,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
nexthop_set_resolved(afi, newhop, nexthop);
resolved = 1;
}
+done_with_match:
if (resolved)
re->nexthop_mtu = match->mtu;
-
- if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
+ else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- " %s: Static route unable to resolve",
+ " %s: Recursion failed to find",
__func__);
+
return resolved;
} else {
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
@@ -2170,17 +2183,20 @@ done:
}
/*
- * Process a list of nexthops, given the head of the list, determining
+ * Process a list of nexthops, given an nhg, determining
* whether each one is ACTIVE/installable at this time.
*/
static uint32_t nexthop_list_active_update(struct route_node *rn,
struct route_entry *re,
- struct nexthop *nexthop)
+ struct nexthop_group *nhg)
{
union g_addr prev_src;
unsigned int prev_active, new_active;
ifindex_t prev_index;
uint32_t counter = 0;
+ struct nexthop *nexthop;
+
+ nexthop = nhg->nexthop;
/* Process nexthops one-by-one */
for ( ; nexthop; nexthop = nexthop->next) {
@@ -2263,7 +2279,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
curr_nhe->id = 0;
/* Process nexthops */
- curr_active = nexthop_list_active_update(rn, re, curr_nhe->nhg.nexthop);
+ curr_active = nexthop_list_active_update(rn, re, &curr_nhe->nhg);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p curr_active %u", __func__, re,
@@ -2274,7 +2290,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
goto backups_done;
backup_active = nexthop_list_active_update(
- rn, re, zebra_nhg_get_backup_nhg(curr_nhe)->nexthop);
+ rn, re, zebra_nhg_get_backup_nhg(curr_nhe));
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p backup_active %u", __func__, re,
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index 8f0c964c18..2328ab650a 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -550,7 +550,7 @@ static void vty_show_mpls_pseudowire_detail(struct vty *vty)
re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
&pw->nexthop, NULL);
if (re) {
- for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+ for (ALL_NEXTHOPS_PTR(rib_get_fib_nhg(re), nexthop)) {
snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
nexthop);
vty_out(vty, " Next Hop: %s\n", buf_nh);
@@ -604,7 +604,7 @@ static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
&pw->nexthop, NULL);
if (re) {
- for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+ for (ALL_NEXTHOPS_PTR(rib_get_fib_nhg(re), nexthop)) {
json_nexthop = json_object_new_object();
snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
json_object_string_add(json_nexthop, "nexthop", buf_nh);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 31582dcb3d..67b3812ed3 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1342,6 +1342,92 @@ static bool rib_compare_routes(const struct route_entry *re1,
}
/*
+ * Compare nexthop lists from a route and a dplane context; test whether
+ * the list installed in the FIB matches the route's list.
+ * Set 'changed_p' to 'true' if there were changes to the route's
+ * installed nexthops.
+ *
+ * Return 'false' if any ACTIVE route nexthops are not mentioned in the FIB
+ * list.
+ */
+static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg,
+ const struct nexthop_group *ctx_nhg,
+ bool *changed_p)
+{
+ bool matched_p = true;
+ struct nexthop *nexthop, *ctx_nexthop;
+
+ /* Get the first `installed` one to check against.
+ * If the dataplane doesn't set these to be what was actually installed,
+ * it will just be whatever was in re->nhe->nhg?
+ */
+ ctx_nexthop = ctx_nhg->nexthop;
+
+ if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
+ || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
+
+ for (ALL_NEXTHOPS_PTR(re_nhg, nexthop)) {
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ continue;
+
+ /* Check for a FIB nexthop corresponding to the RIB nexthop */
+ if (nexthop_same(ctx_nexthop, nexthop) == false) {
+ /* If the FIB doesn't know about the nexthop,
+ * it's not installed
+ */
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED ||
+ IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ zlog_debug("%s: no ctx match for rib nh %pNHv %s",
+ __func__, nexthop,
+ (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_FIB) ?
+ "(FIB)":""));
+ }
+ matched_p = false;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ *changed_p = true;
+
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ /* Keep checking nexthops */
+ continue;
+ }
+
+ if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_FIB)) {
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: rib nh %pNHv -> installed",
+ __func__, nexthop);
+
+ *changed_p = true;
+ }
+
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ } else {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: rib nh %pNHv -> uninstalled",
+ __func__, nexthop);
+
+ *changed_p = true;
+ }
+
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+
+ ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
+ }
+
+ return matched_p;
+}
+
+/*
* Update a route from a dplane context. This consolidates common code
* that can be used in processing of results from FIB updates, and in
* async notification processing.
@@ -1352,10 +1438,10 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
struct zebra_dplane_ctx *ctx)
{
char dest_str[PREFIX_STRLEN] = "";
- char nh_str[NEXTHOP_STRLEN];
- struct nexthop *nexthop, *ctx_nexthop;
+ struct nexthop *nexthop;
bool matched;
const struct nexthop_group *ctxnhg;
+ struct nexthop_group *re_nhg;
bool is_selected = false; /* Is 're' currently the selected re? */
bool changed_p = false; /* Change to nexthops? */
rib_dest_t *dest;
@@ -1386,10 +1472,13 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
matched = false;
ctxnhg = dplane_ctx_get_ng(ctx);
- /* Check both fib group and notif group for equivalence.
+ /* Check route's fib group and incoming notif group for equivalence.
*
* Let's assume the nexthops are ordered here to save time.
*/
+ /* TODO -- this isn't testing or comparing the FIB flags; we should
+ * do a more explicit loop, checking the incoming notification's flags.
+ */
if (re->fib_ng.nexthop && ctxnhg->nexthop &&
nexthop_group_equal(&re->fib_ng, ctxnhg))
matched = true;
@@ -1400,7 +1489,7 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
zlog_debug(
"%s(%u):%s update_from_ctx(): existing fib nhg, no change",
VRF_LOGNAME(vrf), re->vrf_id, dest_str);
- goto done;
+ goto check_backups;
} else if (re->fib_ng.nexthop) {
/*
@@ -1430,70 +1519,16 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
*
* Assume nexthops are ordered here as well.
*/
- matched = true;
- ctx_nexthop = ctxnhg->nexthop;
-
- /* Nothing installed - we can skip some of the checking/comparison
+ /* If nothing is installed, we can skip some of the checking/comparison
* of nexthops.
*/
- if (ctx_nexthop == NULL) {
+ if (ctxnhg->nexthop == NULL) {
changed_p = true;
goto no_nexthops;
}
- /* Get the first `installed` one to check against.
- * If the dataplane doesn't set these to be what was actually installed,
- * it will just be whatever was in re->nhe->nhg?
- */
- if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
- || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
-
- for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
-
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- continue;
-
- /* Check for a FIB nexthop corresponding to the RIB nexthop */
- if (nexthop_same(ctx_nexthop, nexthop) == false) {
- /* If the FIB doesn't know about the nexthop,
- * it's not installed
- */
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- nexthop2str(nexthop, nh_str, sizeof(nh_str));
- zlog_debug(
- "update_from_ctx: no match for rib nh %s",
- nh_str);
- }
- matched = false;
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- changed_p = true;
-
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
-
- /* Keep checking nexthops */
- continue;
- }
-
- if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_FIB)) {
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- changed_p = true;
-
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- } else {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- changed_p = true;
-
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
-
- ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
- }
+ matched = rib_update_nhg_from_ctx(&(re->nhe->nhg), ctxnhg, &changed_p);
/* If all nexthops were processed, we're done */
if (matched) {
@@ -1502,7 +1537,7 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
"%s(%u):%s update_from_ctx(): rib nhg matched, changed '%s'",
VRF_LOGNAME(vrf), re->vrf_id, dest_str,
(changed_p ? "true" : "false"));
- goto done;
+ goto check_backups;
}
no_nexthops:
@@ -1527,7 +1562,81 @@ no_nexthops:
_nexthop_add(&(re->fib_ng.nexthop), nexthop);
}
+check_backups:
+
+ /*
+ * Check the status of the route's backup nexthops, if any.
+ * The logic for backups is somewhat different: if any backup is
+ * installed, a new fib nhg will be attached to the route.
+ */
+ re_nhg = zebra_nhg_get_backup_nhg(re->nhe);
+ if (re_nhg == NULL)
+ goto done; /* No backup nexthops */
+
+ /* First check the route's 'fib' list of backups, if it's present
+ * from some previous event.
+ */
+ re_nhg = &re->fib_backup_ng;
+ ctxnhg = dplane_ctx_get_backup_ng(ctx);
+
+ matched = false;
+ if (re_nhg->nexthop && ctxnhg && nexthop_group_equal(re_nhg, ctxnhg))
+ matched = true;
+
+ /* If the new FIB set matches an existing FIB set, we're done. */
+ if (matched) {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug(
+ "%s(%u):%s update_from_ctx(): existing fib backup nhg, no change",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
+ goto done;
+
+ } else if (re->fib_backup_ng.nexthop) {
+ /*
+ * Free stale fib backup list and move on to check
+ * the route's backups.
+ */
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug(
+ "%s(%u):%s update_from_ctx(): replacing fib backup nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
+ nexthops_free(re->fib_backup_ng.nexthop);
+ re->fib_backup_ng.nexthop = NULL;
+
+ /* Note that the installed nexthops have changed */
+ changed_p = true;
+ } else {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s(%u):%s update_from_ctx(): no fib backup nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
+ }
+
+ /*
+ * If a FIB backup nexthop set exists: attach a copy
+ * to the route if any backup is installed
+ */
+ if (ctxnhg && ctxnhg->nexthop) {
+
+ for (ALL_NEXTHOPS_PTR(ctxnhg, nexthop)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ break;
+ }
+
+ /* If no installed backups, we're done */
+ if (nexthop == NULL)
+ goto done;
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s(%u):%s update_from_ctx(): changed %s, adding new backup fib nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str,
+ (changed_p ? "true" : "false"));
+
+ copy_nexthops(&(re->fib_backup_ng.nexthop), ctxnhg->nexthop,
+ NULL);
+ }
+
done:
+
return changed_p;
}
@@ -1814,6 +1923,38 @@ done:
}
/*
+ * Count installed/FIB nexthops
+ */
+static int rib_count_installed_nh(struct route_entry *re)
+{
+ int count = 0;
+ struct nexthop *nexthop;
+ struct nexthop_group *nhg;
+
+ nhg = rib_get_fib_nhg(re);
+
+ for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+ /* The meaningful flag depends on where the installed
+ * nexthops reside.
+ */
+ if (nhg == &(re->fib_backup_ng)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ count++;
+ } else {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ count++;
+ }
+ }
+
+ for (ALL_NEXTHOPS_PTR(rib_get_fib_backup_nhg(re), nexthop)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ count++;
+ }
+
+ return count;
+}
+
+/*
* Handle notification from async dataplane: the dataplane has detected
* some change to a route, and notifies zebra so that the control plane
* can reflect that change.
@@ -1930,12 +2071,8 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
*/
start_count = 0;
- if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
- for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- start_count++;
- }
- }
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+ start_count = rib_count_installed_nh(re);
/* Update zebra's nexthop FIB flags based on the context struct's
* nexthops.
@@ -1954,12 +2091,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
* Perform follow-up work if the actual status of the prefix
* changed.
*/
-
- end_count = 0;
- for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- end_count++;
- }
+ end_count = rib_count_installed_nh(re);
/* Various fib transitions: changed nexthops; from installed to
* not-installed; or not-installed to installed.
@@ -1988,7 +2120,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
/* Changed nexthops - update kernel/others */
- dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_INSTALL, ctx);
+ dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_UPDATE, ctx);
/* Redistribute, lsp, and nht update */
redistribute_update(dest_pfx, src_pfx, re, NULL);
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 20af96a557..d1a5cf2a9d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -419,7 +419,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
at_least_one++; /* at least one valid NH */
else {
SET_FLAG(nexthop->flags,
- NEXTHOP_FLAG_RNH_FILTERED);
+ NEXTHOP_FLAG_RNH_FILTERED);
}
}
}
@@ -458,12 +458,12 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
char buf[PREFIX_STRLEN];
- char buf1[PREFIX_STRLEN];
+ char buf1[SRCDEST2STR_BUFFER];
zlog_debug("%s: %u:%s Resolved Import Entry to %s", __func__,
rnh->vrf_id,
prefix2str(&rnh->node->p, buf, sizeof(buf)),
- srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ srcdest_rnode2str(rn, buf1, sizeof(buf1)));
}
/* Identify appropriate route entry. */
@@ -974,12 +974,131 @@ static void copy_state(struct rnh *rnh, const struct route_entry *re,
state->vrf_id = re->vrf_id;
state->status = re->status;
- state->nhe = zebra_nhg_alloc();
+ state->nhe = zebra_nhe_copy(re->nhe, 0);
+
+ /* Copy the 'fib' nexthops also, if present - we want to capture
+ * the true installed nexthops.
+ */
+ if (re->fib_ng.nexthop)
+ nexthop_group_copy(&state->fib_ng, &re->fib_ng);
+ if (re->fib_backup_ng.nexthop)
+ nexthop_group_copy(&state->fib_backup_ng, &re->fib_backup_ng);
- nexthop_group_copy(&(state->nhe->nhg), &(re->nhe->nhg));
rnh->state = state;
}
+/*
+ * Compare two route_entries' nexthops.
+ */
+static bool compare_valid_nexthops(struct route_entry *r1,
+ struct route_entry *r2)
+{
+ bool matched_p = false;
+ struct nexthop_group *nhg1, *nhg2;
+ struct nexthop *nh1, *nh2;
+
+ /* Account for backup nexthops and for the 'fib' nexthop lists,
+ * if present.
+ */
+ nhg1 = rib_get_fib_nhg(r1);
+ nhg2 = rib_get_fib_nhg(r2);
+
+ nh1 = nhg1->nexthop;
+ nh2 = nhg2->nexthop;
+
+ while (1) {
+ /* Find each list's next valid nexthop */
+ while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
+ nh1 = nexthop_next(nh1);
+
+ while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
+ nh2 = nexthop_next(nh2);
+
+ if (nh1 && nh2) {
+ /* Any difference is a no-match */
+ if (nexthop_cmp(nh1, nh2) != 0) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("%s: nh1, nh2 differ",
+ __func__);
+ goto done;
+ }
+
+ nh1 = nexthop_next(nh1);
+ nh2 = nexthop_next(nh2);
+ } else if (nh1 || nh2) {
+ /* One list has more valid nexthops than the other */
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("%s: nh1 %s, nh2 %s", __func__,
+ nh1 ? "non-NULL" : "NULL",
+ nh2 ? "non-NULL" : "NULL");
+ goto done;
+ } else
+ break; /* Done with both lists */
+ }
+
+ /* The test for the backups is slightly different: the only installed
+ * backups will be in the 'fib' list.
+ */
+ nhg1 = rib_get_fib_backup_nhg(r1);
+ if (nhg1 == zebra_nhg_get_backup_nhg(r1->nhe))
+ nhg1 = NULL;
+
+ nhg2 = rib_get_fib_backup_nhg(r2);
+ if (nhg2 == zebra_nhg_get_backup_nhg(r2->nhe))
+ nhg2 = NULL;
+
+ if (nhg1)
+ nh1 = nhg1->nexthop;
+ else
+ nh1 = NULL;
+
+ if (nhg2)
+ nh2 = nhg2->nexthop;
+ else
+ nh2 = NULL;
+
+ while (1) {
+ /* Find each backup list's next valid nexthop */
+ while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
+ nh1 = nexthop_next(nh1);
+
+ while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
+ nh2 = nexthop_next(nh2);
+
+ if (nh1 && nh2) {
+ /* Any difference is a no-match */
+ if (nexthop_cmp(nh1, nh2) != 0) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("%s: backup nh1, nh2 differ",
+ __func__);
+ goto done;
+ }
+
+ nh1 = nexthop_next(nh1);
+ nh2 = nexthop_next(nh2);
+ } else if (nh1 || nh2) {
+ /* One list has more valid nexthops than the other */
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("%s: backup nh1 %s, nh2 %s",
+ __func__,
+ nh1 ? "non-NULL" : "NULL",
+ nh2 ? "non-NULL" : "NULL");
+ goto done;
+ } else
+ break; /* Done with both lists */
+ }
+
+ /* Well, it's a match */
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("%s: matched", __func__);
+
+ matched_p = true;
+
+done:
+
+ return matched_p;
+}
+
static int compare_state(struct route_entry *r1, struct route_entry *r2)
{
if (!r1 && !r2)
@@ -994,12 +1113,7 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
if (r1->metric != r2->metric)
return 1;
- if (nexthop_group_nexthop_num(&(r1->nhe->nhg))
- != nexthop_group_nexthop_num(&(r2->nhe->nhg)))
- return 1;
-
- if (nexthop_group_hash(&(r1->nhe->nhg)) !=
- nexthop_group_hash(&(r2->nhe->nhg)))
+ if (!compare_valid_nexthops(r1, r2))
return 1;
return 0;
@@ -1044,6 +1158,7 @@ static int send_client(struct rnh *rnh, struct zserv *client,
}
if (re) {
struct zapi_nexthop znh;
+ struct nexthop_group *nhg;
stream_putc(s, re->type);
stream_putw(s, re->instance);
@@ -1052,7 +1167,9 @@ static int send_client(struct rnh *rnh, struct zserv *client,
num = 0;
nump = stream_get_endp(s);
stream_putc(s, 0);
- for (ALL_NEXTHOPS(re->nhe->nhg, nh))
+
+ nhg = rib_get_fib_nhg(re);
+ for (ALL_NEXTHOPS_PTR(nhg, nh))
if (rnh_nexthop_valid(re, nh)) {
zapi_nexthop_from_nexthop(&znh, nh);
ret = zapi_nexthop_encode(s, &znh, 0/*flags*/);
@@ -1061,6 +1178,21 @@ static int send_client(struct rnh *rnh, struct zserv *client,
num++;
}
+
+ nhg = rib_get_fib_backup_nhg(re);
+ if (nhg == zebra_nhg_get_backup_nhg(re->nhe))
+ nhg = NULL;
+
+ if (nhg) {
+ for (ALL_NEXTHOPS_PTR(nhg, nh))
+ if (rnh_nexthop_valid(re, nh)) {
+ zapi_nexthop_from_nexthop(&znh, nh);
+ zapi_nexthop_encode(s, &znh,
+ 0 /* flags */);
+ num++;
+ }
+ }
+
stream_putc_at(s, nump, num);
} else {
stream_putc(s, 0); // type
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 9718b40d9d..1da2660509 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -516,8 +516,189 @@ static void show_route_nexthop_helper(struct vty *vty,
sizeof(buf), 1));
}
- if ((re == NULL) && nexthop->weight)
+ if (nexthop->weight)
vty_out(vty, ", weight %u", nexthop->weight);
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ vty_out(vty, ", backup %d", nexthop->backup_idx);
+}
+
+/*
+ * Render a nexthop into a json object; the caller allocates and owns
+ * the json object memory.
+ */
+static void show_nexthop_json_helper(json_object *json_nexthop,
+ const struct nexthop *nexthop,
+ const struct route_entry *re)
+{
+ char buf[SRCDEST2STR_BUFFER];
+ struct vrf *vrf = NULL;
+ json_object *json_labels = NULL;
+
+ json_object_int_add(json_nexthop, "flags",
+ nexthop->flags);
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ json_object_boolean_true_add(json_nexthop,
+ "duplicate");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ json_object_boolean_true_add(json_nexthop,
+ "fib");
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ json_object_string_add(
+ json_nexthop, "ip",
+ inet_ntoa(nexthop->gate.ipv4));
+ json_object_string_add(json_nexthop, "afi",
+ "ipv4");
+
+ if (nexthop->ifindex) {
+ json_object_int_add(json_nexthop,
+ "interfaceIndex",
+ nexthop->ifindex);
+ json_object_string_add(
+ json_nexthop, "interfaceName",
+ ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ json_object_string_add(
+ json_nexthop, "ip",
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6,
+ buf, sizeof(buf)));
+ json_object_string_add(json_nexthop, "afi",
+ "ipv6");
+
+ if (nexthop->ifindex) {
+ json_object_int_add(json_nexthop,
+ "interfaceIndex",
+ nexthop->ifindex);
+ json_object_string_add(
+ json_nexthop, "interfaceName",
+ ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+ }
+ break;
+
+ case NEXTHOP_TYPE_IFINDEX:
+ json_object_boolean_true_add(
+ json_nexthop, "directlyConnected");
+ json_object_int_add(json_nexthop,
+ "interfaceIndex",
+ nexthop->ifindex);
+ json_object_string_add(
+ json_nexthop, "interfaceName",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ json_object_boolean_true_add(json_nexthop,
+ "unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ json_object_boolean_true_add(
+ json_nexthop, "reject");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ json_object_boolean_true_add(
+ json_nexthop,
+ "admin-prohibited");
+ break;
+ case BLACKHOLE_NULL:
+ json_object_boolean_true_add(
+ json_nexthop, "blackhole");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((nexthop->vrf_id != re->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
+ vrf = vrf_lookup_by_id(nexthop->vrf_id);
+ json_object_string_add(json_nexthop, "vrf",
+ vrf->name);
+ }
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ json_object_boolean_true_add(json_nexthop,
+ "duplicate");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ json_object_boolean_true_add(json_nexthop,
+ "active");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ json_object_boolean_true_add(json_nexthop,
+ "onLink");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ json_object_boolean_true_add(json_nexthop,
+ "recursive");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ json_object_int_add(json_nexthop, "backupIndex",
+ nexthop->backup_idx);
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nexthop->src.ipv4.s_addr) {
+ if (inet_ntop(AF_INET,
+ &nexthop->src.ipv4, buf,
+ sizeof(buf)))
+ json_object_string_add(
+ json_nexthop, "source",
+ buf);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
+ &in6addr_any)) {
+ if (inet_ntop(AF_INET6,
+ &nexthop->src.ipv6, buf,
+ sizeof(buf)))
+ json_object_string_add(
+ json_nexthop, "source",
+ buf);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nexthop->nh_label
+ && nexthop->nh_label->num_labels) {
+ json_labels = json_object_new_array();
+
+ for (int label_index = 0;
+ label_index
+ < nexthop->nh_label->num_labels;
+ label_index++)
+ json_object_array_add(
+ json_labels,
+ json_object_new_int(
+ nexthop->nh_label->label
+ [label_index]));
+
+ json_object_object_add(json_nexthop, "labels",
+ json_labels);
+ }
+
+ if (nexthop->weight)
+ json_object_int_add(json_nexthop, "weight",
+ nexthop->weight);
+
}
static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
@@ -530,12 +711,12 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
json_object *json_nexthops = NULL;
json_object *json_nexthop = NULL;
json_object *json_route = NULL;
- json_object *json_labels = NULL;
time_t uptime;
struct vrf *vrf = NULL;
rib_dest_t *dest = rib_dest_from_rnode(rn);
struct nexthop_group *nhg;
char up_str[MONOTIME_STRLEN];
+ bool first_p;
uptime = monotime(NULL);
uptime -= re->uptime;
@@ -546,7 +727,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
* nexthops.
*/
if (is_fib)
- nhg = rib_active_nhg(re);
+ nhg = rib_get_fib_nhg(re);
else
nhg = &(re->nhe->nhg);
@@ -611,177 +792,44 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
json_nexthop = json_object_new_object();
- json_object_int_add(json_nexthop, "flags",
- nexthop->flags);
+ show_nexthop_json_helper(json_nexthop, nexthop, re);
+ json_object_array_add(json_nexthops, json_nexthop);
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
- json_object_boolean_true_add(json_nexthop,
- "duplicate");
+ json_object_object_add(json_route, "nexthops", json_nexthops);
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- json_object_boolean_true_add(json_nexthop,
- "fib");
+ /* If there are backup nexthops, include them */
+ if (is_fib)
+ nhg = rib_get_fib_backup_nhg(re);
+ else
+ nhg = zebra_nhg_get_backup_nhg(re->nhe);
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- json_object_string_add(
- json_nexthop, "ip",
- inet_ntoa(nexthop->gate.ipv4));
- json_object_string_add(json_nexthop, "afi",
- "ipv4");
-
- if (nexthop->ifindex) {
- json_object_int_add(json_nexthop,
- "interfaceIndex",
- nexthop->ifindex);
- json_object_string_add(
- json_nexthop, "interfaceName",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- json_object_string_add(
- json_nexthop, "ip",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6,
- buf, sizeof(buf)));
- json_object_string_add(json_nexthop, "afi",
- "ipv6");
-
- if (nexthop->ifindex) {
- json_object_int_add(json_nexthop,
- "interfaceIndex",
- nexthop->ifindex);
- json_object_string_add(
- json_nexthop, "interfaceName",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- }
- break;
-
- case NEXTHOP_TYPE_IFINDEX:
- json_object_boolean_true_add(
- json_nexthop, "directlyConnected");
- json_object_int_add(json_nexthop,
- "interfaceIndex",
- nexthop->ifindex);
- json_object_string_add(
- json_nexthop, "interfaceName",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- json_object_boolean_true_add(json_nexthop,
- "unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- json_object_boolean_true_add(
- json_nexthop, "reject");
- break;
- case BLACKHOLE_ADMINPROHIB:
- json_object_boolean_true_add(
- json_nexthop,
- "admin-prohibited");
- break;
- case BLACKHOLE_NULL:
- json_object_boolean_true_add(
- json_nexthop, "blackhole");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
- }
+ if (nhg) {
+ json_nexthops = json_object_new_array();
- if ((nexthop->vrf_id != re->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
- vrf = vrf_lookup_by_id(nexthop->vrf_id);
- json_object_string_add(json_nexthop, "vrf",
- vrf->name);
- }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
- json_object_boolean_true_add(json_nexthop,
- "duplicate");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- json_object_boolean_true_add(json_nexthop,
- "active");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- json_object_boolean_true_add(json_nexthop,
- "onLink");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- json_object_boolean_true_add(json_nexthop,
- "recursive");
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET,
- &nexthop->src.ipv4, buf,
- sizeof(buf)))
- json_object_string_add(
- json_nexthop, "source",
- buf);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
- &in6addr_any)) {
- if (inet_ntop(AF_INET6,
- &nexthop->src.ipv6, buf,
- sizeof(buf)))
- json_object_string_add(
- json_nexthop, "source",
- buf);
- }
- break;
- default:
- break;
- }
+ for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+ json_nexthop = json_object_new_object();
- if (nexthop->nh_label
- && nexthop->nh_label->num_labels) {
- json_labels = json_object_new_array();
-
- for (int label_index = 0;
- label_index
- < nexthop->nh_label->num_labels;
- label_index++)
- json_object_array_add(
- json_labels,
- json_object_new_int(
- nexthop->nh_label->label
- [label_index]));
-
- json_object_object_add(json_nexthop, "labels",
- json_labels);
+ show_nexthop_json_helper(json_nexthop,
+ nexthop, re);
+ json_object_array_add(json_nexthops,
+ json_nexthop);
}
- if (nexthop->weight)
- json_object_int_add(json_nexthop, "weight",
- nexthop->weight);
-
- json_object_array_add(json_nexthops, json_nexthop);
+ json_object_object_add(json_route, "backupNexthops",
+ json_nexthops);
}
- json_object_object_add(json_route, "nexthops", json_nexthops);
json_object_array_add(json, json_route);
return;
}
/* Nexthop information. */
+ first_p = true;
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
- if (nexthop == nhg->nexthop) {
+ if (first_p) {
+ first_p = false;
+
/* Prefix information. */
len = vty_out(vty, "%c", zebra_route_char(re->type));
if (re->instance)
@@ -808,40 +856,36 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
show_route_nexthop_helper(vty, re, nexthop);
- if (nexthop->weight)
- vty_out(vty, ", weight %u", nexthop->weight);
-
vty_out(vty, ", %s\n", up_str);
+ }
- /* Check for backup info */
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
- struct nexthop *backup;
- int i;
+ /* Check for backup info if present */
+ if (is_fib)
+ nhg = rib_get_fib_backup_nhg(re);
+ else
+ nhg = zebra_nhg_get_backup_nhg(re->nhe);
- if (re->nhe->backup_info == NULL ||
- re->nhe->backup_info->nhe == NULL)
- continue;
+ if (nhg == NULL)
+ return;
- i = 0;
- for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg,
- backup)) {
- if (i == nexthop->backup_idx)
- break;
- i++;
- }
+ /* Print backup info */
+ for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+ bool star_p = false;
- /* Print useful backup info */
- if (backup) {
- /* TODO -- install state is not accurate */
- vty_out(vty, " %*c [backup %d]",
- /*re_status_output_char(re, backup),*/
- len - 3 + (2 * nexthop_level(nexthop)),
- ' ', nexthop->backup_idx);
- show_route_nexthop_helper(vty, re, backup);
- vty_out(vty, "\n");
- }
- }
+ if (is_fib)
+ star_p = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ /* TODO -- it'd be nice to be able to include
+ * the entire list of backups, *and* include the
+ * real installation state.
+ */
+ vty_out(vty, " b%c %*c",
+ (star_p ? '*' : ' '),
+ len - 3 + (2 * nexthop_level(nexthop)), ' ');
+ show_route_nexthop_helper(vty, re, nexthop);
+ vty_out(vty, "\n");
}
+
}
static void vty_show_ip_route_detail_json(struct vty *vty,