summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/zapi_msg.c58
-rw-r--r--zebra/zebra_dplane.c82
-rw-r--r--zebra/zebra_dplane.h11
-rw-r--r--zebra/zebra_mpls.c412
-rw-r--r--zebra/zebra_mpls.h46
5 files changed, 519 insertions, 90 deletions
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 5db4555284..9f099d2819 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 5864471b64..63d55d061d 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 a9e3052240..35ce338959 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 65948a7bef..16dde22089 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);
@@ -1207,21 +1213,13 @@ static zebra_nhlfe_t *nhlfe_find(struct nhlfe_list_head *list,
}
/*
- * 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,7 +2151,7 @@ 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,
@@ -2111,12 +2159,68 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp,
}
/*
+ * 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 9aec9458cb..11eb82eb41 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.