From cd4bb96f9df57c499d25414ebb0ef5890031624f Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 10 Apr 2020 14:47:00 -0400 Subject: [PATCH] zebra: support backup nhlfes in LSPs Handle backup nhlfes in LSP zapi messages. Capture backup info with LSPs, capture backup info in the dataplane LSP processing. Signed-off-by: Mark Stapp --- zebra/zapi_msg.c | 58 ++++-- zebra/zebra_dplane.c | 82 +++++++-- zebra/zebra_dplane.h | 11 ++ zebra/zebra_mpls.c | 412 ++++++++++++++++++++++++++++++++++++------- zebra/zebra_mpls.h | 46 ++++- 5 files changed, 519 insertions(+), 90 deletions(-) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 5db455528..9f099d281 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1998,6 +1998,9 @@ static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS) { struct stream *s; struct zapi_labels zl; + int ret, i; + struct zapi_nexthop *znh; + char buf[NEXTHOP_STRLEN]; /* Get input stream. */ s = msg; @@ -2011,20 +2014,55 @@ static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS) if (!mpls_enabled) return; - for (int i = 0; i < zl.nexthop_num; i++) { - struct zapi_nexthop *znh; + for (i = 0; i < zl.nexthop_num; i++) { znh = &zl.nexthops[i]; - mpls_lsp_install(zvrf, zl.type, zl.local_label, - znh->label_num, znh->labels, - znh->type, &znh->gate, znh->ifindex); + ret = mpls_lsp_znh_install(zvrf, zl.type, zl.local_label, znh); + if (ret < 0) { + if (IS_ZEBRA_DEBUG_RECV) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + zlog_debug("%s: Unable to install LSP: label %u, znh %s", + __func__, zl.local_label, buf); + } + continue; + } - if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) - mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, - znh->type, &znh->gate, znh->ifindex, - zl.route.type, zl.route.instance, - znh->labels[0]); + if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) { + ret = mpls_ftn_update(1 /*add*/, zvrf, zl.type, + &zl.route.prefix, znh->type, + &znh->gate, znh->ifindex, + zl.route.type, zl.route.instance, + znh->labels[0]); + if (ret < 0) { + if (IS_ZEBRA_DEBUG_RECV) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + zlog_debug("%s: Unable to update FEC: label %u, znh %s", + __func__, zl.local_label, + buf); + } + } + } + } + + /* Process backup LSPs/nexthop entries also. */ + if (CHECK_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS)) { + for (i = 0; i < zl.backup_nexthop_num; i++) { + + znh = &zl.backup_nexthops[i]; + + ret = mpls_lsp_backup_znh_install(zvrf, zl.type, + zl.local_label, znh); + if (ret < 0) { + if (IS_ZEBRA_DEBUG_RECV) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + zlog_debug("%s: Unable to install backup LSP: label %u, znh %s", + __func__, zl.local_label, + buf); + } + continue; + } + } } } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 5864471b6..63d55d061 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -513,15 +513,26 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) { zebra_nhlfe_t *nhlfe; - /* Free allocated NHLFEs */ - frr_each_safe(nhlfe_list, &ctx->u.lsp.nhlfe_list, nhlfe) - zebra_mpls_nhlfe_del(nhlfe); + /* Unlink and free allocated NHLFEs */ + frr_each_safe(nhlfe_list, &ctx->u.lsp.nhlfe_list, nhlfe) { + nhlfe_list_del(&ctx->u.lsp.nhlfe_list, nhlfe); + zebra_mpls_nhlfe_free(nhlfe); + } + + /* Unlink and free allocated backup NHLFEs, if present */ + frr_each_safe(nhlfe_list, + &(ctx->u.lsp.backup_nhlfe_list), nhlfe) { + nhlfe_list_del(&ctx->u.lsp.backup_nhlfe_list, + nhlfe); + zebra_mpls_nhlfe_free(nhlfe); + } - /* Clear pointers in lsp struct, in case we're cacheing + /* Clear pointers in lsp struct, in case we're caching * free context structs. */ nhlfe_list_init(&ctx->u.lsp.nhlfe_list); ctx->u.lsp.best_nhlfe = NULL; + nhlfe_list_init(&ctx->u.lsp.backup_nhlfe_list); break; } @@ -1222,6 +1233,13 @@ const struct nhlfe_list_head *dplane_ctx_get_nhlfe_list( return &(ctx->u.lsp.nhlfe_list); } +const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list( + const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return &(ctx->u.lsp.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, @@ -1241,6 +1259,26 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx, return nhlfe; } +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, + ifindex_t ifindex, + uint8_t num_labels, + mpls_label_t *out_labels) +{ + zebra_nhlfe_t *nhlfe; + + DPLANE_CTX_VALID(ctx); + + nhlfe = zebra_mpls_lsp_add_backup_nhlfe(&(ctx->u.lsp), + lsp_type, nh_type, gate, + ifindex, num_labels, + out_labels); + + return nhlfe; +} + const zebra_nhlfe_t * dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx) { @@ -1728,6 +1766,7 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp)); nhlfe_list_init(&(ctx->u.lsp.nhlfe_list)); + nhlfe_list_init(&(ctx->u.lsp.backup_nhlfe_list)); ctx->u.lsp.ile = lsp->ile; ctx->u.lsp.addr_family = lsp->addr_family; ctx->u.lsp.num_ecmp = lsp->num_ecmp; @@ -1739,16 +1778,8 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, if (nhlfe->nexthop == NULL) continue; - new_nhlfe = - zebra_mpls_lsp_add_nhlfe( - &(ctx->u.lsp), - nhlfe->type, - nhlfe->nexthop->type, - &(nhlfe->nexthop->gate), - nhlfe->nexthop->ifindex, - nhlfe->nexthop->nh_label->num_labels, - nhlfe->nexthop->nh_label->label); - + new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp), nhlfe->type, + nhlfe->nexthop); if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) { ret = ENOMEM; break; @@ -1762,9 +1793,32 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, ctx->u.lsp.best_nhlfe = new_nhlfe; } + if (ret != AOK) + goto done; + + /* Capture backup nhlfes/nexthops */ + frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) { + /* Not sure if this is meaningful... */ + if (nhlfe->nexthop == NULL) + continue; + + new_nhlfe = zebra_mpls_lsp_add_backup_nh(&(ctx->u.lsp), + nhlfe->type, + nhlfe->nexthop); + if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) { + ret = ENOMEM; + break; + } + + /* Need to copy flags too */ + new_nhlfe->flags = nhlfe->flags; + new_nhlfe->nexthop->flags = nhlfe->nexthop->flags; + } + /* On error the ctx will be cleaned-up, so we don't need to * deal with any allocated nhlfe or nexthop structs here. */ +done: return ret; } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index a9e305224..35ce33895 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -312,6 +312,9 @@ void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx, uint32_t flags); const struct nhlfe_list_head *dplane_ctx_get_nhlfe_list( const struct zebra_dplane_ctx *ctx); +const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list( + const struct zebra_dplane_ctx *ctx); + zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx, enum lsp_types_t lsp_type, enum nexthop_types_t nh_type, @@ -320,6 +323,14 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx, uint8_t num_labels, mpls_label_t *out_labels); +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, + ifindex_t ifindex, + uint8_t num_labels, + mpls_label_t *out_labels); + const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe( const struct zebra_dplane_ctx *ctx); const zebra_nhlfe_t *dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx, diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 65948a7be..16dde2208 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -106,8 +106,9 @@ 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, mpls_label_t *labels); -static int nhlfe_del(zebra_nhlfe_t *snhlfe); + uint8_t num_labels, const mpls_label_t *labels); +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, @@ -1082,6 +1083,7 @@ static void *lsp_alloc(void *p) lsp = XCALLOC(MTYPE_LSP, sizeof(zebra_lsp_t)); lsp->ile = *ile; nhlfe_list_init(&lsp->nhlfe_list); + nhlfe_list_init(&lsp->backup_nhlfe_list); if (IS_ZEBRA_DEBUG_MPLS) zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label); @@ -1111,6 +1113,10 @@ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp) frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) nhlfe_del(nhlfe); + /* Free backup nhlfes, if any. */ + frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) + nhlfe_del(nhlfe); + hash_release(lsp_table, &lsp->ile); XFREE(MTYPE_LSP, lsp); @@ -1206,22 +1212,14 @@ static zebra_nhlfe_t *nhlfe_find(struct nhlfe_list_head *list, return nhlfe; } -/* - * Enqueue nhlfe to lsp - at the head of the list - */ -static void nhlfe_enqueue(zebra_lsp_t *lsp, zebra_nhlfe_t *nhlfe) -{ - nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe); -} - /* * Allocate and init new NHLFE. */ -static zebra_nhlfe_t *nhlfe_ctor(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, - mpls_label_t *labels) +static zebra_nhlfe_t *nhlfe_alloc(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; struct nexthop *nexthop; @@ -1240,6 +1238,7 @@ static zebra_nhlfe_t *nhlfe_ctor(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, XFREE(MTYPE_NHLFE, nhlfe); return NULL; } + nexthop_add_labels(nexthop, lsp_type, num_labels, labels); nexthop->vrf_id = VRF_DEFAULT; @@ -1277,7 +1276,34 @@ static zebra_nhlfe_t *nhlfe_ctor(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, 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, mpls_label_t *labels) + 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); + + /* Enqueue to LSP, at head of list. */ + if (nhlfe) + 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; @@ -1285,18 +1311,38 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, return NULL; /* Allocate new object */ - nhlfe = nhlfe_ctor(lsp, lsp_type, gtype, gate, ifindex, num_labels, - labels); + nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels, + labels); + + SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP); - /* Enqueue to LSP */ + /* Enqueue to LSP, at tail of list. */ if (nhlfe) - nhlfe_enqueue(lsp, nhlfe); + nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe); return nhlfe; } /* - * Delete NHLFE. Entry must be present on list. + * Common delete for NHLFEs. + */ +static void nhlfe_free(zebra_nhlfe_t *nhlfe) +{ + if (!nhlfe) + return; + + /* Free nexthop. */ + if (nhlfe->nexthop) + nexthop_free(nhlfe->nexthop); + + nhlfe->nexthop = NULL; + + XFREE(MTYPE_NHLFE, nhlfe); +} + + +/* + * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list. */ static int nhlfe_del(zebra_nhlfe_t *nhlfe) { @@ -1309,17 +1355,18 @@ static int nhlfe_del(zebra_nhlfe_t *nhlfe) if (!lsp) return -1; - /* Free nexthop. */ - if (nhlfe->nexthop) - nexthop_free(nhlfe->nexthop); - if (nhlfe == lsp->best_nhlfe) lsp->best_nhlfe = NULL; /* Unlink from LSP */ - nhlfe_list_del(&lsp->nhlfe_list, nhlfe); + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP)) + nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe); + else + nhlfe_list_del(&lsp->nhlfe_list, nhlfe); - XFREE(MTYPE_NHLFE, nhlfe); + nhlfe->lsp = NULL; + + nhlfe_free(nhlfe); return 0; } @@ -2095,7 +2142,8 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn, } /* - * Add an NHLFE to an LSP, return the newly-added object + * Add an NHLFE to an LSP, return the newly-added object. This path only changes + * the LSP object - nothing is scheduled for processing, for example. */ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, @@ -2103,20 +2151,76 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, union g_addr *gate, ifindex_t ifindex, uint8_t num_labels, - mpls_label_t out_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); } +/* + * Add a backup NHLFE to an LSP, return the newly-added object. + * This path only changes the LSP object - nothing is scheduled for + * processing, for example. + */ +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, + 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); +} + +/* + * Add an NHLFE to an LSP based on a nexthop; return the newly-added object + */ +zebra_nhlfe_t *zebra_mpls_lsp_add_nh(zebra_lsp_t *lsp, + enum lsp_types_t lsp_type, + const struct nexthop *nh) +{ + zebra_nhlfe_t *nhlfe; + + if (nh->nh_label == NULL || nh->nh_label->num_labels == 0) + return NULL; + + nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex, + nh->nh_label->num_labels, nh->nh_label->label); + + return nhlfe; +} + +/* + * Add a backup NHLFE to an LSP based on a nexthop; + * return the newly-added object. + */ +zebra_nhlfe_t *zebra_mpls_lsp_add_backup_nh(zebra_lsp_t *lsp, + enum lsp_types_t lsp_type, + const struct nexthop *nh) +{ + zebra_nhlfe_t *nhlfe; + + if (nh->nh_label == NULL || nh->nh_label->num_labels == 0) + return NULL; + + nhlfe = nhlfe_backup_add(lsp, lsp_type, nh->type, &nh->gate, + nh->ifindex, nh->nh_label->num_labels, + nh->nh_label->label); + + return nhlfe; +} + /* * Free an allocated NHLFE */ -void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe) +void zebra_mpls_nhlfe_free(zebra_nhlfe_t *nhlfe) { /* Just a pass-through to the internal implementation */ - nhlfe_del(nhlfe); + nhlfe_free(nhlfe); } /* @@ -2750,27 +2854,14 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, * 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). */ -int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, - mpls_label_t in_label, uint8_t num_out_labels, - mpls_label_t out_labels[], enum nexthop_types_t gtype, - const union g_addr *gate, ifindex_t ifindex) +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) { - 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; - - /* Find or create LSP object */ - tmp_ile.in_label = in_label; - lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); - if (!lsp) - return -1; + char buf[MPLS_LABEL_STRLEN]; nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate, ifindex); if (nhlfe) { @@ -2785,23 +2876,21 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, && !memcmp(nh->nh_label->label, out_labels, sizeof(mpls_label_t) * num_out_labels)) /* No change */ - return 0; + return nhlfe; if (IS_ZEBRA_DEBUG_MPLS) { char buf2[MPLS_LABEL_STRLEN]; char buf3[MPLS_LABEL_STRLEN]; - nhlfe2str(nhlfe, buf, BUFSIZ); + 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)", - in_label, type, buf, buf2, buf3); + 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. */ @@ -2818,19 +2907,17 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, num_out_labels, out_labels); if (!nhlfe) - return -1; + return NULL; if (IS_ZEBRA_DEBUG_MPLS) { - char buf2[BUFSIZ]; + char buf2[MPLS_LABEL_STRLEN]; - nhlfe2str(nhlfe, buf, BUFSIZ); + 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", - in_label, type, buf, buf2); + 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); @@ -2838,6 +2925,205 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, /* 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; + + 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 backup 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); + } + } else { + /* Add LSP entry to this nexthop */ + nhlfe = nhlfe_backup_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 backup nexthop %s out-label(s) %s", + lsp->ile.in_label, type, buf, buf2); + } + + lsp->addr_family = NHLFE_FAMILY(nhlfe); + } + + /* Mark NHLFE, queue LSP for processing. */ + SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + + return nhlfe; +} + +/* + * Install an LSP and forwarding entry; used primarily + * from zapi message processing. + */ +int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, uint8_t num_out_labels, + const mpls_label_t *out_labels, 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; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* Find or create LSP object */ + tmp_ile.in_label = in_label; + lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); + if (!lsp) + return -1; + + nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype, + gate, ifindex); + if (nhlfe == NULL) + return -1; + + /* Queue LSP for processing. */ + if (lsp_processq_add(lsp)) + return -1; + + return 0; +} + +/* + * Install or replace NHLFE, using info from zapi nexthop + */ +int mpls_lsp_znh_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, + const struct zapi_nexthop *znh) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + zebra_nhlfe_t *nhlfe; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* Find or create LSP object */ + tmp_ile.in_label = in_label; + lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); + if (!lsp) + return -1; + + nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels, + znh->type, &znh->gate, znh->ifindex); + if (nhlfe == NULL) + return -1; + + /* Update backup info if present */ + if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { + nhlfe->nexthop->backup_idx = znh->backup_idx; + SET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP); + } + + /* Queue LSP for processing. */ + if (lsp_processq_add(lsp)) + return -1; + + return 0; +} + +/* + * Install/update backup NHLFE for an LSP, using info from a zapi message. + */ +int mpls_lsp_backup_znh_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, + const struct zapi_nexthop *znh) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + zebra_nhlfe_t *nhlfe; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* Find or create LSP object */ + tmp_ile.in_label = in_label; + lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); + if (!lsp) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("%s: unable to get LSP for label: %u", + __func__, in_label); + return -1; + } + + nhlfe = lsp_add_backup_nhlfe(lsp, type, znh->label_num, znh->labels, + znh->type, &znh->gate, znh->ifindex); + if (nhlfe == NULL) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("%s: unable to add backup nhlfe, label: %u", + __func__, in_label); + return -1; + } + + /* Queue LSP for processing. */ if (lsp_processq_add(lsp)) return -1; diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 9aec9458c..11eb82eb4 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -99,6 +99,7 @@ struct zebra_nhlfe_t_ { #define NHLFE_FLAG_MULTIPATH (1 << 2) #define NHLFE_FLAG_DELETED (1 << 3) #define NHLFE_FLAG_INSTALLED (1 << 4) +#define NHLFE_FLAG_IS_BACKUP (1 << 5) uint8_t distance; @@ -137,6 +138,12 @@ struct zebra_lsp_t_ { zebra_nhlfe_t *best_nhlfe; uint32_t num_ecmp; + /* Backup nhlfes, if present. The nexthop in a primary/active nhlfe + * refers to its backup (if any) by index, so the order of this list + * is significant. + */ + struct nhlfe_list_head backup_nhlfe_list; + /* Flags */ uint32_t flags; #define LSP_FLAG_SCHEDULED (1 << 0) @@ -209,10 +216,31 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, union g_addr *gate, ifindex_t ifindex, uint8_t num_labels, - mpls_label_t out_labels[]); + const mpls_label_t *out_labels); + +/* Add or update a backup NHLFE for an LSP; return the object */ +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, + ifindex_t ifindex, + uint8_t num_labels, + const mpls_label_t *out_labels); + +/* + * Add NHLFE or backup NHLFE to an LSP based on a nexthop. These just maintain + * the LSP and NHLFE objects; nothing is scheduled for processing. + * Return: the newly-added object + */ +zebra_nhlfe_t *zebra_mpls_lsp_add_nh(zebra_lsp_t *lsp, + enum lsp_types_t lsp_type, + const struct nexthop *nh); +zebra_nhlfe_t *zebra_mpls_lsp_add_backup_nh(zebra_lsp_t *lsp, + enum lsp_types_t lsp_type, + const struct nexthop *nh); /* Free an allocated NHLFE */ -void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe); +void zebra_mpls_nhlfe_free(zebra_nhlfe_t *nhlfe); int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, uint32_t label, uint32_t label_index, @@ -295,9 +323,21 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, */ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, uint8_t num_out_labels, - mpls_label_t out_labels[], enum nexthop_types_t gtype, + const mpls_label_t *out_labels, enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex); +/* Version using a zapi nexthop directly */ +int mpls_lsp_znh_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, + const struct zapi_nexthop *znh); + +/* + * Install/update backup NHLFE for an LSP, using zapi nexthop info. + */ +int mpls_lsp_backup_znh_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, + const struct zapi_nexthop *znh); + /* * Uninstall a particular NHLFE in the forwarding table. If this is * the only NHLFE, the entire LSP forwarding entry has to be deleted. -- 2.39.5