diff options
Diffstat (limited to 'zebra/zebra_mpls.c')
| -rw-r--r-- | zebra/zebra_mpls.c | 1051 |
1 files changed, 816 insertions, 235 deletions
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 0aaede4507..1210430b06 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -93,28 +93,38 @@ static void lsp_processq_del(struct work_queue *wq, void *data); static void lsp_processq_complete(struct work_queue *wq); static int lsp_processq_add(zebra_lsp_t *lsp); static void *lsp_alloc(void *p); + +/* Check whether lsp can be freed - no nhlfes, e.g., and call free api */ +static void lsp_check_free(struct hash *lsp_table, zebra_lsp_t **plsp); + /* Free lsp; sets caller's pointer to NULL */ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp); static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size); static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex); -static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, +static zebra_nhlfe_t *nhlfe_find(struct nhlfe_list_head *list, + enum lsp_types_t lsp_type, enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex); 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, 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); -static void lsp_print(zebra_lsp_t *lsp, void *ctxt); +static void lsp_print(struct vty *vty, zebra_lsp_t *lsp); static void *slsp_alloc(void *p); static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex); @@ -131,7 +141,13 @@ static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size); static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt); static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi, enum lsp_types_t lsp_type); +static int lsp_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type, + const struct zapi_nexthop *znh); +static int lsp_backup_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type, + const struct zapi_nexthop *znh); +/* List implementations - declare internal linkage */ +DECLARE_DLIST(snhlfe_list, struct zebra_snhlfe_t_, list); /* Static functions */ @@ -143,7 +159,7 @@ static void clear_nhlfe_installed(zebra_lsp_t *lsp) zebra_nhlfe_t *nhlfe; struct nexthop *nexthop; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -196,7 +212,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; - nhlfe = nhlfe_find(lsp, lsp_type, nexthop->type, &nexthop->gate, + nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type, + nexthop->type, &nexthop->gate, nexthop->ifindex); if (nhlfe) { /* Clear deleted flag (in case it was set) */ @@ -251,9 +268,9 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, if (added || changed) { if (lsp_processq_add(lsp)) return -1; - } else if (!lsp->nhlfe_list - && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) - lsp_free(lsp_table, &lsp); + } else { + lsp_check_free(lsp_table, &lsp); + } return 0; } @@ -267,7 +284,7 @@ static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label) struct hash *lsp_table; zebra_ile_t tmp_ile; zebra_lsp_t *lsp; - zebra_nhlfe_t *nhlfe, *nhlfe_next; + zebra_nhlfe_t *nhlfe; char buf[BUFSIZ]; /* Lookup table. */ @@ -278,12 +295,11 @@ static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label) /* If entry is not present, exit. */ tmp_ile.in_label = label; lsp = hash_lookup(lsp_table, &tmp_ile); - if (!lsp || !lsp->nhlfe_list) + if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL)) return 0; /* Mark NHLFEs for delete or directly delete, as appropriate. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) { - nhlfe_next = nhlfe->next; + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { /* Skip static NHLFEs */ if (nhlfe->type == ZEBRA_LSP_STATIC) @@ -308,9 +324,9 @@ static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label) if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) { if (lsp_processq_add(lsp)) return -1; - } else if (!lsp->nhlfe_list - && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) - lsp_free(lsp_table, &lsp); + } else { + lsp_check_free(lsp_table, &lsp); + } return 0; } @@ -784,7 +800,7 @@ static void lsp_select_best_nhlfe(zebra_lsp_t *lsp) * only * concerned with non-deleted NHLFEs. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { /* Clear selection flags. */ UNSET_FLAG(nhlfe->flags, (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH)); @@ -809,7 +825,7 @@ static void lsp_select_best_nhlfe(zebra_lsp_t *lsp) * new (uninstalled) NHLFE has been selected, an installed entry that is * still selected has a change or an installed entry is to be removed. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) { int nh_chg, nh_sel, nh_inst; nexthop = nhlfe->nexthop; @@ -967,8 +983,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) * Any NHLFE that was installed but is not * selected now needs to have its flags updated. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; - nhlfe = nhlfe->next) { + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -1012,7 +1027,7 @@ static void lsp_processq_del(struct work_queue *wq, void *data) struct zebra_vrf *zvrf; zebra_lsp_t *lsp; struct hash *lsp_table; - zebra_nhlfe_t *nhlfe, *nhlfe_next; + zebra_nhlfe_t *nhlfe; zvrf = vrf_info_lookup(VRF_DEFAULT); assert(zvrf); @@ -1031,14 +1046,17 @@ static void lsp_processq_del(struct work_queue *wq, void *data) */ UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED); - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) { - nhlfe_next = nhlfe->next; + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)) + nhlfe_del(nhlfe); + } + + frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) { if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)) nhlfe_del(nhlfe); } - if (!lsp->nhlfe_list) - lsp_free(lsp_table, &lsp); + lsp_check_free(lsp_table, &lsp); } /* @@ -1080,6 +1098,8 @@ 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); @@ -1088,13 +1108,31 @@ static void *lsp_alloc(void *p) } /* + * Check whether lsp can be freed - no nhlfes, e.g., and call free api + */ +static void lsp_check_free(struct hash *lsp_table, zebra_lsp_t **plsp) +{ + zebra_lsp_t *lsp; + + if (plsp == NULL || *plsp == NULL) + return; + + lsp = *plsp; + + if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) && + (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) && + !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) + lsp_free(lsp_table, plsp); +} + +/* * Dtor for an LSP: remove from ile hash, release any internal allocations, * free LSP object. */ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp) { zebra_lsp_t *lsp; - zebra_nhlfe_t *nhlfe, *nhlfe_next; + zebra_nhlfe_t *nhlfe; if (plsp == NULL || *plsp == NULL) return; @@ -1106,11 +1144,12 @@ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp) lsp->ile.in_label, lsp->flags); /* Free nhlfes, if any. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) { - nhlfe_next = nhlfe->next; + 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); @@ -1190,16 +1229,14 @@ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, /* * Locate NHLFE that matches with passed info. */ -static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, +static zebra_nhlfe_t *nhlfe_find(struct nhlfe_list_head *list, + enum lsp_types_t lsp_type, enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex) { zebra_nhlfe_t *nhlfe; - if (!lsp) - return NULL; - - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + frr_each_safe(nhlfe_list, list, nhlfe) { if (nhlfe->type != lsp_type) continue; if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex)) @@ -1210,13 +1247,13 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, } /* - * Add NHLFE. Base entry must have been created and duplicate - * check done. + * Allocate and init new NHLFE. */ -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 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; @@ -1235,6 +1272,7 @@ static zebra_nhlfe_t *nhlfe_add(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; @@ -1260,18 +1298,85 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, XFREE(MTYPE_NHLFE, nhlfe); return NULL; } - nhlfe->nexthop = nexthop; - if (lsp->nhlfe_list) - lsp->nhlfe_list->prev = nhlfe; - nhlfe->next = lsp->nhlfe_list; - lsp->nhlfe_list = nhlfe; return nhlfe; } /* - * Delete NHLFE. Entry must be present on list. + * Add 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) +{ + 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; + + 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. */ + if (nhlfe) + nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe); + + return nhlfe; +} + +/* + * 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) { @@ -1284,22 +1389,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 */ - if (nhlfe->next) - nhlfe->next->prev = nhlfe->prev; - if (nhlfe->prev) - nhlfe->prev->next = nhlfe->next; + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP)) + nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe); else - lsp->nhlfe_list = nhlfe->next; + nhlfe_list_del(&lsp->nhlfe_list, nhlfe); - if (nhlfe == lsp->best_nhlfe) - lsp->best_nhlfe = NULL; + nhlfe->lsp = NULL; - XFREE(MTYPE_NHLFE, nhlfe); + nhlfe_free(nhlfe); return 0; } @@ -1316,14 +1417,12 @@ static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp, enum lsp_types_t type) { - zebra_nhlfe_t *nhlfe, *nhlfe_next; + zebra_nhlfe_t *nhlfe; int schedule_lsp = 0; char buf[BUFSIZ]; /* Mark NHLFEs for delete or directly delete, as appropriate. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) { - nhlfe_next = nhlfe->next; - + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { /* Skip non-static NHLFEs */ if (nhlfe->type != type) continue; @@ -1344,13 +1443,34 @@ static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp, } } + frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) { + /* Skip non-static NHLFEs */ + if (nhlfe->type != type) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "Del backup LSP in-label %u type %d nexthop %s flags 0x%x", + lsp->ile.in_label, type, buf, nhlfe->flags); + } + + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) { + UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED); + schedule_lsp = 1; + } else { + nhlfe_del(nhlfe); + } + } + /* Queue LSP for processing, if needed, else delete. */ if (schedule_lsp) { if (lsp_processq_add(lsp)) return -1; - } else if (!lsp->nhlfe_list - && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) - lsp_free(lsp_table, &lsp); + } else { + lsp_check_free(lsp_table, &lsp); + } return 0; } @@ -1374,7 +1494,7 @@ static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf, /* If entry is not present, exit. */ tmp_ile.in_label = in_label; lsp = hash_lookup(lsp_table, &tmp_ile); - if (!lsp || !lsp->nhlfe_list) + if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL)) return 0; return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC); @@ -1424,7 +1544,7 @@ static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe) static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty) { struct nexthop *nexthop; - char buf[BUFSIZ]; + char buf[MPLS_LABEL_STRLEN]; nexthop = nhlfe->nexthop; if (!nexthop || !nexthop->nh_label) // unexpected @@ -1432,7 +1552,9 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty) vty_out(vty, " type: %s remote label: %s distance: %d\n", nhlfe_type2str(nhlfe->type), - label2str(nexthop->nh_label->label[0], buf, BUFSIZ), + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, + buf, sizeof(buf), 0), nhlfe->distance); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -1464,19 +1586,36 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty) /* * Print an LSP forwarding entry. */ -static void lsp_print(zebra_lsp_t *lsp, void *ctxt) +static void lsp_print(struct vty *vty, zebra_lsp_t *lsp) { - zebra_nhlfe_t *nhlfe; - struct vty *vty; - - vty = (struct vty *)ctxt; + zebra_nhlfe_t *nhlfe, *backup; + int i; vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label, CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)" : ""); - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) + frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) { nhlfe_print(nhlfe, vty); + + if (nhlfe->nexthop && + CHECK_FLAG(nhlfe->nexthop->flags, + NEXTHOP_FLAG_HAS_BACKUP)) { + /* Find backup in backup list */ + + i = 0; + frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) { + if (i == nhlfe->nexthop->backup_idx) + break; + i++; + } + + if (backup) { + vty_out(vty, " [backup %d]", i); + nhlfe_print(backup, vty); + } + } + } } /* @@ -1493,7 +1632,7 @@ static json_object *lsp_json(zebra_lsp_t *lsp) if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) json_object_boolean_true_add(json, "installed"); - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) + frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe)); json_object_object_add(json, "nexthops", json_nhlfe_list); @@ -1541,6 +1680,8 @@ static void *slsp_alloc(void *p) slsp = XCALLOC(MTYPE_SLSP, sizeof(zebra_slsp_t)); slsp->ile = *ile; + snhlfe_list_init(&slsp->snhlfe_list); + return ((void *)slsp); } @@ -1600,7 +1741,7 @@ static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp, if (!slsp) return NULL; - for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) { + frr_each_safe(snhlfe_list, &slsp->snhlfe_list, snhlfe) { if (!snhlfe_match(snhlfe, gtype, gate, ifindex)) break; } @@ -1642,10 +1783,7 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, return NULL; } - if (slsp->snhlfe_list) - slsp->snhlfe_list->prev = snhlfe; - snhlfe->next = slsp->snhlfe_list; - slsp->snhlfe_list = snhlfe; + snhlfe_list_add_head(&slsp->snhlfe_list, snhlfe); return snhlfe; } @@ -1664,14 +1802,8 @@ static int snhlfe_del(zebra_snhlfe_t *snhlfe) if (!slsp) return -1; - if (snhlfe->next) - snhlfe->next->prev = snhlfe->prev; - if (snhlfe->prev) - snhlfe->prev->next = snhlfe->next; - else - slsp->snhlfe_list = snhlfe->next; + snhlfe_list_del(&slsp->snhlfe_list, snhlfe); - snhlfe->prev = snhlfe->next = NULL; XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname); XFREE(MTYPE_SNHLFE, snhlfe); @@ -1683,13 +1815,12 @@ static int snhlfe_del(zebra_snhlfe_t *snhlfe) */ static int snhlfe_del_all(zebra_slsp_t *slsp) { - zebra_snhlfe_t *snhlfe, *snhlfe_next; + zebra_snhlfe_t *snhlfe; if (!slsp) return -1; - for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next) { - snhlfe_next = snhlfe->next; + frr_each_safe(snhlfe_list, &slsp->snhlfe_list, snhlfe) { snhlfe_del(snhlfe); } @@ -1793,8 +1924,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { /* Update zebra object */ SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); - for (nhlfe = lsp->nhlfe_list; nhlfe; - nhlfe = nhlfe->next) { + frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -1837,6 +1967,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) 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; @@ -1872,7 +2003,8 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) * the existing state of the LSP objects available before making * any changes. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + head = dplane_ctx_get_nhlfe_list(ctx); + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { char buf[NEXTHOP_STRLEN]; nexthop = nhlfe->nexthop; @@ -1883,9 +2015,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) start_count++; ctx_nexthop = NULL; - for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx); - ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) { - + frr_each(nhlfe_list_const, head, ctx_nhlfe) { ctx_nexthop = ctx_nhlfe->nexthop; if (!ctx_nexthop) continue; @@ -1960,7 +2090,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) * Now we take a second pass and bring the zebra * nexthop state into sync with the forwarding-plane state. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { char buf[NEXTHOP_STRLEN]; nexthop = nhlfe->nexthop; @@ -1968,9 +2098,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) continue; ctx_nexthop = NULL; - for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx); - ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) { - + frr_each(nhlfe_list_const, head, ctx_nhlfe) { ctx_nexthop = ctx_nhlfe->nexthop; if (!ctx_nexthop) continue; @@ -2088,7 +2216,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, @@ -2096,7 +2225,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, @@ -2104,12 +2233,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); } /* @@ -2579,22 +2764,23 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, fec_print(rn->info, vty); } -static void mpls_zebra_nhg_update(struct route_entry *re, afi_t afi, - struct nexthop_group *new_grp) +static void mpls_zebra_nhe_update(struct route_entry *re, afi_t afi, + struct nhg_hash_entry *new_nhe) { struct nhg_hash_entry *nhe; - nhe = zebra_nhg_rib_find(0, new_grp, afi); + nhe = zebra_nhg_rib_find_nhe(new_nhe, afi); route_entry_update_nhe(re, nhe); } -static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, - enum lsp_types_t type, mpls_label_t label) +static bool ftn_update_nexthop(bool add_p, struct nexthop *nexthop, + enum lsp_types_t type, + const struct zapi_nexthop *znh) { - if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE) - nexthop_add_labels(nexthop, type, 1, &label); - else if (!add && nexthop->nh_label_type == type) + if (add_p && nexthop->nh_label_type == ZEBRA_LSP_NONE) + nexthop_add_labels(nexthop, type, znh->label_num, znh->labels); + else if (!add_p && nexthop->nh_label_type == type) nexthop_del_labels(nexthop); else return false; @@ -2602,20 +2788,15 @@ static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, return true; } -/* - * Install/uninstall a FEC-To-NHLFE (FTN) binding. - */ -int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, - struct prefix *prefix, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, uint8_t route_type, - unsigned short route_instance, mpls_label_t out_label) +int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + unsigned short route_instance) { struct route_table *table; struct route_node *rn; struct route_entry *re; struct nexthop *nexthop; - struct nexthop_group new_grp = {}; - bool found; + struct nhg_hash_entry *new_nhe; afi_t afi = family2afi(prefix->family); /* Lookup table. */ @@ -2631,111 +2812,374 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, if (re->type == route_type && re->instance == route_instance) break; } - if (re == NULL) return -1; /* - * Copy over current nexthops into a temporary group. - * We can't just change the values here since we are hashing - * on labels. We need to create a whole new group + * Nexthops are now shared by multiple routes, so we have to make + * a local copy, modify the copy, then update the route. */ - nexthop_group_copy(&new_grp, &(re->nhe->nhg)); + new_nhe = zebra_nhe_copy(re->nhe, 0); + + for (nexthop = new_nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) + nexthop_del_labels(nexthop); + + /* Update backup routes/nexthops also, if present. */ + if (zebra_nhg_get_backup_nhg(new_nhe) != NULL) { + for (nexthop = new_nhe->backup_info->nhe->nhg.nexthop; nexthop; + nexthop = nexthop->next) + nexthop_del_labels(nexthop); + } - found = false; - for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + + mpls_zebra_nhe_update(re, afi, new_nhe); + + zebra_nhg_free(new_nhe); + + rib_queue_add(rn); + + return 0; +} + +/* + * Iterate through a list of nexthops, for a match for 'znh'. If found, + * update its labels according to 'add_p', and return 'true' if successful. + */ +static bool ftn_update_znh(bool add_p, enum lsp_types_t type, + struct nexthop *head, const struct zapi_nexthop *znh) +{ + bool found = false, success = false; + struct nexthop *nexthop; + + for (nexthop = head; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - if (gtype != NEXTHOP_TYPE_IPV4 - && gtype != NEXTHOP_TYPE_IPV4_IFINDEX) + if (znh->type != NEXTHOP_TYPE_IPV4 + && znh->type != NEXTHOP_TYPE_IPV4_IFINDEX) continue; - if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4)) + if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, + &znh->gate.ipv4)) continue; if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - && nexthop->ifindex != ifindex) + && nexthop->ifindex != znh->ifindex) continue; - if (!mpls_ftn_update_nexthop(add, nexthop, type, - out_label)) - break; + found = true; + + if (!ftn_update_nexthop(add_p, nexthop, type, znh)) + break; + + success = true; break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - if (gtype != NEXTHOP_TYPE_IPV6 - && gtype != NEXTHOP_TYPE_IPV6_IFINDEX) + if (znh->type != NEXTHOP_TYPE_IPV6 + && znh->type != NEXTHOP_TYPE_IPV6_IFINDEX) continue; - if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6)) + if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, + &znh->gate.ipv6)) continue; if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX - && nexthop->ifindex != ifindex) + && nexthop->ifindex != znh->ifindex) continue; - if (!mpls_ftn_update_nexthop(add, nexthop, type, - out_label)) - break; + found = true; + + if (!ftn_update_nexthop(add_p, nexthop, type, znh)) + break; + success = true; break; default: break; } + + if (found) + break; + } + + return success; +} + +/* + * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings, + * using zapi message info. + * There are several changes that need to be made, in several zebra + * data structures, so we want to do all the work required at once. + */ +int mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf, + const struct zapi_labels *zl) +{ + int i, counter, ret = 0; + char buf[NEXTHOP_STRLEN], prefix_buf[PREFIX_STRLEN]; + const struct zapi_nexthop *znh; + struct route_table *table; + struct route_node *rn = NULL; + struct route_entry *re = NULL; + struct nhg_hash_entry *new_nhe = NULL; + bool found; + afi_t afi = AFI_IP; + const struct prefix *prefix = NULL; + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp = NULL; + + /* Prep LSP for add case */ + if (add_p) { + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + /* Find or create LSP object */ + tmp_ile.in_label = zl->local_label; + lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); + if (!lsp) + return -1; + } + + /* Prep for route/FEC update if requested */ + if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) { + prefix = &zl->route.prefix; + + afi = family2afi(prefix->family); + + /* Lookup table. */ + table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); + if (table) { + /* Lookup existing route */ + rn = route_node_get(table, prefix); + RNODE_FOREACH_RE(rn, re) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + if (re->type == zl->route.type && + re->instance == zl->route.instance) + break; + } + } + + if (re) { + /* + * Copy over current nexthops into a temporary group. + * We can't just change the values here since the nhgs + * are shared and if the labels change, we'll need + * to find or create a new nhg. We need to create + * a whole temporary group, make changes to it, + * then attach that to the route. + */ + new_nhe = zebra_nhe_copy(re->nhe, 0); + + } else { + /* + * The old version of the zapi code + * attempted to manage LSPs before trying to + * find a route/FEC, so we'll continue that way. + */ + if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) { + prefix2str(prefix, prefix_buf, + sizeof(prefix_buf)); + zlog_debug("%s: FTN update requested: no route for prefix %s", + __func__, prefix_buf); + } + } } - if (found) { + /* + * Use info from the zapi nexthops to add/replace/remove LSP/FECs + */ + + counter = 0; + for (i = 0; i < zl->nexthop_num; i++) { + + znh = &zl->nexthops[i]; + + /* Attempt LSP update */ + if (add_p) + ret = lsp_znh_install(lsp, zl->type, znh); + else + ret = mpls_lsp_uninstall(zvrf, zl->type, + zl->local_label, znh->type, + &znh->gate, znh->ifindex); + if (ret < 0) { + if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + zlog_debug("%s: Unable to %sinstall LSP: label %u, znh %s", + __func__, (add_p ? "" : "un"), + zl->local_label, buf); + } + continue; + } + + /* Attempt route/FEC update if requested */ + if (re == NULL) + continue; + + /* Search the route's nexthops for a match, and update it. */ + found = ftn_update_znh(add_p, zl->type, new_nhe->nhg.nexthop, + znh); + if (found) { + counter++; + } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + prefix2str(prefix, prefix_buf, sizeof(prefix_buf)); + zlog_debug("%s: Unable to update FEC: prefix %s, label %u, znh %s", + __func__, prefix_buf, zl->local_label, buf); + } + } + + /* + * Process backup LSPs/nexthop entries also. We associate backup + * LSP info with backup nexthops. + */ + if (!CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS)) + goto znh_done; + + for (i = 0; i < zl->backup_nexthop_num; i++) { + + znh = &zl->backup_nexthops[i]; + + 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); + + if (ret < 0) { + if (IS_ZEBRA_DEBUG_RECV || + IS_ZEBRA_DEBUG_MPLS) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + zlog_debug("%s: Unable to %sinstall backup LSP: label %u, znh %s", + __func__, (add_p ? "" : "un"), + zl->local_label, buf); + } + continue; + } + + /* Attempt backup nexthop/FEC update if requested */ + if (re == NULL || zebra_nhg_get_backup_nhg(new_nhe) == NULL) + continue; + + /* Search the route's backup nexthops for a match + * and update it. + */ + found = ftn_update_znh(add_p, zl->type, + new_nhe->backup_info->nhe->nhg.nexthop, + znh); + if (found) { + counter++; + } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) { + zapi_nexthop2str(znh, buf, sizeof(buf)); + prefix2str(prefix, prefix_buf, sizeof(prefix_buf)); + zlog_debug("%s: Unable to update backup FEC: prefix %s, label %u, znh %s", + __func__, prefix_buf, zl->local_label, buf); + } + } + +znh_done: + + /* + * If we made changes, update the route, and schedule it + * for rib processing + */ + if (re != NULL && counter > 0) { + assert(rn != NULL); + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); - mpls_zebra_nhg_update(re, afi, &new_grp); + mpls_zebra_nhe_update(re, afi, new_nhe); rib_queue_add(rn); } - nexthops_free(new_grp.nexthop); + if (new_nhe) + zebra_nhg_free(new_nhe); - return found ? 0 : -1; + return ret; } -int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, - struct prefix *prefix, uint8_t route_type, - unsigned short route_instance) +/* + * 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_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 route_table *table; - struct route_node *rn; - struct route_entry *re; - struct nexthop *nexthop; - struct nexthop_group new_grp = {}; - afi_t afi = family2afi(prefix->family); + zebra_nhlfe_t *nhlfe; + char buf[MPLS_LABEL_STRLEN]; - /* Lookup table. */ - table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); - if (!table) - return -1; + nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate, ifindex); + if (nhlfe) { + struct nexthop *nh = nhlfe->nexthop; - /* Lookup existing route */ - rn = route_node_get(table, prefix); - RNODE_FOREACH_RE (rn, re) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) - continue; - if (re->type == route_type && re->instance == route_instance) - break; - } - if (re == NULL) - return -1; + assert(nh); + assert(nh->nh_label); - nexthop_group_copy(&new_grp, &(re->nhe->nhg)); + /* 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; - for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) - nexthop_del_labels(nexthop); + if (IS_ZEBRA_DEBUG_MPLS) { + char buf2[MPLS_LABEL_STRLEN]; + char buf3[MPLS_LABEL_STRLEN]; - SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + 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); + } + } else { + /* Add LSP entry to this nexthop */ + nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, + num_out_labels, out_labels); + if (!nhlfe) + return NULL; - mpls_zebra_nhg_update(re, afi, &new_grp); + if (IS_ZEBRA_DEBUG_MPLS) { + char buf2[MPLS_LABEL_STRLEN]; - nexthops_free(new_grp.nexthop); + nhlfe2str(nhlfe, buf, sizeof(buf)); + mpls_label2str(num_out_labels, out_labels, buf2, + sizeof(buf2), 0); - rib_queue_add(rn); + zlog_debug("Add LSP in-label %u type %d nexthop %s out-label(s) %s", + lsp->ile.in_label, type, buf, buf2); + } - return 0; + lsp->addr_family = NHLFE_FAMILY(nhlfe); + } + + /* Mark NHLFE, queue LSP for processing. */ + SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + + return nhlfe; } /* @@ -2743,29 +3187,16 @@ 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_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) { - struct hash *lsp_table; - zebra_ile_t tmp_ile; - zebra_lsp_t *lsp; zebra_nhlfe_t *nhlfe; - char buf[BUFSIZ]; + char buf[MPLS_LABEL_STRLEN]; - /* 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 = nhlfe_find(lsp, type, gtype, gate, ifindex); + nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype, gate, ifindex); if (nhlfe) { struct nexthop *nh = nhlfe->nexthop; @@ -2778,23 +3209,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 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. */ @@ -2808,22 +3237,20 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, } } else { /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, - num_out_labels, out_labels); + nhlfe = nhlfe_backup_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 backup nexthop %s out-label(s) %s", + lsp->ile.in_label, type, buf, buf2); } lsp->addr_family = NHLFE_FAMILY(nhlfe); @@ -2831,6 +3258,92 @@ 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 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 + */ +static int lsp_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type, + const struct zapi_nexthop *znh) +{ + zebra_nhlfe_t *nhlfe; + + 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. + */ +static int lsp_backup_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type, + const struct zapi_nexthop *znh) +{ + zebra_nhlfe_t *nhlfe; + + 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__, lsp->ile.in_label); + return -1; + } + + /* Queue LSP for processing. */ if (lsp_processq_add(lsp)) return -1; @@ -2861,7 +3374,7 @@ 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, type, gtype, gate, ifindex); + nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate, ifindex); if (!nhlfe) return 0; @@ -2881,10 +3394,58 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, nhlfe_del(nhlfe); /* Free LSP entry if no other NHLFEs and not scheduled. */ - if (!lsp->nhlfe_list - && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) - lsp_free(lsp_table, &lsp); + lsp_check_free(lsp_table, &lsp); + + } + 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; } @@ -2921,7 +3482,7 @@ static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt) struct hash *lsp_table; lsp = (zebra_lsp_t *)bucket->data; - if (!lsp->nhlfe_list) + if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) return; lsp_table = args->lsp_table; @@ -2942,7 +3503,8 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, struct route_node *rn; struct route_entry *re; struct nexthop *nexthop; - int update; + struct nexthop_group *nhg; + bool update; /* Process routes of interested address-families. */ table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); @@ -2950,13 +3512,15 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, return; for (rn = route_top(table); rn; rn = route_next(rn)) { - update = 0; + update = false; + RNODE_FOREACH_RE (rn, re) { - struct nexthop_group new_grp = {}; + struct nhg_hash_entry *new_nhe; - nexthop_group_copy(&new_grp, &(re->nhe->nhg)); + new_nhe = zebra_nhe_copy(re->nhe, 0); - for (nexthop = new_grp.nexthop; nexthop; + nhg = &new_nhe->nhg; + for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) { if (nexthop->nh_label_type != lsp_type) continue; @@ -2965,13 +3529,30 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); - update = 1; + update = true; + } + + /* Check for backup info and update that also */ + nhg = zebra_nhg_get_backup_nhg(new_nhe); + if (nhg != NULL) { + for (nexthop = nhg->nexthop; nexthop; + nexthop = nexthop->next) { + if (nexthop->nh_label_type != lsp_type) + continue; + + nexthop_del_labels(nexthop); + SET_FLAG(re->status, + ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, + ROUTE_ENTRY_LABELS_CHANGED); + update = true; + } } if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) - mpls_zebra_nhg_update(re, afi, &new_grp); + mpls_zebra_nhe_update(re, afi, new_nhe); - nexthops_free(new_grp.nexthop); + zebra_nhg_free(new_nhe); } if (update) @@ -3014,15 +3595,17 @@ int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf, return 1; /* If not only NHLFE, cannot allow label change. */ - if (snhlfe != slsp->snhlfe_list || snhlfe->next) + if (snhlfe != snhlfe_list_first(&slsp->snhlfe_list) || + snhlfe_list_next(&slsp->snhlfe_list, snhlfe) != NULL) return 0; } else { /* If other NHLFEs exist, label operation must match. */ - if (slsp->snhlfe_list) { + snhlfe = snhlfe_list_first(&slsp->snhlfe_list); + if (snhlfe != NULL) { int cur_op, new_op; - cur_op = (slsp->snhlfe_list->out_label - == MPLS_LABEL_IMPLICIT_NULL); + cur_op = (snhlfe->out_label == + MPLS_LABEL_IMPLICIT_NULL); new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL); if (cur_op != new_op) return 0; @@ -3159,7 +3742,7 @@ int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label, /* Remove entire static LSP entry if no NHLFE - valid in either case * above. */ - if (!slsp->snhlfe_list) { + if (snhlfe_list_first(&slsp->snhlfe_list) == NULL) { slsp = hash_release(slsp_table, &tmp_ile); XFREE(MTYPE_SLSP, slsp); } @@ -3208,7 +3791,7 @@ void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf, json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } else - lsp_print(lsp, (void *)vty); + lsp_print(vty, lsp); } /* @@ -3247,8 +3830,7 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) { - for (nhlfe = lsp->nhlfe_list; nhlfe; - nhlfe = nhlfe->next) { + frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) { struct nexthop *nexthop; const char *out_label_str; char nh_buf[NEXTHOP_STRLEN]; @@ -3320,8 +3902,7 @@ int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf) hash_get_sorted_list(zvrf->slsp_table, slsp_cmp); for (ALL_LIST_ELEMENTS_RO(slsp_list, node, slsp)) { - for (snhlfe = slsp->snhlfe_list; snhlfe; - snhlfe = snhlfe->next) { + frr_each(snhlfe_list, &slsp->snhlfe_list, snhlfe) { char buf[BUFSIZ]; char lstr[30]; |
