]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: support backup nhlfes in LSPs
authorMark Stapp <mjs@voltanet.io>
Fri, 10 Apr 2020 18:47:00 +0000 (14:47 -0400)
committerMark Stapp <mjs@voltanet.io>
Mon, 1 Jun 2020 18:46:32 +0000 (14:46 -0400)
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 <mjs@voltanet.io>
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h

index 5db455528411fdccdb73c2903a1c27ac49d462bd..9f099d281911bc73a56c6e4272a6b21357e3a71f 100644 (file)
@@ -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;
+                       }
+               }
        }
 }
 
index 5864471b64581aa4803d23d9910de18ee8335ebf..63d55d061d2ad2634809b4f3c23a1f65d2f321b9 100644 (file)
@@ -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;
 }
index a9e30522400cfd757363d9939d8df3823bda3ad7..35ce338959e0bbeb60175265752b54006cdfd14c 100644 (file)
@@ -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,
index 65948a7beffcc9d1b66445c19966534248198a26..16dde220895bdf3d113b2205b694b15000fdc08a 100644 (file)
@@ -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;
 
index 9aec9458cb3e745c7e4cae925679b8dd8abf1ebf..11eb82eb41f0ef889d5dc02f90cf8add9f380747 100644 (file)
@@ -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.