diff options
Diffstat (limited to 'zebra/zebra_mpls.c')
-rw-r--r-- | zebra/zebra_mpls.c | 4393 |
1 files changed, 2107 insertions, 2286 deletions
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 3c8503878..e44e5d2e6 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -45,12 +45,12 @@ #include "zebra/zebra_vrf.h" #include "zebra/zebra_mpls.h" -DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object") -DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object") -DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config") -DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object") -DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object") -DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname") +DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object") +DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object") +DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config") +DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object") +DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object") +DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname") int mpls_enabled; @@ -59,106 +59,72 @@ extern struct zebra_t zebrad; /* static function declarations */ -static void -fec_evaluate (struct zebra_vrf *zvrf); -static u_int32_t -fec_derive_label_from_index (struct zebra_vrf *vrf, zebra_fec_t *fec); -static int -lsp_install (struct zebra_vrf *zvrf, mpls_label_t label, - struct route_node *rn, struct route_entry *re); -static int -lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label); -static int -fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label); -static int -fec_send (zebra_fec_t *fec, struct zserv *client); -static void -fec_update_clients (zebra_fec_t *fec); -static void -fec_print (zebra_fec_t *fec, struct vty *vty); -static zebra_fec_t * -fec_find (struct route_table *table, struct prefix *p); -static zebra_fec_t * -fec_add (struct route_table *table, struct prefix *p, mpls_label_t label, - u_int32_t flags, u_int32_t label_index); -static int -fec_del (zebra_fec_t *fec); - -static unsigned int -label_hash (void *p); -static int -label_cmp (const void *p1, const void *p2); -static int -nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop); -static int -nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop); -static int -nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe); - -static void -lsp_select_best_nhlfe (zebra_lsp_t *lsp); -static void -lsp_uninstall_from_kernel (struct hash_backet *backet, void *ctxt); -static void -lsp_schedule (struct hash_backet *backet, void *ctxt); -static wq_item_status -lsp_process (struct work_queue *wq, void *data); -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); - -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, - union g_addr *gate, ifindex_t ifindex); -static zebra_nhlfe_t * -nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, 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, union g_addr *gate, - ifindex_t ifindex, mpls_label_t out_label); -static int -nhlfe_del (zebra_nhlfe_t *snhlfe); -static void -nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label); -static int -mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp, - enum lsp_types_t type); -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 * -slsp_alloc (void *p); -static int -snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); -static zebra_snhlfe_t * -snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); -static zebra_snhlfe_t * -snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label); -static int -snhlfe_del (zebra_snhlfe_t *snhlfe); -static int -snhlfe_del_all (zebra_slsp_t *slsp); -static char * -snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size); -static int -mpls_processq_init (struct zebra_t *zebra); - - +static void fec_evaluate(struct zebra_vrf *zvrf); +static u_int32_t fec_derive_label_from_index(struct zebra_vrf *vrf, + zebra_fec_t *fec); +static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, + struct route_node *rn, struct route_entry *re); +static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label); +static int fec_change_update_lsp(struct zebra_vrf *zvrf, zebra_fec_t *fec, + mpls_label_t old_label); +static int fec_send(zebra_fec_t *fec, struct zserv *client); +static void fec_update_clients(zebra_fec_t *fec); +static void fec_print(zebra_fec_t *fec, struct vty *vty); +static zebra_fec_t *fec_find(struct route_table *table, struct prefix *p); +static zebra_fec_t *fec_add(struct route_table *table, struct prefix *p, + mpls_label_t label, u_int32_t flags, + u_int32_t label_index); +static int fec_del(zebra_fec_t *fec); + +static unsigned int label_hash(void *p); +static int label_cmp(const void *p1, const void *p2); +static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe, + struct nexthop *nexthop); +static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, + struct nexthop *nexthop); +static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe); + +static void lsp_select_best_nhlfe(zebra_lsp_t *lsp); +static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt); +static void lsp_schedule(struct hash_backet *backet, void *ctxt); +static wq_item_status lsp_process(struct work_queue *wq, void *data); +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); + +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, + union g_addr *gate, ifindex_t ifindex); +static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, 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, union g_addr *gate, + ifindex_t ifindex, mpls_label_t out_label); +static int nhlfe_del(zebra_nhlfe_t *snhlfe); +static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, + struct nexthop_label *nh_label); +static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp, + enum lsp_types_t type); +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 *slsp_alloc(void *p); +static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex); +static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp, + enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex); +static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, + enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex, + mpls_label_t out_label); +static int snhlfe_del(zebra_snhlfe_t *snhlfe); +static int snhlfe_del_all(zebra_slsp_t *slsp); +static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size); +static int mpls_processq_init(struct zebra_t *zebra); /* Static functions */ @@ -166,189 +132,175 @@ mpls_processq_init (struct zebra_t *zebra); /* * Install label forwarding entry based on labeled-route entry. */ -static int -lsp_install (struct zebra_vrf *zvrf, mpls_label_t label, - struct route_node *rn, struct route_entry *re) -{ - struct hash *lsp_table; - zebra_ile_t tmp_ile; - zebra_lsp_t *lsp; - zebra_nhlfe_t *nhlfe; - struct nexthop *nexthop; - enum lsp_types_t lsp_type; - char buf[BUFSIZ]; - int added, changed; - - /* Lookup table. */ - lsp_table = zvrf->lsp_table; - if (!lsp_table) - return -1; - - lsp_type = lsp_type_from_re_type (re->type); - added = changed = 0; - - /* Locate or allocate LSP entry. */ - tmp_ile.in_label = label; - lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc); - if (!lsp) - return -1; - - /* For each active nexthop, create NHLFE. Note that we deliberately skip - * recursive nexthops right now, because intermediate hops won't understand - * the label advertised by the recursive nexthop (plus we don't have the - * logic yet to push multiple labels). - */ - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) - { - /* Skip inactive and recursive entries. */ - if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - continue; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - nhlfe = nhlfe_find (lsp, lsp_type, nexthop->type, &nexthop->gate, - nexthop->ifindex); - if (nhlfe) - { - /* Clear deleted flag (in case it was set) */ - UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED); - if (nexthop_labels_match (nhlfe->nexthop, nexthop)) - /* No change */ - continue; - - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("LSP in-label %u type %d nexthop %s " - "out-label changed", - lsp->ile.in_label, lsp_type, buf); - } - - /* Update out label, trigger processing. */ - nhlfe_out_label_update (nhlfe, nexthop->nh_label); - SET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED); - changed++; - } - else - { - /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add (lsp, lsp_type, nexthop->type, - &nexthop->gate, nexthop->ifindex, - nexthop->nh_label->label[0]); - if (!nhlfe) - return -1; - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("Add LSP in-label %u type %d nexthop %s " - "out-label %u", - lsp->ile.in_label, lsp_type, buf, - nexthop->nh_label->label[0]); - } - - lsp->addr_family = NHLFE_FAMILY (nhlfe); - - /* Mark NHLFE as changed. */ - SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); - added++; - } - } - - /* Queue LSP for processing if necessary. If no NHLFE got added (special - * case), delete the LSP entry; this case results in somewhat ugly logging. - */ - if (added || changed) - { - if (lsp_processq_add (lsp)) - return -1; - } - else if (!lsp->nhlfe_list && - !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED)) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Free LSP in-label %u flags 0x%x", - lsp->ile.in_label, lsp->flags); - - lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); - } - - return 0; +static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, + struct route_node *rn, struct route_entry *re) +{ + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; + zebra_nhlfe_t *nhlfe; + struct nexthop *nexthop; + enum lsp_types_t lsp_type; + char buf[BUFSIZ]; + int added, changed; + + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return -1; + + lsp_type = lsp_type_from_re_type(re->type); + added = changed = 0; + + /* Locate or allocate LSP entry. */ + tmp_ile.in_label = label; + lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); + if (!lsp) + return -1; + + /* For each active nexthop, create NHLFE. Note that we deliberately skip + * recursive nexthops right now, because intermediate hops won't + * understand + * the label advertised by the recursive nexthop (plus we don't have the + * logic yet to push multiple labels). + */ + for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) { + /* Skip inactive and recursive entries. */ + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + nhlfe = nhlfe_find(lsp, lsp_type, nexthop->type, &nexthop->gate, + nexthop->ifindex); + if (nhlfe) { + /* Clear deleted flag (in case it was set) */ + UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED); + if (nexthop_labels_match(nhlfe->nexthop, nexthop)) + /* No change */ + continue; + + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "LSP in-label %u type %d nexthop %s " + "out-label changed", + lsp->ile.in_label, lsp_type, buf); + } + + /* Update out label, trigger processing. */ + nhlfe_out_label_update(nhlfe, nexthop->nh_label); + SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + changed++; + } else { + /* Add LSP entry to this nexthop */ + nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type, + &nexthop->gate, nexthop->ifindex, + nexthop->nh_label->label[0]); + if (!nhlfe) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "Add LSP in-label %u type %d nexthop %s " + "out-label %u", + lsp->ile.in_label, lsp_type, buf, + nexthop->nh_label->label[0]); + } + + lsp->addr_family = NHLFE_FAMILY(nhlfe); + + /* Mark NHLFE as changed. */ + SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + added++; + } + } + + /* Queue LSP for processing if necessary. If no NHLFE got added (special + * case), delete the LSP entry; this case results in somewhat ugly + * logging. + */ + if (added || changed) { + if (lsp_processq_add(lsp)) + return -1; + } else if (!lsp->nhlfe_list + && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Free LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); + + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } + + return 0; } /* * Uninstall all non-static NHLFEs of a label forwarding entry. If all * NHLFEs are removed, the entire entry is deleted. */ -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; - 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 = label; - lsp = hash_lookup (lsp_table, &tmp_ile); - if (!lsp || !lsp->nhlfe_list) - return 0; - - /* Mark NHLFEs for delete or directly delete, as appropriate. */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) - { - nhlfe_next = nhlfe->next; - - /* Skip static NHLFEs */ - if (nhlfe->type == ZEBRA_LSP_STATIC) - continue; - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x", - label, nhlfe->type, buf, nhlfe->flags); - } - - if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) - { - UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED); - SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED); - } - else - { - nhlfe_del (nhlfe); - } - } - - /* Queue LSP for processing, if needed, else delete. */ - 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)) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Del LSP in-label %u flags 0x%x", - lsp->ile.in_label, lsp->flags); - - lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); - } - - return 0; +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; + 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 = label; + lsp = hash_lookup(lsp_table, &tmp_ile); + if (!lsp || !lsp->nhlfe_list) + return 0; + + /* Mark NHLFEs for delete or directly delete, as appropriate. */ + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) { + nhlfe_next = nhlfe->next; + + /* Skip static NHLFEs */ + if (nhlfe->type == ZEBRA_LSP_STATIC) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "Del LSP in-label %u type %d nexthop %s flags 0x%x", + label, nhlfe->type, buf, nhlfe->flags); + } + + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) { + UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED); + } else { + nhlfe_del(nhlfe); + } + } + + /* Queue LSP for processing, if needed, else delete. */ + 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)) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Del LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); + + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } + + return 0; } /* @@ -356,54 +308,55 @@ lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label) * will walk all registered FECs with label-index and appropriately update * their local labels and trigger client updates. */ -static void -fec_evaluate (struct zebra_vrf *zvrf) -{ - struct route_node *rn; - zebra_fec_t *fec; - u_int32_t old_label, new_label; - int af; - char buf[BUFSIZ]; - - for (af = AFI_IP; af < AFI_MAX; af++) - { - if (zvrf->fec_table[af] == NULL) - continue; - - for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) - { - if ((fec = rn->info) == NULL) - continue; - - /* Skip configured FECs and those without a label index. */ - if (fec->flags & FEC_FLAG_CONFIGURED || - fec->label_index == MPLS_INVALID_LABEL_INDEX) - continue; - - if (IS_ZEBRA_DEBUG_MPLS) - prefix2str(&rn->p, buf, BUFSIZ); - - /* Save old label, determine new label. */ - old_label = fec->label; - new_label = zvrf->mpls_srgb.start_label + fec->label_index; - if (new_label >= zvrf->mpls_srgb.end_label) - new_label = MPLS_INVALID_LABEL; - - /* If label has changed, update FEC and clients. */ - if (new_label == old_label) - continue; - - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Update fec %s new label %u upon label block", - buf, new_label); - - fec->label = new_label; - fec_update_clients (fec); - - /* Update label forwarding entries appropriately */ - fec_change_update_lsp (zvrf, fec, old_label); - } - } +static void fec_evaluate(struct zebra_vrf *zvrf) +{ + struct route_node *rn; + zebra_fec_t *fec; + u_int32_t old_label, new_label; + int af; + char buf[BUFSIZ]; + + for (af = AFI_IP; af < AFI_MAX; af++) { + if (zvrf->fec_table[af] == NULL) + continue; + + for (rn = route_top(zvrf->fec_table[af]); rn; + rn = route_next(rn)) { + if ((fec = rn->info) == NULL) + continue; + + /* Skip configured FECs and those without a label index. + */ + if (fec->flags & FEC_FLAG_CONFIGURED + || fec->label_index == MPLS_INVALID_LABEL_INDEX) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) + prefix2str(&rn->p, buf, BUFSIZ); + + /* Save old label, determine new label. */ + old_label = fec->label; + new_label = + zvrf->mpls_srgb.start_label + fec->label_index; + if (new_label >= zvrf->mpls_srgb.end_label) + new_label = MPLS_INVALID_LABEL; + + /* If label has changed, update FEC and clients. */ + if (new_label == old_label) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug( + "Update fec %s new label %u upon label block", + buf, new_label); + + fec->label = new_label; + fec_update_clients(fec); + + /* Update label forwarding entries appropriately */ + fec_change_update_lsp(zvrf, fec, old_label); + } + } } /* @@ -411,195 +364,188 @@ fec_evaluate (struct zebra_vrf *zvrf) * its label index. The index is "acceptable" if it falls within the * globally configured label block (SRGB). */ -static u_int32_t -fec_derive_label_from_index (struct zebra_vrf *zvrf, zebra_fec_t *fec) +static u_int32_t fec_derive_label_from_index(struct zebra_vrf *zvrf, + zebra_fec_t *fec) { - u_int32_t label; + u_int32_t label; - if (fec->label_index != MPLS_INVALID_LABEL_INDEX && - zvrf->mpls_srgb.start_label && - ((label = zvrf->mpls_srgb.start_label + fec->label_index) < - zvrf->mpls_srgb.end_label)) - fec->label = label; - else - fec->label = MPLS_INVALID_LABEL; + if (fec->label_index != MPLS_INVALID_LABEL_INDEX + && zvrf->mpls_srgb.start_label + && ((label = zvrf->mpls_srgb.start_label + fec->label_index) + < zvrf->mpls_srgb.end_label)) + fec->label = label; + else + fec->label = MPLS_INVALID_LABEL; - return fec->label; + return fec->label; } /* * There is a change for this FEC. Install or uninstall label forwarding * entries, as appropriate. */ -static int -fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label) +static int fec_change_update_lsp(struct zebra_vrf *zvrf, zebra_fec_t *fec, + mpls_label_t old_label) { - struct route_table *table; - struct route_node *rn; - struct route_entry *re; - afi_t afi; + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + afi_t afi; - /* Uninstall label forwarding entry, if previously installed. */ - if (old_label != MPLS_INVALID_LABEL && - old_label != MPLS_IMP_NULL_LABEL) - lsp_uninstall (zvrf, old_label); + /* Uninstall label forwarding entry, if previously installed. */ + if (old_label != MPLS_INVALID_LABEL && old_label != MPLS_IMP_NULL_LABEL) + lsp_uninstall(zvrf, old_label); - /* Install label forwarding entry corr. to new label, if needed. */ - if (fec->label == MPLS_INVALID_LABEL || - fec->label == MPLS_IMP_NULL_LABEL) - return 0; + /* Install label forwarding entry corr. to new label, if needed. */ + if (fec->label == MPLS_INVALID_LABEL + || fec->label == MPLS_IMP_NULL_LABEL) + return 0; - afi = family2afi(PREFIX_FAMILY(&fec->rn->p)); - table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf_id (zvrf)); - if (!table) - return 0; + afi = family2afi(PREFIX_FAMILY(&fec->rn->p)); + table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); + if (!table) + return 0; - /* See if labeled route exists. */ - rn = route_node_lookup (table, &fec->rn->p); - if (!rn) - return 0; + /* See if labeled route exists. */ + rn = route_node_lookup(table, &fec->rn->p); + if (!rn) + return 0; - RNODE_FOREACH_RE (rn, re) - { - if (CHECK_FLAG (re->flags, ZEBRA_FLAG_SELECTED)) - break; - } + RNODE_FOREACH_RE(rn, re) + { + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) + break; + } - if (!re || !zebra_rib_labeled_unicast (re)) - return 0; + if (!re || !zebra_rib_labeled_unicast(re)) + return 0; - if (lsp_install (zvrf, fec->label, rn, re)) - return -1; + if (lsp_install(zvrf, fec->label, rn, re)) + return -1; - return 0; + return 0; } /* * Inform about FEC to a registered client. */ -static int -fec_send (zebra_fec_t *fec, struct zserv *client) +static int fec_send(zebra_fec_t *fec, struct zserv *client) { - struct stream *s; - struct route_node *rn; + struct stream *s; + struct route_node *rn; - rn = fec->rn; + rn = fec->rn; - /* Get output stream. */ - s = client->obuf; - stream_reset (s); + /* Get output stream. */ + s = client->obuf; + stream_reset(s); - zserv_create_header (s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); + zserv_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); - stream_putw(s, rn->p.family); - stream_put_prefix (s, &rn->p); - stream_putl(s, fec->label); - stream_putw_at(s, 0, stream_get_endp(s)); - return zebra_server_send_message(client); + stream_putw(s, rn->p.family); + stream_put_prefix(s, &rn->p); + stream_putl(s, fec->label); + stream_putw_at(s, 0, stream_get_endp(s)); + return zebra_server_send_message(client); } /* * Update all registered clients about this FEC. Caller should've updated * FEC and ensure no duplicate updates. */ -static void -fec_update_clients (zebra_fec_t *fec) +static void fec_update_clients(zebra_fec_t *fec) { - struct listnode *node; - struct zserv *client; + struct listnode *node; + struct zserv *client; - for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Update client %s", zebra_route_string(client->proto)); - fec_send(fec, client); - } + for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Update client %s", + zebra_route_string(client->proto)); + fec_send(fec, client); + } } /* * Print a FEC-label binding entry. */ -static void -fec_print (zebra_fec_t *fec, struct vty *vty) -{ - struct route_node *rn; - struct listnode *node; - struct zserv *client; - char buf[BUFSIZ]; - - rn = fec->rn; - prefix2str(&rn->p, buf, BUFSIZ); - vty_out (vty, "%s\n", buf); - vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ)); - if (fec->label_index != MPLS_INVALID_LABEL_INDEX) - vty_out(vty, ", Label Index: %u", fec->label_index); - vty_out (vty, "\n"); - if (!list_isempty(fec->client_list)) - { - vty_out(vty, " Client list:"); - for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) - vty_out(vty, " %s(fd %d)", - zebra_route_string(client->proto), client->sock); - vty_out (vty, "\n"); - } +static void fec_print(zebra_fec_t *fec, struct vty *vty) +{ + struct route_node *rn; + struct listnode *node; + struct zserv *client; + char buf[BUFSIZ]; + + rn = fec->rn; + prefix2str(&rn->p, buf, BUFSIZ); + vty_out(vty, "%s\n", buf); + vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ)); + if (fec->label_index != MPLS_INVALID_LABEL_INDEX) + vty_out(vty, ", Label Index: %u", fec->label_index); + vty_out(vty, "\n"); + if (!list_isempty(fec->client_list)) { + vty_out(vty, " Client list:"); + for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) + vty_out(vty, " %s(fd %d)", + zebra_route_string(client->proto), + client->sock); + vty_out(vty, "\n"); + } } /* * Locate FEC-label binding that matches with passed info. */ -static zebra_fec_t * -fec_find (struct route_table *table, struct prefix *p) +static zebra_fec_t *fec_find(struct route_table *table, struct prefix *p) { - struct route_node *rn; + struct route_node *rn; - apply_mask (p); - rn = route_node_lookup(table, p); - if (!rn) - return NULL; + apply_mask(p); + rn = route_node_lookup(table, p); + if (!rn) + return NULL; - route_unlock_node(rn); - return (rn->info); + route_unlock_node(rn); + return (rn->info); } /* * Add a FEC. This may be upon a client registering for a binding * or when a binding is configured. */ -static zebra_fec_t * -fec_add (struct route_table *table, struct prefix *p, - mpls_label_t label, u_int32_t flags, u_int32_t label_index) +static zebra_fec_t *fec_add(struct route_table *table, struct prefix *p, + mpls_label_t label, u_int32_t flags, + u_int32_t label_index) { - struct route_node *rn; - zebra_fec_t *fec; + struct route_node *rn; + zebra_fec_t *fec; - apply_mask (p); + apply_mask(p); - /* Lookup (or add) route node.*/ - rn = route_node_get (table, p); - if (!rn) - return NULL; + /* Lookup (or add) route node.*/ + rn = route_node_get(table, p); + if (!rn) + return NULL; - fec = rn->info; + fec = rn->info; - if (!fec) - { - fec = XCALLOC (MTYPE_FEC, sizeof(zebra_fec_t)); - if (!fec) - return NULL; + if (!fec) { + fec = XCALLOC(MTYPE_FEC, sizeof(zebra_fec_t)); + if (!fec) + return NULL; - rn->info = fec; - fec->rn = rn; - fec->label = label; - fec->client_list = list_new(); - } - else - route_unlock_node (rn); /* for the route_node_get */ + rn->info = fec; + fec->rn = rn; + fec->label = label; + fec->client_list = list_new(); + } else + route_unlock_node(rn); /* for the route_node_get */ - fec->label_index = label_index; - fec->flags = flags; + fec->label_index = label_index; + fec->flags = flags; - return fec; + return fec; } /* @@ -607,37 +553,34 @@ fec_add (struct route_table *table, struct prefix *p, * a FEC and no binding exists or when the binding is deleted and there * are no registered clients. */ -static int -fec_del (zebra_fec_t *fec) +static int fec_del(zebra_fec_t *fec) { - list_free (fec->client_list); - fec->rn->info = NULL; - route_unlock_node (fec->rn); - XFREE (MTYPE_FEC, fec); - return 0; + list_free(fec->client_list); + fec->rn->info = NULL; + route_unlock_node(fec->rn); + XFREE(MTYPE_FEC, fec); + return 0; } /* * Hash function for label. */ -static unsigned int -label_hash (void *p) +static unsigned int label_hash(void *p) { - const zebra_ile_t *ile = p; + const zebra_ile_t *ile = p; - return (jhash_1word(ile->in_label, 0)); + return (jhash_1word(ile->in_label, 0)); } /* * Compare 2 LSP hash entries based on in-label. */ -static int -label_cmp (const void *p1, const void *p2) +static int label_cmp(const void *p1, const void *p2) { - const zebra_ile_t *ile1 = p1; - const zebra_ile_t *ile2 = p2; + const zebra_ile_t *ile1 = p1; + const zebra_ile_t *ile2 = p2; - return (ile1->in_label == ile2->in_label); + return (ile1->in_label == ile2->in_label); } /* @@ -645,50 +588,49 @@ label_cmp (const void *p1, const void *p2) * the passed flag. * NOTE: Looking only for connected routes right now. */ -static int -nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop) +static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe, + struct nexthop *nexthop) { - struct route_table *table; - struct prefix_ipv4 p; - struct route_node *rn; - struct route_entry *match; - struct nexthop *match_nh; - - table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); - if (!table) - return 0; + struct route_table *table; + struct prefix_ipv4 p; + struct route_node *rn; + struct route_entry *match; + struct nexthop *match_nh; - /* Lookup nexthop in IPv4 routing table. */ - memset (&p, 0, sizeof (struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = nexthop->gate.ipv4; + table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT); + if (!table) + return 0; - rn = route_node_match (table, (struct prefix *) &p); - if (!rn) - return 0; + /* Lookup nexthop in IPv4 routing table. */ + memset(&p, 0, sizeof(struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = nexthop->gate.ipv4; - route_unlock_node (rn); + rn = route_node_match(table, (struct prefix *)&p); + if (!rn) + return 0; - /* Locate a valid connected route. */ - RNODE_FOREACH_RE (rn, match) - { - if (CHECK_FLAG (match->status, ROUTE_ENTRY_REMOVED) || - !CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - continue; + route_unlock_node(rn); - for (match_nh = match->nexthop; match_nh; match_nh = match_nh->next) + /* Locate a valid connected route. */ + RNODE_FOREACH_RE(rn, match) { - if (match->type == ZEBRA_ROUTE_CONNECT || - nexthop->ifindex == match_nh->ifindex) - { - nexthop->ifindex = match_nh->ifindex; - return 1; - } + if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED) + || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) + continue; + + for (match_nh = match->nexthop; match_nh; + match_nh = match_nh->next) { + if (match->type == ZEBRA_ROUTE_CONNECT + || nexthop->ifindex == match_nh->ifindex) { + nexthop->ifindex = match_nh->ifindex; + return 1; + } + } } - } - return 0; + return 0; } @@ -697,44 +639,44 @@ nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop) * the passed flag. * NOTE: Looking only for connected routes right now. */ -static int -nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop) +static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, + struct nexthop *nexthop) { - struct route_table *table; - struct prefix_ipv6 p; - struct route_node *rn; - struct route_entry *match; + struct route_table *table; + struct prefix_ipv6 p; + struct route_node *rn; + struct route_entry *match; - table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); - if (!table) - return 0; + table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT); + if (!table) + return 0; - /* Lookup nexthop in IPv6 routing table. */ - memset (&p, 0, sizeof (struct prefix_ipv6)); - p.family = AF_INET6; - p.prefixlen = IPV6_MAX_PREFIXLEN; - p.prefix = nexthop->gate.ipv6; + /* Lookup nexthop in IPv6 routing table. */ + memset(&p, 0, sizeof(struct prefix_ipv6)); + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + p.prefix = nexthop->gate.ipv6; - rn = route_node_match (table, (struct prefix *) &p); - if (!rn) - return 0; + rn = route_node_match(table, (struct prefix *)&p); + if (!rn) + return 0; - route_unlock_node (rn); + route_unlock_node(rn); - /* Locate a valid connected route. */ - RNODE_FOREACH_RE (rn, match) - { - if ((match->type == ZEBRA_ROUTE_CONNECT) && - !CHECK_FLAG (match->status, ROUTE_ENTRY_REMOVED) && - CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; - } + /* Locate a valid connected route. */ + RNODE_FOREACH_RE(rn, match) + { + if ((match->type == ZEBRA_ROUTE_CONNECT) + && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED) + && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) + break; + } - if (!match || !match->nexthop) - return 0; + if (!match || !match->nexthop) + return 0; - nexthop->ifindex = match->nexthop->ifindex; - return 1; + nexthop->ifindex = match->nexthop->ifindex; + return 1; } @@ -743,57 +685,52 @@ nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop) * or not. * NOTE: Each NHLFE points to only 1 nexthop. */ -static int -nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe) -{ - struct nexthop *nexthop; - struct interface *ifp; - - nexthop = nhlfe->nexthop; - if (!nexthop) // unexpected - return 0; - - /* Check on nexthop based on type. */ - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nhlfe_nexthop_active_ipv4 (nhlfe, nexthop)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - break; - - case NEXTHOP_TYPE_IPV6: - if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - break; - - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) - { - ifp = if_lookup_by_index (nexthop->ifindex, VRF_DEFAULT); - if (ifp && if_is_operative(ifp)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - } - else - { - if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - } - break; - - default: - break; - } - - return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); +static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe) +{ + struct nexthop *nexthop; + struct interface *ifp; + + nexthop = nhlfe->nexthop; + if (!nexthop) // unexpected + return 0; + + /* Check on nexthop based on type. */ + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + + case NEXTHOP_TYPE_IPV6: + if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) { + ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT); + if (ifp && if_is_operative(ifp)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } else { + if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; + + default: + break; + } + + return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } /* @@ -802,783 +739,739 @@ nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe) * marked. This is invoked when an LSP scheduled for processing (due * to some change) is examined. */ -static void -lsp_select_best_nhlfe (zebra_lsp_t *lsp) -{ - zebra_nhlfe_t *nhlfe; - zebra_nhlfe_t *best; - struct nexthop *nexthop; - int changed = 0; - - if (!lsp) - return; - - best = NULL; - lsp->num_ecmp = 0; - UNSET_FLAG (lsp->flags, LSP_FLAG_CHANGED); - - /* - * First compute the best path, after checking nexthop status. We are only - * concerned with non-deleted NHLFEs. - */ - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - /* Clear selection flags. */ - UNSET_FLAG (nhlfe->flags, - (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH)); - - if (!CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED) && - nhlfe_nexthop_active (nhlfe)) - { - if (!best || (nhlfe->distance < best->distance)) - best = nhlfe; - } - } - - lsp->best_nhlfe = best; - if (!lsp->best_nhlfe) - return; - - /* Mark best NHLFE as selected. */ - SET_FLAG (lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED); - - /* - * If best path exists, see if there is ECMP. While doing this, note if a - * 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) - { - int nh_chg, nh_sel, nh_inst; - - nexthop = nhlfe->nexthop; - if (!nexthop) // unexpected - continue; - - if (!CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) && - (nhlfe->distance == lsp->best_nhlfe->distance)) - { - SET_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED); - SET_FLAG (nhlfe->flags, NHLFE_FLAG_MULTIPATH); - lsp->num_ecmp++; - } - - if (CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED) && - !changed) - { - nh_chg = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED); - nh_sel = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED); - nh_inst = CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED); - - if ((nh_sel && !nh_inst) || - (nh_sel && nh_inst && nh_chg) || - (nh_inst && !nh_sel)) - changed = 1; - } - - /* We have finished examining, clear changed flag. */ - UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED); - } - - if (changed) - SET_FLAG (lsp->flags, LSP_FLAG_CHANGED); +static void lsp_select_best_nhlfe(zebra_lsp_t *lsp) +{ + zebra_nhlfe_t *nhlfe; + zebra_nhlfe_t *best; + struct nexthop *nexthop; + int changed = 0; + + if (!lsp) + return; + + best = NULL; + lsp->num_ecmp = 0; + UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED); + + /* + * First compute the best path, after checking nexthop status. We are + * only + * concerned with non-deleted NHLFEs. + */ + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + /* Clear selection flags. */ + UNSET_FLAG(nhlfe->flags, + (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH)); + + if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED) + && nhlfe_nexthop_active(nhlfe)) { + if (!best || (nhlfe->distance < best->distance)) + best = nhlfe; + } + } + + lsp->best_nhlfe = best; + if (!lsp->best_nhlfe) + return; + + /* Mark best NHLFE as selected. */ + SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED); + + /* + * If best path exists, see if there is ECMP. While doing this, note if + * a + * 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) { + int nh_chg, nh_sel, nh_inst; + + nexthop = nhlfe->nexthop; + if (!nexthop) // unexpected + continue; + + if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED) + && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) + && (nhlfe->distance == lsp->best_nhlfe->distance)) { + SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED); + SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH); + lsp->num_ecmp++; + } + + if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) { + nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED); + nh_inst = + CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED); + + if ((nh_sel && !nh_inst) + || (nh_sel && nh_inst && nh_chg) + || (nh_inst && !nh_sel)) + changed = 1; + } + + /* We have finished examining, clear changed flag. */ + UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + } + + if (changed) + SET_FLAG(lsp->flags, LSP_FLAG_CHANGED); } /* * Delete LSP forwarding entry from kernel, if installed. Called upon * process exit. */ -static void -lsp_uninstall_from_kernel (struct hash_backet *backet, void *ctxt) +static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt) { - zebra_lsp_t *lsp; + zebra_lsp_t *lsp; - lsp = (zebra_lsp_t *) backet->data; - if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) - kernel_del_lsp (lsp); + lsp = (zebra_lsp_t *)backet->data; + if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) + kernel_del_lsp(lsp); } /* * Schedule LSP forwarding entry for processing. Called upon changes * that may impact LSPs such as nexthop / connected route changes. */ -static void -lsp_schedule (struct hash_backet *backet, void *ctxt) +static void lsp_schedule(struct hash_backet *backet, void *ctxt) { - zebra_lsp_t *lsp; + zebra_lsp_t *lsp; - lsp = (zebra_lsp_t *) backet->data; - lsp_processq_add (lsp); + lsp = (zebra_lsp_t *)backet->data; + lsp_processq_add(lsp); } /* * Process a LSP entry that is in the queue. Recalculate best NHLFE and * any multipaths and update or delete from the kernel, as needed. */ -static wq_item_status -lsp_process (struct work_queue *wq, void *data) -{ - zebra_lsp_t *lsp; - zebra_nhlfe_t *oldbest, *newbest; - char buf[BUFSIZ], buf2[BUFSIZ]; - struct zebra_vrf *zvrf = vrf_info_lookup (VRF_DEFAULT); - - lsp = (zebra_lsp_t *)data; - if (!lsp) // unexpected - return WQ_SUCCESS; - - oldbest = lsp->best_nhlfe; - - /* Select best NHLFE(s) */ - lsp_select_best_nhlfe (lsp); - - newbest = lsp->best_nhlfe; - - if (IS_ZEBRA_DEBUG_MPLS) - { - if (oldbest) - nhlfe2str (oldbest, buf, BUFSIZ); - if (newbest) - nhlfe2str (newbest, buf2, BUFSIZ); - zlog_debug ("Process LSP in-label %u oldbest %s newbest %s " - "flags 0x%x ecmp# %d", - lsp->ile.in_label, oldbest ? buf : "NULL", - newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp); - } - - if (!CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED)) - { - /* Not already installed */ - if (newbest) - { - kernel_add_lsp (lsp); - zvrf->lsp_installs++; - } - } - else - { - /* Installed, may need an update and/or delete. */ - if (!newbest) - { - kernel_del_lsp (lsp); - zvrf->lsp_removals++; - } - else if (CHECK_FLAG (lsp->flags, LSP_FLAG_CHANGED)) - { - kernel_upd_lsp (lsp); - zvrf->lsp_installs++; - } - } - - return WQ_SUCCESS; +static wq_item_status lsp_process(struct work_queue *wq, void *data) +{ + zebra_lsp_t *lsp; + zebra_nhlfe_t *oldbest, *newbest; + char buf[BUFSIZ], buf2[BUFSIZ]; + struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT); + + lsp = (zebra_lsp_t *)data; + if (!lsp) // unexpected + return WQ_SUCCESS; + + oldbest = lsp->best_nhlfe; + + /* Select best NHLFE(s) */ + lsp_select_best_nhlfe(lsp); + + newbest = lsp->best_nhlfe; + + if (IS_ZEBRA_DEBUG_MPLS) { + if (oldbest) + nhlfe2str(oldbest, buf, BUFSIZ); + if (newbest) + nhlfe2str(newbest, buf2, BUFSIZ); + zlog_debug( + "Process LSP in-label %u oldbest %s newbest %s " + "flags 0x%x ecmp# %d", + lsp->ile.in_label, oldbest ? buf : "NULL", + newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp); + } + + if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) { + /* Not already installed */ + if (newbest) { + kernel_add_lsp(lsp); + zvrf->lsp_installs++; + } + } else { + /* Installed, may need an update and/or delete. */ + if (!newbest) { + kernel_del_lsp(lsp); + zvrf->lsp_removals++; + } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) { + kernel_upd_lsp(lsp); + zvrf->lsp_installs++; + } + } + + return WQ_SUCCESS; } /* * Callback upon processing completion of a LSP forwarding entry. */ -static void -lsp_processq_del (struct work_queue *wq, void *data) +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; + struct zebra_vrf *zvrf; + zebra_lsp_t *lsp; + struct hash *lsp_table; + zebra_nhlfe_t *nhlfe, *nhlfe_next; - zvrf = vrf_info_lookup(VRF_DEFAULT); - assert (zvrf); + zvrf = vrf_info_lookup(VRF_DEFAULT); + assert(zvrf); - lsp_table = zvrf->lsp_table; - if (!lsp_table) // unexpected - return; + lsp_table = zvrf->lsp_table; + if (!lsp_table) // unexpected + return; - lsp = (zebra_lsp_t *)data; - if (!lsp) // unexpected - return; + lsp = (zebra_lsp_t *)data; + if (!lsp) // unexpected + return; - /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs exist, - * delete LSP entry also. - */ - UNSET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED); + /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs + * exist, + * delete LSP entry also. + */ + UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED); - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) - { - nhlfe_next = nhlfe->next; - if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)) - nhlfe_del (nhlfe); - } + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next) { + nhlfe_next = nhlfe->next; + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)) + nhlfe_del(nhlfe); + } - if (!lsp->nhlfe_list) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Free LSP in-label %u flags 0x%x", - lsp->ile.in_label, lsp->flags); + if (!lsp->nhlfe_list) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Free LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); - lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); - } + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } } /* * Callback upon finishing the processing of all scheduled * LSP forwarding entries. */ -static void -lsp_processq_complete (struct work_queue *wq) +static void lsp_processq_complete(struct work_queue *wq) { - /* Nothing to do for now. */ + /* Nothing to do for now. */ } /* * Add LSP forwarding entry to queue for subsequent processing. */ -static int -lsp_processq_add (zebra_lsp_t *lsp) +static int lsp_processq_add(zebra_lsp_t *lsp) { - /* If already scheduled, exit. */ - if (CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED)) - return 0; + /* If already scheduled, exit. */ + if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) + return 0; - if (zebrad.lsp_process_q == NULL) - { - zlog_err ("%s: work_queue does not exist!", __func__); - return -1; - } + if (zebrad.lsp_process_q == NULL) { + zlog_err("%s: work_queue does not exist!", __func__); + return -1; + } - work_queue_add (zebrad.lsp_process_q, lsp); - SET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED); - return 0; + work_queue_add(zebrad.lsp_process_q, lsp); + SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED); + return 0; } /* * Callback to allocate LSP forwarding table entry. */ -static void * -lsp_alloc (void *p) +static void *lsp_alloc(void *p) { - const zebra_ile_t *ile = p; - zebra_lsp_t *lsp; + const zebra_ile_t *ile = p; + zebra_lsp_t *lsp; - lsp = XCALLOC (MTYPE_LSP, sizeof(zebra_lsp_t)); - lsp->ile = *ile; + lsp = XCALLOC(MTYPE_LSP, sizeof(zebra_lsp_t)); + lsp->ile = *ile; - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Alloc LSP in-label %u", lsp->ile.in_label); + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label); - return ((void *)lsp); + return ((void *)lsp); } /* * Create printable string for NHLFE entry. */ -static char * -nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size) +static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size) { - struct nexthop *nexthop; + struct nexthop *nexthop; - buf[0] = '\0'; - nexthop = nhlfe->nexthop; - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, size); - break; - case NEXTHOP_TYPE_IPV6: - inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, size); - break; - default: - break; - } + buf[0] = '\0'; + nexthop = nhlfe->nexthop; + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size); + break; + case NEXTHOP_TYPE_IPV6: + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size); + break; + default: + break; + } - return buf; + return buf; } /* * Check if NHLFE matches with search info passed. */ -static int -nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) +static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex) { - struct nexthop *nhop; - int cmp = 1; + struct nexthop *nhop; + int cmp = 1; - nhop = nhlfe->nexthop; - if (!nhop) - return 1; + nhop = nhlfe->nexthop; + if (!nhop) + return 1; - if (nhop->type != gtype) - return 1; + if (nhop->type != gtype) + return 1; - switch (nhop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4), - sizeof(struct in_addr)); - if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - cmp = !(nhop->ifindex == ifindex); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6), - sizeof(struct in6_addr)); - if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX) - cmp = !(nhop->ifindex == ifindex); - break; - default: - break; - } + switch (nhop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4), + sizeof(struct in_addr)); + if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + cmp = !(nhop->ifindex == ifindex); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6), + sizeof(struct in6_addr)); + if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX) + cmp = !(nhop->ifindex == ifindex); + break; + default: + break; + } - return cmp; + return cmp; } /* * Locate NHLFE that matches with passed info. */ -static zebra_nhlfe_t * -nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex) +static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex) { - zebra_nhlfe_t *nhlfe; + zebra_nhlfe_t *nhlfe; - if (!lsp) - return NULL; + if (!lsp) + return NULL; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - if (nhlfe->type != lsp_type) - continue; - if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex)) - break; - } + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + if (nhlfe->type != lsp_type) + continue; + if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex)) + break; + } - return nhlfe; + return nhlfe; } /* * 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, union g_addr *gate, - ifindex_t ifindex, mpls_label_t out_label) -{ - zebra_nhlfe_t *nhlfe; - struct nexthop *nexthop; - - if (!lsp) - return NULL; - - nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t)); - if (!nhlfe) - return NULL; - - nhlfe->lsp = lsp; - nhlfe->type = lsp_type; - nhlfe->distance = lsp_distance (lsp_type); - - nexthop = nexthop_new(); - if (!nexthop) - { - XFREE (MTYPE_NHLFE, nhlfe); - return NULL; - } - nexthop_add_labels (nexthop, lsp_type, 1, &out_label); - - nexthop->type = gtype; - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - nexthop->gate.ipv4 = gate->ipv4; - if (ifindex) - nexthop->ifindex = ifindex; - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - nexthop->gate.ipv6 = gate->ipv6; - if (ifindex) - nexthop->ifindex = ifindex; - break; - default: - nexthop_free(nexthop); - XFREE (MTYPE_NHLFE, nhlfe); - return NULL; - break; - } - - nhlfe->nexthop = nexthop; - if (lsp->nhlfe_list) - lsp->nhlfe_list->prev = nhlfe; - nhlfe->next = lsp->nhlfe_list; - lsp->nhlfe_list = nhlfe; - - return nhlfe; +static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex, mpls_label_t out_label) +{ + zebra_nhlfe_t *nhlfe; + struct nexthop *nexthop; + + if (!lsp) + return NULL; + + nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t)); + if (!nhlfe) + return NULL; + + nhlfe->lsp = lsp; + nhlfe->type = lsp_type; + nhlfe->distance = lsp_distance(lsp_type); + + nexthop = nexthop_new(); + if (!nexthop) { + XFREE(MTYPE_NHLFE, nhlfe); + return NULL; + } + nexthop_add_labels(nexthop, lsp_type, 1, &out_label); + + nexthop->type = gtype; + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + nexthop->gate.ipv4 = gate->ipv4; + if (ifindex) + nexthop->ifindex = ifindex; + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + nexthop->gate.ipv6 = gate->ipv6; + if (ifindex) + nexthop->ifindex = ifindex; + break; + default: + nexthop_free(nexthop); + XFREE(MTYPE_NHLFE, nhlfe); + return NULL; + break; + } + + 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. */ -static int -nhlfe_del (zebra_nhlfe_t *nhlfe) +static int nhlfe_del(zebra_nhlfe_t *nhlfe) { - zebra_lsp_t *lsp; + zebra_lsp_t *lsp; - if (!nhlfe) - return -1; + if (!nhlfe) + return -1; - lsp = nhlfe->lsp; - if (!lsp) - return -1; + lsp = nhlfe->lsp; + if (!lsp) + return -1; - /* Free nexthop. */ - if (nhlfe->nexthop) - nexthop_free(nhlfe->nexthop); + /* Free nexthop. */ + if (nhlfe->nexthop) + nexthop_free(nhlfe->nexthop); - /* Unlink from LSP */ - if (nhlfe->next) - nhlfe->next->prev = nhlfe->prev; - if (nhlfe->prev) - nhlfe->prev->next = nhlfe->next; - else - lsp->nhlfe_list = nhlfe->next; + /* Unlink from LSP */ + if (nhlfe->next) + nhlfe->next->prev = nhlfe->prev; + if (nhlfe->prev) + nhlfe->prev->next = nhlfe->next; + else + lsp->nhlfe_list = nhlfe->next; - if (nhlfe == lsp->best_nhlfe) - lsp->best_nhlfe = NULL; + if (nhlfe == lsp->best_nhlfe) + lsp->best_nhlfe = NULL; - XFREE (MTYPE_NHLFE, nhlfe); + XFREE(MTYPE_NHLFE, nhlfe); - return 0; + return 0; } /* * Update label for NHLFE entry. */ -static void -nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label) -{ - nhlfe->nexthop->nh_label->label[0] = nh_label->label[0]; -} - -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; - 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; - - /* Skip non-static NHLFEs */ - if (nhlfe->type != type) - continue; - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("Del 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)) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Free LSP in-label %u flags 0x%x", - lsp->ile.in_label, lsp->flags); - - lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); - } - - return 0; +static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, + struct nexthop_label *nh_label) +{ + nhlfe->nexthop->nh_label->label[0] = nh_label->label[0]; +} + +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; + 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; + + /* Skip non-static NHLFEs */ + if (nhlfe->type != type) + continue; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "Del 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)) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Free LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); + + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } + + return 0; } /* * Uninstall all static NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -static int -mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label) +static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf, + mpls_label_t in_label) { - struct hash *lsp_table; - zebra_ile_t tmp_ile; - zebra_lsp_t *lsp; + struct hash *lsp_table; + zebra_ile_t tmp_ile; + zebra_lsp_t *lsp; - /* Lookup table. */ - lsp_table = zvrf->lsp_table; - if (!lsp_table) - return -1; + /* 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 || !lsp->nhlfe_list) - return 0; + /* If entry is not present, exit. */ + tmp_ile.in_label = in_label; + lsp = hash_lookup(lsp_table, &tmp_ile); + if (!lsp || !lsp->nhlfe_list) + return 0; - return mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_STATIC); + return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC); } -static json_object * -nhlfe_json (zebra_nhlfe_t *nhlfe) +static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe) { - char buf[BUFSIZ]; - json_object *json_nhlfe = NULL; - struct nexthop *nexthop = nhlfe->nexthop; + char buf[BUFSIZ]; + json_object *json_nhlfe = NULL; + struct nexthop *nexthop = nhlfe->nexthop; - json_nhlfe = json_object_new_object(); - json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type)); - json_object_int_add(json_nhlfe, "outLabel", nexthop->nh_label->label[0]); - json_object_int_add(json_nhlfe, "distance", nhlfe->distance); + json_nhlfe = json_object_new_object(); + json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type)); + json_object_int_add(json_nhlfe, "outLabel", + nexthop->nh_label->label[0]); + json_object_int_add(json_nhlfe, "distance", nhlfe->distance); - if (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED)) - json_object_boolean_true_add(json_nhlfe, "installed"); + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) + json_object_boolean_true_add(json_nhlfe, "installed"); - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - json_object_string_add(json_nhlfe, "nexthop", - inet_ntoa (nexthop->gate.ipv4)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - json_object_string_add(json_nhlfe, "nexthop", - inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); - - if (nexthop->ifindex) - json_object_string_add(json_nhlfe, "interface", ifindex2ifname (nexthop->ifindex, VRF_DEFAULT)); - break; - default: - break; - } - return json_nhlfe; + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + json_object_string_add(json_nhlfe, "nexthop", + inet_ntoa(nexthop->gate.ipv4)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + json_object_string_add( + json_nhlfe, "nexthop", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + + if (nexthop->ifindex) + json_object_string_add( + json_nhlfe, "interface", + ifindex2ifname(nexthop->ifindex, VRF_DEFAULT)); + break; + default: + break; + } + return json_nhlfe; } /* * Print the NHLFE for a LSP forwarding entry. */ -static void -nhlfe_print (zebra_nhlfe_t *nhlfe, struct vty *vty) -{ - struct nexthop *nexthop; - char buf[BUFSIZ]; - - nexthop = nhlfe->nexthop; - if (!nexthop || !nexthop->nh_label) // unexpected - return; - - vty_out (vty, " type: %s remote label: %s distance: %d\n", - nhlfe_type2str(nhlfe->type), - label2str(nexthop->nh_label->label[0], buf, BUFSIZ), - nhlfe->distance); - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); - if (nexthop->ifindex) - vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex, VRF_DEFAULT)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out (vty, " via %s", - inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); - if (nexthop->ifindex) - vty_out (vty, " dev %s", ifindex2ifname (nexthop->ifindex, VRF_DEFAULT)); - break; - default: - break; - } - vty_out(vty, "%s", CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) ? - " (installed)" : ""); - vty_out (vty, "\n"); +static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty) +{ + struct nexthop *nexthop; + char buf[BUFSIZ]; + + nexthop = nhlfe->nexthop; + if (!nexthop || !nexthop->nh_label) // unexpected + return; + + vty_out(vty, " type: %s remote label: %s distance: %d\n", + nhlfe_type2str(nhlfe->type), + label2str(nexthop->nh_label->label[0], buf, BUFSIZ), + nhlfe->distance); + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out(vty, " dev %s", + ifindex2ifname(nexthop->ifindex, VRF_DEFAULT)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " via %s", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + if (nexthop->ifindex) + vty_out(vty, " dev %s", + ifindex2ifname(nexthop->ifindex, VRF_DEFAULT)); + break; + default: + break; + } + vty_out(vty, "%s", + CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)" + : ""); + vty_out(vty, "\n"); } /* * Print an LSP forwarding entry. */ -static void -lsp_print (zebra_lsp_t *lsp, void *ctxt) +static void lsp_print(zebra_lsp_t *lsp, void *ctxt) { - zebra_nhlfe_t *nhlfe; - struct vty *vty; + zebra_nhlfe_t *nhlfe; + struct vty *vty; - vty = (struct vty *) ctxt; + vty = (struct vty *)ctxt; - vty_out (vty, "Local label: %u%s\n", - lsp->ile.in_label, - CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)" : ""); + 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) - nhlfe_print (nhlfe, vty); + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) + nhlfe_print(nhlfe, vty); } /* * JSON objects for an LSP forwarding entry. */ -static json_object * -lsp_json (zebra_lsp_t *lsp) +static json_object *lsp_json(zebra_lsp_t *lsp) { - zebra_nhlfe_t *nhlfe = NULL; - json_object *json = json_object_new_object(); - json_object *json_nhlfe_list = json_object_new_array(); + zebra_nhlfe_t *nhlfe = NULL; + json_object *json = json_object_new_object(); + json_object *json_nhlfe_list = json_object_new_array(); - json_object_int_add(json, "inLabel", lsp->ile.in_label); + json_object_int_add(json, "inLabel", lsp->ile.in_label); - if (CHECK_FLAG (lsp->flags, LSP_FLAG_INSTALLED)) - json_object_boolean_true_add(json, "installed"); + if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) + json_object_boolean_true_add(json, "installed"); - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe)); + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) + json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe)); - json_object_object_add(json, "nexthops", json_nhlfe_list); - return json; + json_object_object_add(json, "nexthops", json_nhlfe_list); + return json; } /* Return a sorted linked list of the hash contents */ -static struct list * -hash_get_sorted_list (struct hash *hash, void *cmp) +static struct list *hash_get_sorted_list(struct hash *hash, void *cmp) { - unsigned int i; - struct hash_backet *hb; - struct list *sorted_list = list_new(); + unsigned int i; + struct hash_backet *hb; + struct list *sorted_list = list_new(); - sorted_list->cmp = (int (*)(void *, void *)) cmp; + sorted_list->cmp = (int (*)(void *, void *))cmp; - for (i = 0; i < hash->size; i++) - for (hb = hash->index[i]; hb; hb = hb->next) - listnode_add_sort(sorted_list, hb->data); + for (i = 0; i < hash->size; i++) + for (hb = hash->index[i]; hb; hb = hb->next) + listnode_add_sort(sorted_list, hb->data); - return sorted_list; + return sorted_list; } /* * Compare two LSPs based on their label values. */ -static int -lsp_cmp (zebra_lsp_t *lsp1, zebra_lsp_t *lsp2) +static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2) { - if (lsp1->ile.in_label < lsp2->ile.in_label) - return -1; + if (lsp1->ile.in_label < lsp2->ile.in_label) + return -1; - if (lsp1->ile.in_label > lsp2->ile.in_label) - return 1; + if (lsp1->ile.in_label > lsp2->ile.in_label) + return 1; - return 0; + return 0; } /* * Callback to allocate static LSP. */ -static void * -slsp_alloc (void *p) +static void *slsp_alloc(void *p) { - const zebra_ile_t *ile = p; - zebra_slsp_t *slsp; + const zebra_ile_t *ile = p; + zebra_slsp_t *slsp; - slsp = XCALLOC (MTYPE_SLSP, sizeof(zebra_slsp_t)); - slsp->ile = *ile; - return ((void *)slsp); + slsp = XCALLOC(MTYPE_SLSP, sizeof(zebra_slsp_t)); + slsp->ile = *ile; + return ((void *)slsp); } /* * Compare two static LSPs based on their label values. */ -static int -slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2) +static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2) { - if (slsp1->ile.in_label < slsp2->ile.in_label) - return -1; + if (slsp1->ile.in_label < slsp2->ile.in_label) + return -1; - if (slsp1->ile.in_label > slsp2->ile.in_label) - return 1; + if (slsp1->ile.in_label > slsp2->ile.in_label) + return 1; - return 0; + return 0; } /* * Check if static NHLFE matches with search info passed. */ -static int -snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) +static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex) { - int cmp = 1; + int cmp = 1; - if (snhlfe->gtype != gtype) - return 1; + if (snhlfe->gtype != gtype) + return 1; - switch (snhlfe->gtype) - { - case NEXTHOP_TYPE_IPV4: - cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4), - sizeof(struct in_addr)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6), - sizeof(struct in6_addr)); - if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX) - cmp = !(snhlfe->ifindex == ifindex); - break; - default: - break; - } + switch (snhlfe->gtype) { + case NEXTHOP_TYPE_IPV4: + cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4), + sizeof(struct in_addr)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6), + sizeof(struct in6_addr)); + if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX) + cmp = !(snhlfe->ifindex == ifindex); + break; + default: + break; + } - return cmp; + return cmp; } /* * Locate static NHLFE that matches with passed info. */ -static zebra_snhlfe_t * -snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) +static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp, + enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex) { - zebra_snhlfe_t *snhlfe; + zebra_snhlfe_t *snhlfe; - if (!slsp) - return NULL; + if (!slsp) + return NULL; - for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) - { - if (!snhlfe_match (snhlfe, gtype, gate, ifindex)) - break; - } + for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) { + if (!snhlfe_match(snhlfe, gtype, gate, ifindex)) + break; + } - return snhlfe; + return snhlfe; } @@ -1586,144 +1479,136 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, * Add static NHLFE. Base LSP config entry must have been created * and duplicate check done. */ -static zebra_snhlfe_t * -snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, - mpls_label_t out_label) -{ - zebra_snhlfe_t *snhlfe; - - if (!slsp) - return NULL; - - snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t)); - snhlfe->slsp = slsp; - snhlfe->out_label = out_label; - snhlfe->gtype = gtype; - switch (gtype) - { - case NEXTHOP_TYPE_IPV4: - snhlfe->gate.ipv4 = gate->ipv4; - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - snhlfe->gate.ipv6 = gate->ipv6; - if (ifindex) - snhlfe->ifindex = ifindex; - break; - default: - XFREE (MTYPE_SNHLFE, snhlfe); - return NULL; - } - - if (slsp->snhlfe_list) - slsp->snhlfe_list->prev = snhlfe; - snhlfe->next = slsp->snhlfe_list; - slsp->snhlfe_list = snhlfe; - - return snhlfe; +static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, + enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex, + mpls_label_t out_label) +{ + zebra_snhlfe_t *snhlfe; + + if (!slsp) + return NULL; + + snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t)); + snhlfe->slsp = slsp; + snhlfe->out_label = out_label; + snhlfe->gtype = gtype; + switch (gtype) { + case NEXTHOP_TYPE_IPV4: + snhlfe->gate.ipv4 = gate->ipv4; + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + snhlfe->gate.ipv6 = gate->ipv6; + if (ifindex) + snhlfe->ifindex = ifindex; + break; + default: + XFREE(MTYPE_SNHLFE, snhlfe); + return NULL; + } + + if (slsp->snhlfe_list) + slsp->snhlfe_list->prev = snhlfe; + snhlfe->next = slsp->snhlfe_list; + slsp->snhlfe_list = snhlfe; + + return snhlfe; } /* * Delete static NHLFE. Entry must be present on list. */ -static int -snhlfe_del (zebra_snhlfe_t *snhlfe) +static int snhlfe_del(zebra_snhlfe_t *snhlfe) { - zebra_slsp_t *slsp; + zebra_slsp_t *slsp; - if (!snhlfe) - return -1; + if (!snhlfe) + return -1; - slsp = snhlfe->slsp; - if (!slsp) - return -1; + slsp = snhlfe->slsp; + 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; + if (snhlfe->next) + snhlfe->next->prev = snhlfe->prev; + if (snhlfe->prev) + snhlfe->prev->next = snhlfe->next; + else + slsp->snhlfe_list = snhlfe->next; - snhlfe->prev = snhlfe->next = NULL; - if (snhlfe->ifname) - XFREE (MTYPE_SNHLFE_IFNAME, snhlfe->ifname); - XFREE (MTYPE_SNHLFE, snhlfe); + snhlfe->prev = snhlfe->next = NULL; + if (snhlfe->ifname) + XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname); + XFREE(MTYPE_SNHLFE, snhlfe); - return 0; + return 0; } /* * Delete all static NHLFE entries for this LSP (in label). */ -static int -snhlfe_del_all (zebra_slsp_t *slsp) +static int snhlfe_del_all(zebra_slsp_t *slsp) { - zebra_snhlfe_t *snhlfe, *snhlfe_next; + zebra_snhlfe_t *snhlfe, *snhlfe_next; - if (!slsp) - return -1; + if (!slsp) + return -1; - for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next) - { - snhlfe_next = snhlfe->next; - snhlfe_del (snhlfe); - } + for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next) { + snhlfe_next = snhlfe->next; + snhlfe_del(snhlfe); + } - return 0; + return 0; } /* * Create printable string for NHLFE configuration. */ -static char * -snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size) +static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size) { - buf[0] = '\0'; - switch (snhlfe->gtype) - { - case NEXTHOP_TYPE_IPV4: - inet_ntop (AF_INET, &snhlfe->gate.ipv4, buf, size); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size); - if (snhlfe->ifindex) - strcat (buf, ifindex2ifname (snhlfe->ifindex, VRF_DEFAULT)); - break; - default: - break; - } + buf[0] = '\0'; + switch (snhlfe->gtype) { + case NEXTHOP_TYPE_IPV4: + inet_ntop(AF_INET, &snhlfe->gate.ipv4, buf, size); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + inet_ntop(AF_INET6, &snhlfe->gate.ipv6, buf, size); + if (snhlfe->ifindex) + strcat(buf, + ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT)); + break; + default: + break; + } - return buf; + return buf; } /* * Initialize work queue for processing changed LSPs. */ -static int -mpls_processq_init (struct zebra_t *zebra) +static int mpls_processq_init(struct zebra_t *zebra) { - zebra->lsp_process_q = work_queue_new (zebra->master, "LSP processing"); - if (!zebra->lsp_process_q) - { - zlog_err ("%s: could not initialise work queue!", __func__); - return -1; - } + zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing"); + if (!zebra->lsp_process_q) { + zlog_err("%s: could not initialise work queue!", __func__); + return -1; + } - zebra->lsp_process_q->spec.workfunc = &lsp_process; - zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del; - zebra->lsp_process_q->spec.errorfunc = NULL; - zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete; - zebra->lsp_process_q->spec.max_retries = 0; - zebra->lsp_process_q->spec.hold = 10; + zebra->lsp_process_q->spec.workfunc = &lsp_process; + zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del; + zebra->lsp_process_q->spec.errorfunc = NULL; + zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete; + zebra->lsp_process_q->spec.max_retries = 0; + zebra->lsp_process_q->spec.hold = 10; - return 0; + return 0; } - /* Public functions */ /* @@ -1738,132 +1623,128 @@ mpls_processq_init (struct zebra_t *zebra) * -2 if a label was inside the reserved range (0-15) * -3 if the number of labels given exceeds MPLS_MAX_LABELS */ -int -mpls_str2label (const char *label_str, u_int8_t *num_labels, - mpls_label_t *labels) -{ - char *ostr; // copy of label string (start) - char *lstr; // copy of label string - char *nump; // pointer to next segment - char *endp; // end pointer - int i; // for iterating label_str - int rc; // return code - mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels - - /* labels to zero until we have a successful parse */ - ostr = lstr = XSTRDUP (MTYPE_TMP, label_str); - *num_labels = 0; - rc = 0; - - for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) - { - nump = strsep (&lstr, "/"); - pl[i] = strtoul(nump, &endp, 10); - - /* format check */ - if (*endp != '\0') - rc = -1; - /* validity check */ - else if (!IS_MPLS_UNRESERVED_LABEL(pl[i])) - rc = -2; - } +int mpls_str2label(const char *label_str, u_int8_t *num_labels, + mpls_label_t *labels) +{ + char *ostr; // copy of label string (start) + char *lstr; // copy of label string + char *nump; // pointer to next segment + char *endp; // end pointer + int i; // for iterating label_str + int rc; // return code + mpls_label_t pl[MPLS_MAX_LABELS]; // parsed labels + + /* labels to zero until we have a successful parse */ + ostr = lstr = XSTRDUP(MTYPE_TMP, label_str); + *num_labels = 0; + rc = 0; + + for (i = 0; i < MPLS_MAX_LABELS && lstr && !rc; i++) { + nump = strsep(&lstr, "/"); + pl[i] = strtoul(nump, &endp, 10); + + /* format check */ + if (*endp != '\0') + rc = -1; + /* validity check */ + else if (!IS_MPLS_UNRESERVED_LABEL(pl[i])) + rc = -2; + } - /* excess labels */ - if (!rc && i == MPLS_MAX_LABELS && lstr) - rc = -3; + /* excess labels */ + if (!rc && i == MPLS_MAX_LABELS && lstr) + rc = -3; - if (!rc) - { - *num_labels = i; - memcpy (labels, pl, *num_labels * sizeof (mpls_label_t)); - } + if (!rc) { + *num_labels = i; + memcpy(labels, pl, *num_labels * sizeof(mpls_label_t)); + } - XFREE (MTYPE_TMP, ostr); + XFREE(MTYPE_TMP, ostr); - return rc; + return rc; } /* * Label to string conversion, labels in string separated by '/'. */ -char * -mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, - char *buf, int len, int pretty) -{ - char *buf_ptr = buf; - buf[0] = '\0'; - - if (pretty) { - if (num_labels == 1) { - label2str(labels[0], buf, len); - } else if (num_labels == 2) { - label2str(labels[0], buf, len); - buf_ptr += strlen(buf); - - snprintf (buf_ptr, len, "/"); - buf_ptr++; - - label2str(labels[1], buf_ptr, len); - } - } else { - if (num_labels == 1) - snprintf (buf, len, "%u", labels[0]); - else if (num_labels == 2) - snprintf (buf, len, "%u/%u", labels[0], labels[1]); - } - return buf; +char *mpls_label2str(u_int8_t num_labels, mpls_label_t *labels, char *buf, + int len, int pretty) +{ + char *buf_ptr = buf; + buf[0] = '\0'; + + if (pretty) { + if (num_labels == 1) { + label2str(labels[0], buf, len); + } else if (num_labels == 2) { + label2str(labels[0], buf, len); + buf_ptr += strlen(buf); + + snprintf(buf_ptr, len, "/"); + buf_ptr++; + + label2str(labels[1], buf_ptr, len); + } + } else { + if (num_labels == 1) + snprintf(buf, len, "%u", labels[0]); + else if (num_labels == 2) + snprintf(buf, len, "%u/%u", labels[0], labels[1]); + } + return buf; } /* * Install dynamic LSP entry. */ -int -zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *re) +int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, + struct route_entry *re) { - struct route_table *table; - zebra_fec_t *fec; + struct route_table *table; + zebra_fec_t *fec; - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; - if (!table) - return -1; + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; + if (!table) + return -1; - /* See if there is a configured label binding for this FEC. */ - fec = fec_find (table, &rn->p); - if (!fec || fec->label == MPLS_INVALID_LABEL) - return 0; + /* See if there is a configured label binding for this FEC. */ + fec = fec_find(table, &rn->p); + if (!fec || fec->label == MPLS_INVALID_LABEL) + return 0; - /* We cannot install a label forwarding entry if local label is the - * implicit-null label. - */ - if (fec->label == MPLS_IMP_NULL_LABEL) - return 0; + /* We cannot install a label forwarding entry if local label is the + * implicit-null label. + */ + if (fec->label == MPLS_IMP_NULL_LABEL) + return 0; - if (lsp_install (zvrf, fec->label, rn, re)) - return -1; + if (lsp_install(zvrf, fec->label, rn, re)) + return -1; - return 0; + return 0; } /* * Uninstall dynamic LSP entry, if any. */ -int -zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *re) +int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn, + struct route_entry *re) { - struct route_table *table; - zebra_fec_t *fec; + struct route_table *table; + zebra_fec_t *fec; - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; - if (!table) - return -1; + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; + if (!table) + return -1; - /* See if there is a configured label binding for this FEC. */ - fec = fec_find (table, &rn->p); - if (!fec || fec->label == MPLS_INVALID_LABEL) - return 0; + /* See if there is a configured label binding for this FEC. */ + fec = fec_find(table, &rn->p); + if (!fec || fec->label == MPLS_INVALID_LABEL) + return 0; - /* Uninstall always removes all dynamic NHLFEs. */ - return lsp_uninstall (zvrf, fec->label); + /* Uninstall always removes all dynamic NHLFEs. */ + return lsp_uninstall(zvrf, fec->label); } /* @@ -1874,91 +1755,85 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct * label from a locally configured label block (SRGB), if one exists and index * is acceptable. */ -int -zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p, - u_int32_t label_index, struct zserv *client) -{ - struct route_table *table; - zebra_fec_t *fec; - char buf[BUFSIZ]; - int new_client; - int label_change = 0; - u_int32_t old_label; - - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; - if (!table) - return -1; - - if (IS_ZEBRA_DEBUG_MPLS) - prefix2str(p, buf, BUFSIZ); - - /* Locate FEC */ - fec = fec_find (table, p); - if (!fec) - { - fec = fec_add (table, p, MPLS_INVALID_LABEL, 0, label_index); - if (!fec) - { - prefix2str(p, buf, BUFSIZ); - zlog_err("Failed to add FEC %s upon register, client %s", - buf, zebra_route_string(client->proto)); - return -1; - } - - old_label = MPLS_INVALID_LABEL; - new_client = 1; - } - else - { - /* Client may register same FEC with different label index. */ - new_client = (listnode_lookup(fec->client_list, client) == NULL); - if (!new_client && fec->label_index == label_index) - /* Duplicate register */ - return 0; - - /* Save current label, update label index */ - old_label = fec->label; - fec->label_index = label_index; - } - - if (new_client) - listnode_add (fec->client_list, client); - - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug("FEC %s Label Index %u %s by client %s", - buf, label_index, new_client ? "registered" : "updated", - zebra_route_string(client->proto)); - - /* If not a configured FEC, derive the local label (from label index) - * or reset it. - */ - if (!(fec->flags & FEC_FLAG_CONFIGURED)) - { - fec_derive_label_from_index (zvrf, fec); - - /* If no label change, exit. */ - if (fec->label == old_label) - return 0; - - label_change = 1; - } - - /* If new client or label change, update client and install or uninstall - * label forwarding entry as needed. - */ - /* Inform client of label, if needed. */ - if ((new_client && fec->label != MPLS_INVALID_LABEL) || - label_change) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Update client label %u", fec->label); - fec_send (fec, client); - } - - if (new_client || label_change) - return fec_change_update_lsp (zvrf, fec, old_label); - - return 0; +int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, + u_int32_t label_index, struct zserv *client) +{ + struct route_table *table; + zebra_fec_t *fec; + char buf[BUFSIZ]; + int new_client; + int label_change = 0; + u_int32_t old_label; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) + prefix2str(p, buf, BUFSIZ); + + /* Locate FEC */ + fec = fec_find(table, p); + if (!fec) { + fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index); + if (!fec) { + prefix2str(p, buf, BUFSIZ); + zlog_err( + "Failed to add FEC %s upon register, client %s", + buf, zebra_route_string(client->proto)); + return -1; + } + + old_label = MPLS_INVALID_LABEL; + new_client = 1; + } else { + /* Client may register same FEC with different label index. */ + new_client = + (listnode_lookup(fec->client_list, client) == NULL); + if (!new_client && fec->label_index == label_index) + /* Duplicate register */ + return 0; + + /* Save current label, update label index */ + old_label = fec->label; + fec->label_index = label_index; + } + + if (new_client) + listnode_add(fec->client_list, client); + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("FEC %s Label Index %u %s by client %s", buf, + label_index, new_client ? "registered" : "updated", + zebra_route_string(client->proto)); + + /* If not a configured FEC, derive the local label (from label index) + * or reset it. + */ + if (!(fec->flags & FEC_FLAG_CONFIGURED)) { + fec_derive_label_from_index(zvrf, fec); + + /* If no label change, exit. */ + if (fec->label == old_label) + return 0; + + label_change = 1; + } + + /* If new client or label change, update client and install or uninstall + * label forwarding entry as needed. + */ + /* Inform client of label, if needed. */ + if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Update client label %u", fec->label); + fec_send(fec, client); + } + + if (new_client || label_change) + return fec_change_update_lsp(zvrf, fec, old_label); + + return 0; } /* @@ -1966,89 +1841,85 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p, * itself is deleted if no other registered clients exist and there is no * label bound to the FEC. */ -int -zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p, - struct zserv *client) +int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, + struct zserv *client) { - struct route_table *table; - zebra_fec_t *fec; - char buf[BUFSIZ]; - - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; - if (!table) - return -1; + struct route_table *table; + zebra_fec_t *fec; + char buf[BUFSIZ]; - if (IS_ZEBRA_DEBUG_MPLS) - prefix2str(p, buf, BUFSIZ); + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return -1; - fec = fec_find (table, p); - if (!fec) - { - prefix2str(p, buf, BUFSIZ); - zlog_err("Failed to find FEC %s upon unregister, client %s", - buf, zebra_route_string(client->proto)); - return -1; - } + if (IS_ZEBRA_DEBUG_MPLS) + prefix2str(p, buf, BUFSIZ); - listnode_delete(fec->client_list, client); - - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug("FEC %s unregistered by client %s", - buf, zebra_route_string(client->proto)); + fec = fec_find(table, p); + if (!fec) { + prefix2str(p, buf, BUFSIZ); + zlog_err("Failed to find FEC %s upon unregister, client %s", + buf, zebra_route_string(client->proto)); + return -1; + } - /* If not a configured entry, delete the FEC if no other clients. Before - * deleting, see if any LSP needs to be uninstalled. - */ - if (!(fec->flags & FEC_FLAG_CONFIGURED) && - list_isempty(fec->client_list)) - { - mpls_label_t old_label = fec->label; - fec->label = MPLS_INVALID_LABEL; /* reset */ - fec_change_update_lsp (zvrf, fec, old_label); - fec_del (fec); - } + listnode_delete(fec->client_list, client); + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("FEC %s unregistered by client %s", buf, + zebra_route_string(client->proto)); + + /* If not a configured entry, delete the FEC if no other clients. Before + * deleting, see if any LSP needs to be uninstalled. + */ + if (!(fec->flags & FEC_FLAG_CONFIGURED) + && list_isempty(fec->client_list)) { + mpls_label_t old_label = fec->label; + fec->label = MPLS_INVALID_LABEL; /* reset */ + fec_change_update_lsp(zvrf, fec, old_label); + fec_del(fec); + } - return 0; + return 0; } /* * Cleanup any FECs registered by this client. */ -int -zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client) -{ - struct route_node *rn; - zebra_fec_t *fec; - struct listnode *node; - struct zserv *fec_client; - int af; - - for (af = AFI_IP; af < AFI_MAX; af++) - { - if (zvrf->fec_table[af] == NULL) - continue; - - for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) - { - fec = rn->info; - if (!fec || list_isempty(fec->client_list)) - continue; - - for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, fec_client)) - { - if (fec_client == client) - { - listnode_delete(fec->client_list, fec_client); - if (!(fec->flags & FEC_FLAG_CONFIGURED) && - list_isempty(fec->client_list)) - fec_del (fec); - break; - } - } - } - } +int zebra_mpls_cleanup_fecs_for_client(struct zebra_vrf *zvrf, + struct zserv *client) +{ + struct route_node *rn; + zebra_fec_t *fec; + struct listnode *node; + struct zserv *fec_client; + int af; + + for (af = AFI_IP; af < AFI_MAX; af++) { + if (zvrf->fec_table[af] == NULL) + continue; + + for (rn = route_top(zvrf->fec_table[af]); rn; + rn = route_next(rn)) { + fec = rn->info; + if (!fec || list_isempty(fec->client_list)) + continue; + + for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, + fec_client)) { + if (fec_client == client) { + listnode_delete(fec->client_list, + fec_client); + if (!(fec->flags & FEC_FLAG_CONFIGURED) + && list_isempty(fec->client_list)) + fec_del(fec); + break; + } + } + } + } - return 0; + return 0; } /* @@ -2058,38 +1929,36 @@ zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client * TODO: Currently walks entire table, can optimize later with another * hash.. */ -zebra_fec_t * -zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label) -{ - struct route_node *rn; - zebra_fec_t *fec; - int af; - - for (af = AFI_IP; af < AFI_MAX; af++) - { - if (zvrf->fec_table[af] == NULL) - continue; - - for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) - { - if (!rn->info) - continue; - fec = rn->info; - if (fec->label == label) - return fec; - } - } +zebra_fec_t *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, + mpls_label_t label) +{ + struct route_node *rn; + zebra_fec_t *fec; + int af; + + for (af = AFI_IP; af < AFI_MAX; af++) { + if (zvrf->fec_table[af] == NULL) + continue; + + for (rn = route_top(zvrf->fec_table[af]); rn; + rn = route_next(rn)) { + if (!rn->info) + continue; + fec = rn->info; + if (fec->label == label) + return fec; + } + } - return NULL; + return NULL; } /* * Inform if specified label is currently bound to a FEC or not. */ -int -zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label) +int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label) { - return (zebra_mpls_fec_for_label (zvrf, label) ? 1 : 0); + return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0); } /* @@ -2097,59 +1966,54 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label) * FEC, notify them. If there are labeled routes for this FEC, install the * label forwarding entry. */ -int -zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, - mpls_label_t in_label) -{ - struct route_table *table; - zebra_fec_t *fec; - char buf[BUFSIZ]; - mpls_label_t old_label; - int ret = 0; - - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; - if (!table) - return -1; - - if (IS_ZEBRA_DEBUG_MPLS) - prefix2str(p, buf, BUFSIZ); - - /* Update existing FEC or create a new one. */ - fec = fec_find (table, p); - if (!fec) - { - fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED, - MPLS_INVALID_LABEL_INDEX); - if (!fec) - { - prefix2str(p, buf, BUFSIZ); - zlog_err ("Failed to add FEC %s upon config", buf); - return -1; - } - - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Add fec %s label %u", buf, in_label); - } - else - { - fec->flags |= FEC_FLAG_CONFIGURED; - if (fec->label == in_label) - /* Duplicate config */ - return 0; - - /* Label change, update clients. */ - old_label = fec->label; - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Update fec %s new label %u", buf, in_label); - - fec->label = in_label; - fec_update_clients (fec); - - /* Update label forwarding entries appropriately */ - ret = fec_change_update_lsp (zvrf, fec, old_label); - } - - return ret; +int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t in_label) +{ + struct route_table *table; + zebra_fec_t *fec; + char buf[BUFSIZ]; + mpls_label_t old_label; + int ret = 0; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) + prefix2str(p, buf, BUFSIZ); + + /* Update existing FEC or create a new one. */ + fec = fec_find(table, p); + if (!fec) { + fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED, + MPLS_INVALID_LABEL_INDEX); + if (!fec) { + prefix2str(p, buf, BUFSIZ); + zlog_err("Failed to add FEC %s upon config", buf); + return -1; + } + + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Add fec %s label %u", buf, in_label); + } else { + fec->flags |= FEC_FLAG_CONFIGURED; + if (fec->label == in_label) + /* Duplicate config */ + return 0; + + /* Label change, update clients. */ + old_label = fec->label; + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Update fec %s new label %u", buf, in_label); + + fec->label = in_label; + fec_update_clients(fec); + + /* Update label forwarding entries appropriately */ + ret = fec_change_update_lsp(zvrf, fec, old_label); + } + + return ret; } /* @@ -2158,218 +2022,210 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, * Note: Upon delete of static binding, if label index exists for this FEC, * client may need to be updated with derived label. */ -int -zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) -{ - struct route_table *table; - zebra_fec_t *fec; - mpls_label_t old_label; - char buf[BUFSIZ]; - - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; - if (!table) - return -1; - - fec = fec_find (table, p); - if (!fec) - { - prefix2str(p, buf, BUFSIZ); - zlog_err("Failed to find FEC %s upon delete", buf); - return -1; - } - - if (IS_ZEBRA_DEBUG_MPLS) - { - prefix2str(p, buf, BUFSIZ); - zlog_debug ("Delete fec %s label index %u", - buf, fec->label_index); - } - - old_label = fec->label; - fec->flags &= ~FEC_FLAG_CONFIGURED; - fec->label = MPLS_INVALID_LABEL; - - /* If no client exists, just delete the FEC. */ - if (list_isempty(fec->client_list)) - { - fec_del (fec); - return 0; - } - - /* Derive the local label (from label index) or reset it. */ - fec_derive_label_from_index (zvrf, fec); - - /* If there is a label change, update clients. */ - if (fec->label == old_label) - return 0; - fec_update_clients (fec); - - /* Update label forwarding entries appropriately */ - return fec_change_update_lsp (zvrf, fec, old_label); +int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p) +{ + struct route_table *table; + zebra_fec_t *fec; + mpls_label_t old_label; + char buf[BUFSIZ]; + + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return -1; + + fec = fec_find(table, p); + if (!fec) { + prefix2str(p, buf, BUFSIZ); + zlog_err("Failed to find FEC %s upon delete", buf); + return -1; + } + + if (IS_ZEBRA_DEBUG_MPLS) { + prefix2str(p, buf, BUFSIZ); + zlog_debug("Delete fec %s label index %u", buf, + fec->label_index); + } + + old_label = fec->label; + fec->flags &= ~FEC_FLAG_CONFIGURED; + fec->label = MPLS_INVALID_LABEL; + + /* If no client exists, just delete the FEC. */ + if (list_isempty(fec->client_list)) { + fec_del(fec); + return 0; + } + + /* Derive the local label (from label index) or reset it. */ + fec_derive_label_from_index(zvrf, fec); + + /* If there is a label change, update clients. */ + if (fec->label == old_label) + return 0; + fec_update_clients(fec); + + /* Update label forwarding entries appropriately */ + return fec_change_update_lsp(zvrf, fec, old_label); } /* * Display MPLS FEC to label binding configuration (VTY command handler). */ -int -zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf) +int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf) { - struct route_node *rn; - int af; - zebra_fec_t *fec; - char buf[BUFSIZ]; - int write = 0; + struct route_node *rn; + int af; + zebra_fec_t *fec; + char buf[BUFSIZ]; + int write = 0; - for (af = AFI_IP; af < AFI_MAX; af++) - { - if (zvrf->fec_table[af] == NULL) - continue; + for (af = AFI_IP; af < AFI_MAX; af++) { + if (zvrf->fec_table[af] == NULL) + continue; - for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) - { - if (!rn->info) - continue; + for (rn = route_top(zvrf->fec_table[af]); rn; + rn = route_next(rn)) { + if (!rn->info) + continue; - char lstr[BUFSIZ]; - fec = rn->info; + char lstr[BUFSIZ]; + fec = rn->info; - if (!(fec->flags & FEC_FLAG_CONFIGURED)) - continue; + if (!(fec->flags & FEC_FLAG_CONFIGURED)) + continue; - write = 1; - prefix2str(&rn->p, buf, BUFSIZ); - vty_out (vty, "mpls label bind %s %s\n", buf, - label2str(fec->label, lstr, BUFSIZ)); - } - } + write = 1; + prefix2str(&rn->p, buf, BUFSIZ); + vty_out(vty, "mpls label bind %s %s\n", buf, + label2str(fec->label, lstr, BUFSIZ)); + } + } - return write; + return write; } /* * Display MPLS FEC to label binding (VTY command handler). */ -void -zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf) +void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf) { - struct route_node *rn; - int af; + struct route_node *rn; + int af; - for (af = AFI_IP; af < AFI_MAX; af++) - { - if (zvrf->fec_table[af] == NULL) - continue; + for (af = AFI_IP; af < AFI_MAX; af++) { + if (zvrf->fec_table[af] == NULL) + continue; - for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn)) - { - if (!rn->info) - continue; - fec_print (rn->info, vty); - } - } + for (rn = route_top(zvrf->fec_table[af]); rn; + rn = route_next(rn)) { + if (!rn->info) + continue; + fec_print(rn->info, vty); + } + } } /* * Display MPLS FEC to label binding for a specific FEC (VTY command handler). */ -void -zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p) +void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, + struct prefix *p) { - struct route_table *table; - struct route_node *rn; + struct route_table *table; + struct route_node *rn; - table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; - if (!table) - return; + table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))]; + if (!table) + return; - apply_mask (p); - rn = route_node_lookup(table, p); - if (!rn) - return; + apply_mask(p); + rn = route_node_lookup(table, p); + if (!rn) + return; - route_unlock_node(rn); - if (!rn->info) - return; + route_unlock_node(rn); + if (!rn->info) + return; - fec_print (rn->info, vty); + fec_print(rn->info, vty); } /* * 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, u_int8_t distance, - mpls_label_t out_label) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *re; - struct nexthop *nexthop; - - /* Lookup table. */ - table = zebra_vrf_table (family2afi(prefix->family), SAFI_UNICAST, zvrf_id (zvrf)); - if (! table) - return -1; - - /* 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->distance == distance) - break; - } - - if (re == NULL) - return -1; - - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) - { - switch (nexthop->type) +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, u_int8_t distance, + mpls_label_t out_label) +{ + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + struct nexthop *nexthop; + + /* Lookup table. */ + table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST, + zvrf_id(zvrf)); + if (!table) + return -1; + + /* Lookup existing route */ + rn = route_node_get(table, prefix); + RNODE_FOREACH_RE(rn, re) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (gtype != NEXTHOP_TYPE_IPV4 && gtype != NEXTHOP_TYPE_IPV4_IFINDEX) - continue; - if (! IPV4_ADDR_SAME (&nexthop->gate.ipv4, &gate->ipv4)) - continue; - if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX && - nexthop->ifindex != ifindex) - continue; - goto found; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (gtype != NEXTHOP_TYPE_IPV6 && gtype != NEXTHOP_TYPE_IPV6_IFINDEX) - continue; - if (! IPV6_ADDR_SAME (&nexthop->gate.ipv6, &gate->ipv6)) - continue; - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX && - nexthop->ifindex != ifindex) - continue; - goto found; - default: - break; + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + if (re->distance == distance) + break; } - } - /* nexthop not found */ - return -1; - found: - if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE) - nexthop_add_labels (nexthop, type, 1, &out_label); - else if (!add && nexthop->nh_label_type == type) - nexthop_del_labels (nexthop); - else - return 0; + if (re == NULL) + return -1; + + for (nexthop = re->nexthop; 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) + continue; + if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4)) + continue; + if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX + && nexthop->ifindex != ifindex) + continue; + goto found; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (gtype != NEXTHOP_TYPE_IPV6 + && gtype != NEXTHOP_TYPE_IPV6_IFINDEX) + continue; + if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6, &gate->ipv6)) + continue; + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX + && nexthop->ifindex != ifindex) + continue; + goto found; + default: + break; + } + } + /* nexthop not found */ + return -1; + +found: + if (add && nexthop->nh_label_type == ZEBRA_LSP_NONE) + nexthop_add_labels(nexthop, type, 1, &out_label); + else if (!add && nexthop->nh_label_type == type) + nexthop_del_labels(nexthop); + else + return 0; - SET_FLAG (re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG (re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); - rib_queue_add (rn); + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); + rib_queue_add(rn); - return 0; + return 0; } /* @@ -2377,197 +2233,185 @@ mpls_ftn_update (int add, 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, mpls_label_t out_label, - enum nexthop_types_t gtype, 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 present, exit. */ - 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); - 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->label[0] == out_label) - /* No change */ - return 0; - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("LSP in-label %u type %d nexthop %s " - "out-label changed to %u (old %u)", - in_label, type, buf, - out_label, nh->nh_label->label[0]); - } - - /* Update out label, trigger processing. */ - nh->nh_label->label[0] = out_label; - } - else - { - /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add (lsp, type, gtype, gate, ifindex, out_label); - if (!nhlfe) - return -1; - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("Add LSP in-label %u type %d nexthop %s " - "out-label %u", in_label, type, buf, out_label); - } - - lsp->addr_family = NHLFE_FAMILY (nhlfe); - } - - /* Mark NHLFE, queue LSP for processing. */ - SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); - if (lsp_processq_add (lsp)) - return -1; - - return 0; +int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, mpls_label_t out_label, + enum nexthop_types_t gtype, 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 present, exit. */ + 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); + 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->label[0] == out_label) + /* No change */ + return 0; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "LSP in-label %u type %d nexthop %s " + "out-label changed to %u (old %u)", + in_label, type, buf, out_label, + nh->nh_label->label[0]); + } + + /* Update out label, trigger processing. */ + nh->nh_label->label[0] = out_label; + } else { + /* Add LSP entry to this nexthop */ + nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label); + if (!nhlfe) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug( + "Add LSP in-label %u type %d nexthop %s " + "out-label %u", + in_label, type, buf, out_label); + } + + lsp->addr_family = NHLFE_FAMILY(nhlfe); + } + + /* Mark NHLFE, queue LSP for processing. */ + SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); + if (lsp_processq_add(lsp)) + return -1; + + 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. */ -int -mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type, - mpls_label_t in_label, enum nexthop_types_t gtype, - 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, type, gtype, gate, ifindex); - if (!nhlfe) - return 0; - - if (IS_ZEBRA_DEBUG_MPLS) - { - nhlfe2str (nhlfe, buf, BUFSIZ); - zlog_debug ("Del 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. */ - if (!lsp->nhlfe_list && - !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED)) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Free LSP in-label %u flags 0x%x", - lsp->ile.in_label, lsp->flags); - - lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); - } - } - return 0; +int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + mpls_label_t in_label, enum nexthop_types_t gtype, + 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, type, gtype, gate, ifindex); + if (!nhlfe) + return 0; + + if (IS_ZEBRA_DEBUG_MPLS) { + nhlfe2str(nhlfe, buf, BUFSIZ); + zlog_debug("Del 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. */ + if (!lsp->nhlfe_list + && !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Free LSP in-label %u flags 0x%x", + lsp->ile.in_label, lsp->flags); + + lsp = hash_release(lsp_table, &lsp->ile); + if (lsp) + XFREE(MTYPE_LSP, lsp); + } + } + return 0; } /* * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void -mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt) +void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt) { - zebra_lsp_t *lsp; - struct hash *lsp_table; + zebra_lsp_t *lsp; + struct hash *lsp_table; - lsp = (zebra_lsp_t *) backet->data; - if (!lsp || !lsp->nhlfe_list) - return; + lsp = (zebra_lsp_t *)backet->data; + if (!lsp || !lsp->nhlfe_list) + return; - lsp_table = ctxt; - if (!lsp_table) - return; + lsp_table = ctxt; + if (!lsp_table) + return; - mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_LDP); + mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP); } /* * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. */ -void -mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *re; - struct nexthop *nexthop; - int update; - - /* Process routes of interested address-families. */ - table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf_id (zvrf)); - if (!table) - return; - - for (rn = route_top (table); rn; rn = route_next (rn)) - { - update = 0; - RNODE_FOREACH_RE (rn, re) - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) - if (nexthop->nh_label_type == ZEBRA_LSP_LDP) - { - nexthop_del_labels (nexthop); - SET_FLAG (re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG (re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); - update = 1; - } - - if (update) - rib_queue_add (rn); - } +void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) +{ + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + struct nexthop *nexthop; + int update; + + /* Process routes of interested address-families. */ + table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); + if (!table) + return; + + for (rn = route_top(table); rn; rn = route_next(rn)) { + update = 0; + RNODE_FOREACH_RE(rn, re) + for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) + if (nexthop->nh_label_type == ZEBRA_LSP_LDP) { + nexthop_del_labels(nexthop); + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, + ROUTE_ENTRY_NEXTHOPS_CHANGED); + update = 1; + } + + if (update) + rib_queue_add(rn); + } } #if defined(HAVE_CUMULUS) @@ -2577,54 +2421,51 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi) * be consistent - i.e., all paths either do a swap or do PHP. This is due * to current HW restrictions. */ -int -zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, - mpls_label_t out_label, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) -{ - struct hash *slsp_table; - zebra_ile_t tmp_ile; - zebra_slsp_t *slsp; - zebra_snhlfe_t *snhlfe; - - /* Lookup table. */ - slsp_table = zvrf->slsp_table; - if (!slsp_table) - return 0; - - /* If entry is not present, exit. */ - tmp_ile.in_label = in_label; - slsp = hash_lookup (slsp_table, &tmp_ile); - if (!slsp) - return 1; - - snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); - if (snhlfe) - { - if (snhlfe->out_label == out_label) - return 1; - - /* If not only NHLFE, cannot allow label change. */ - if (snhlfe != slsp->snhlfe_list || - snhlfe->next) - return 0; - } - else - { - /* If other NHLFEs exist, label operation must match. */ - if (slsp->snhlfe_list) - { - int cur_op, new_op; - - cur_op = (slsp->snhlfe_list->out_label == MPLS_IMP_NULL_LABEL); - new_op = (out_label == MPLS_IMP_NULL_LABEL); - if (cur_op != new_op) - return 0; - } - } - - /* Label values are good. */ - return 1; +int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf, + mpls_label_t in_label, + mpls_label_t out_label, + enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex) +{ + struct hash *slsp_table; + zebra_ile_t tmp_ile; + zebra_slsp_t *slsp; + zebra_snhlfe_t *snhlfe; + + /* Lookup table. */ + slsp_table = zvrf->slsp_table; + if (!slsp_table) + return 0; + + /* If entry is not present, exit. */ + tmp_ile.in_label = in_label; + slsp = hash_lookup(slsp_table, &tmp_ile); + if (!slsp) + return 1; + + snhlfe = snhlfe_find(slsp, gtype, gate, ifindex); + if (snhlfe) { + if (snhlfe->out_label == out_label) + return 1; + + /* If not only NHLFE, cannot allow label change. */ + if (snhlfe != slsp->snhlfe_list || snhlfe->next) + return 0; + } else { + /* If other NHLFEs exist, label operation must match. */ + if (slsp->snhlfe_list) { + int cur_op, new_op; + + cur_op = (slsp->snhlfe_list->out_label + == MPLS_IMP_NULL_LABEL); + new_op = (out_label == MPLS_IMP_NULL_LABEL); + if (cur_op != new_op) + return 0; + } + } + + /* Label values are good. */ + return 1; } #endif /* HAVE_CUMULUS */ @@ -2635,64 +2476,61 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, * Note: The label operation (swap or PHP) is common for the LSP entry (all * NHLFEs). */ -int -zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, - mpls_label_t out_label, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) -{ - struct hash *slsp_table; - zebra_ile_t tmp_ile; - zebra_slsp_t *slsp; - zebra_snhlfe_t *snhlfe; - char buf[BUFSIZ]; - - /* Lookup table. */ - slsp_table = zvrf->slsp_table; - if (!slsp_table) - return -1; - - /* If entry is present, exit. */ - tmp_ile.in_label = in_label; - slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc); - if (!slsp) - return -1; - snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); - if (snhlfe) - { - if (snhlfe->out_label == out_label) - /* No change */ - return 0; - - if (IS_ZEBRA_DEBUG_MPLS) - { - snhlfe2str (snhlfe, buf, BUFSIZ); - zlog_debug ("Upd static LSP in-label %u nexthop %s " - "out-label %u (old %u)", - in_label, buf, out_label, snhlfe->out_label); - } - snhlfe->out_label = out_label; - } - else - { - /* Add static LSP entry to this nexthop */ - snhlfe = snhlfe_add (slsp, gtype, gate, ifindex, out_label); - if (!snhlfe) - return -1; - - if (IS_ZEBRA_DEBUG_MPLS) - { - snhlfe2str (snhlfe, buf, BUFSIZ); - zlog_debug ("Add static LSP in-label %u nexthop %s out-label %u", - in_label, buf, out_label); - } - } - - /* (Re)Install LSP in the main table. */ - if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype, - gate, ifindex)) - return -1; - - return 0; +int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label, + mpls_label_t out_label, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex) +{ + struct hash *slsp_table; + zebra_ile_t tmp_ile; + zebra_slsp_t *slsp; + zebra_snhlfe_t *snhlfe; + char buf[BUFSIZ]; + + /* Lookup table. */ + slsp_table = zvrf->slsp_table; + if (!slsp_table) + return -1; + + /* If entry is present, exit. */ + tmp_ile.in_label = in_label; + slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc); + if (!slsp) + return -1; + snhlfe = snhlfe_find(slsp, gtype, gate, ifindex); + if (snhlfe) { + if (snhlfe->out_label == out_label) + /* No change */ + return 0; + + if (IS_ZEBRA_DEBUG_MPLS) { + snhlfe2str(snhlfe, buf, BUFSIZ); + zlog_debug( + "Upd static LSP in-label %u nexthop %s " + "out-label %u (old %u)", + in_label, buf, out_label, snhlfe->out_label); + } + snhlfe->out_label = out_label; + } else { + /* Add static LSP entry to this nexthop */ + snhlfe = snhlfe_add(slsp, gtype, gate, ifindex, out_label); + if (!snhlfe) + return -1; + + if (IS_ZEBRA_DEBUG_MPLS) { + snhlfe2str(snhlfe, buf, BUFSIZ); + zlog_debug( + "Add static LSP in-label %u nexthop %s out-label %u", + in_label, buf, out_label); + } + } + + /* (Re)Install LSP in the main table. */ + if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype, + gate, ifindex)) + return -1; + + return 0; } /* @@ -2702,71 +2540,66 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, * NOTE: Delete of the only NHLFE will also end up deleting the entire * LSP configuration. */ -int -zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex) -{ - struct hash *slsp_table; - zebra_ile_t tmp_ile; - zebra_slsp_t *slsp; - zebra_snhlfe_t *snhlfe; - - /* Lookup table. */ - slsp_table = zvrf->slsp_table; - if (!slsp_table) - return -1; - - /* If entry is not present, exit. */ - tmp_ile.in_label = in_label; - slsp = hash_lookup (slsp_table, &tmp_ile); - if (!slsp) - return 0; - - /* Is it delete of entire LSP or a specific NHLFE? */ - if (gtype == NEXTHOP_TYPE_BLACKHOLE) - { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug ("Del static LSP in-label %u", in_label); - - /* Uninstall entire LSP from the main table. */ - mpls_static_lsp_uninstall_all (zvrf, in_label); - - /* Delete all static NHLFEs */ - snhlfe_del_all (slsp); - } - else - { - /* Find specific NHLFE, exit if not found. */ - snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); - if (!snhlfe) - return 0; - - if (IS_ZEBRA_DEBUG_MPLS) - { - char buf[BUFSIZ]; - snhlfe2str (snhlfe, buf, BUFSIZ); - zlog_debug ("Del static LSP in-label %u nexthop %s", - in_label, buf); - } - - /* Uninstall LSP from the main table. */ - mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate, - ifindex); - - /* Delete static LSP NHLFE */ - snhlfe_del (snhlfe); - } - - /* Remove entire static LSP entry if no NHLFE - valid in either case above. */ - if (!slsp->snhlfe_list) - { - slsp = hash_release(slsp_table, &tmp_ile); - if (slsp) - XFREE(MTYPE_SLSP, slsp); - } - - return 0; +int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label, + enum nexthop_types_t gtype, union g_addr *gate, + ifindex_t ifindex) +{ + struct hash *slsp_table; + zebra_ile_t tmp_ile; + zebra_slsp_t *slsp; + zebra_snhlfe_t *snhlfe; + + /* Lookup table. */ + slsp_table = zvrf->slsp_table; + if (!slsp_table) + return -1; + + /* If entry is not present, exit. */ + tmp_ile.in_label = in_label; + slsp = hash_lookup(slsp_table, &tmp_ile); + if (!slsp) + return 0; + + /* Is it delete of entire LSP or a specific NHLFE? */ + if (gtype == NEXTHOP_TYPE_BLACKHOLE) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("Del static LSP in-label %u", in_label); + + /* Uninstall entire LSP from the main table. */ + mpls_static_lsp_uninstall_all(zvrf, in_label); + + /* Delete all static NHLFEs */ + snhlfe_del_all(slsp); + } else { + /* Find specific NHLFE, exit if not found. */ + snhlfe = snhlfe_find(slsp, gtype, gate, ifindex); + if (!snhlfe) + return 0; + + if (IS_ZEBRA_DEBUG_MPLS) { + char buf[BUFSIZ]; + snhlfe2str(snhlfe, buf, BUFSIZ); + zlog_debug("Del static LSP in-label %u nexthop %s", + in_label, buf); + } + + /* Uninstall LSP from the main table. */ + mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype, + gate, ifindex); + + /* Delete static LSP NHLFE */ + snhlfe_del(snhlfe); + } + + /* Remove entire static LSP entry if no NHLFE - valid in either case + * above. */ + if (!slsp->snhlfe_list) { + slsp = hash_release(slsp_table, &tmp_ile); + if (slsp) + XFREE(MTYPE_SLSP, slsp); + } + + return 0; } /* @@ -2774,200 +2607,192 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, * Called upon changes that may affect one or more of them such as * interface or nexthop state changes. */ -void -zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf) +void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf) { - if (!zvrf) - return; - hash_iterate(zvrf->lsp_table, lsp_schedule, NULL); + if (!zvrf) + return; + hash_iterate(zvrf->lsp_table, lsp_schedule, NULL); } /* * Display MPLS label forwarding table for a specific LSP * (VTY command handler). */ -void -zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label, - u_char use_json) +void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf, + mpls_label_t label, u_char use_json) { - struct hash *lsp_table; - zebra_lsp_t *lsp; - zebra_ile_t tmp_ile; - json_object *json = NULL; + struct hash *lsp_table; + zebra_lsp_t *lsp; + zebra_ile_t tmp_ile; + json_object *json = NULL; - /* Lookup table. */ - lsp_table = zvrf->lsp_table; - if (!lsp_table) - return; + /* Lookup table. */ + lsp_table = zvrf->lsp_table; + if (!lsp_table) + return; - /* If entry is not present, exit. */ - tmp_ile.in_label = label; - lsp = hash_lookup (lsp_table, &tmp_ile); - if (!lsp) - return; + /* If entry is not present, exit. */ + tmp_ile.in_label = label; + lsp = hash_lookup(lsp_table, &tmp_ile); + if (!lsp) + return; - if (use_json) - { - json = lsp_json(lsp); - vty_out (vty, "%s\n", - json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } - else - lsp_print (lsp, (void *)vty); + if (use_json) { + json = lsp_json(lsp); + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else + lsp_print(lsp, (void *)vty); } /* * Display MPLS label forwarding table (VTY command handler). */ -void -zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf, - u_char use_json) -{ - char buf[BUFSIZ]; - json_object *json = NULL; - zebra_lsp_t *lsp = NULL; - zebra_nhlfe_t *nhlfe = NULL; - struct nexthop *nexthop = NULL; - struct listnode *node = NULL; - struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp); - - if (use_json) - { - json = json_object_new_object(); - - for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) - json_object_object_add(json, label2str(lsp->ile.in_label, buf, BUFSIZ), - lsp_json(lsp)); - - vty_out (vty, "%s\n", - json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } - else - { - vty_out (vty, " Inbound Outbound\n"); - vty_out (vty, " Label Type Nexthop Label\n"); - vty_out (vty, "-------- ------- --------------- --------\n"); - - for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) - { - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - vty_out (vty, "%8d %7s ", lsp->ile.in_label, nhlfe_type2str(nhlfe->type)); - nexthop = nhlfe->nexthop; - - switch (nexthop->type) - { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out (vty, "%15s", inet_ntoa (nexthop->gate.ipv4)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out (vty, "%15s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); - break; - default: - break; - } - - vty_out (vty, " %8d\n", nexthop->nh_label->label[0]); - } - } - - vty_out (vty, "\n"); - } - - list_delete (lsp_list); +void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, + u_char use_json) +{ + char buf[BUFSIZ]; + json_object *json = NULL; + zebra_lsp_t *lsp = NULL; + zebra_nhlfe_t *nhlfe = NULL; + struct nexthop *nexthop = NULL; + struct listnode *node = NULL; + struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp); + + if (use_json) { + json = json_object_new_object(); + + for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) + json_object_object_add( + json, label2str(lsp->ile.in_label, buf, BUFSIZ), + lsp_json(lsp)); + + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, " Inbound Outbound\n"); + vty_out(vty, " Label Type Nexthop Label\n"); + vty_out(vty, "-------- ------- --------------- --------\n"); + + for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) { + for (nhlfe = lsp->nhlfe_list; nhlfe; + nhlfe = nhlfe->next) { + vty_out(vty, "%8d %7s ", lsp->ile.in_label, + nhlfe_type2str(nhlfe->type)); + nexthop = nhlfe->nexthop; + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, "%15s", + inet_ntoa(nexthop->gate.ipv4)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, "%15s", + inet_ntop(AF_INET6, + &nexthop->gate.ipv6, + buf, BUFSIZ)); + break; + default: + break; + } + + vty_out(vty, " %8d\n", + nexthop->nh_label->label[0]); + } + } + + vty_out(vty, "\n"); + } + + list_delete(lsp_list); } /* * Display MPLS LSP configuration of all static LSPs (VTY command handler). */ -int -zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf) -{ - zebra_slsp_t *slsp; - zebra_snhlfe_t *snhlfe; - struct listnode *node; - struct list *slsp_list = 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) - { - char buf[INET6_ADDRSTRLEN]; - char lstr[30]; - - snhlfe2str (snhlfe, buf, BUFSIZ); - switch (snhlfe->out_label) { - case MPLS_V4_EXP_NULL_LABEL: - case MPLS_V6_EXP_NULL_LABEL: - strlcpy(lstr, "explicit-null", sizeof(lstr)); - break; - case MPLS_IMP_NULL_LABEL: - strlcpy(lstr, "implicit-null", sizeof(lstr)); - break; - default: - sprintf(lstr, "%u", snhlfe->out_label); - break; - } - - vty_out (vty, "mpls lsp %u %s %s\n", - slsp->ile.in_label, buf, lstr); - } - } +int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf) +{ + zebra_slsp_t *slsp; + zebra_snhlfe_t *snhlfe; + struct listnode *node; + struct list *slsp_list = + 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) { + char buf[INET6_ADDRSTRLEN]; + char lstr[30]; + + snhlfe2str(snhlfe, buf, BUFSIZ); + switch (snhlfe->out_label) { + case MPLS_V4_EXP_NULL_LABEL: + case MPLS_V6_EXP_NULL_LABEL: + strlcpy(lstr, "explicit-null", sizeof(lstr)); + break; + case MPLS_IMP_NULL_LABEL: + strlcpy(lstr, "implicit-null", sizeof(lstr)); + break; + default: + sprintf(lstr, "%u", snhlfe->out_label); + break; + } + + vty_out(vty, "mpls lsp %u %s %s\n", slsp->ile.in_label, + buf, lstr); + } + } - list_delete (slsp_list); - return (zvrf->slsp_table->count ? 1 : 0); + list_delete(slsp_list); + return (zvrf->slsp_table->count ? 1 : 0); } /* * Add/update global label block. */ -int -zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label, - u_int32_t end_label) +int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, u_int32_t start_label, + u_int32_t end_label) { - zvrf->mpls_srgb.start_label = start_label; - zvrf->mpls_srgb.end_label = end_label; + zvrf->mpls_srgb.start_label = start_label; + zvrf->mpls_srgb.end_label = end_label; - /* Evaluate registered FECs to see if any get a label or not. */ - fec_evaluate (zvrf); - return 0; + /* Evaluate registered FECs to see if any get a label or not. */ + fec_evaluate(zvrf); + return 0; } /* * Delete global label block. */ -int -zebra_mpls_label_block_del (struct zebra_vrf *zvrf) +int zebra_mpls_label_block_del(struct zebra_vrf *zvrf) { - zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL; - zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL; + zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL; + zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL; - /* Process registered FECs to clear their local label, if needed. */ - fec_evaluate (zvrf); - return 0; + /* Process registered FECs to clear their local label, if needed. */ + fec_evaluate(zvrf); + return 0; } /* * Display MPLS global label block configuration (VTY command handler). */ -int -zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf) +int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf) { - if (zvrf->mpls_srgb.start_label == 0) - return 0; + if (zvrf->mpls_srgb.start_label == 0) + return 0; - if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL) || - (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) - { - vty_out (vty, "mpls label global-block %u %u\n", - zvrf->mpls_srgb.start_label,zvrf->mpls_srgb.end_label); - } + if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL) + || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) { + vty_out(vty, "mpls label global-block %u %u\n", + zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label); + } - return 1; + return 1; } /* @@ -2975,48 +2800,44 @@ zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf) * entries from the kernel. * NOTE: Currently supported only for default VRF. */ -void -zebra_mpls_close_tables (struct zebra_vrf *zvrf) +void zebra_mpls_close_tables(struct zebra_vrf *zvrf) { - hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL); - hash_clean(zvrf->lsp_table, NULL); - hash_free(zvrf->lsp_table); - hash_clean(zvrf->slsp_table, NULL); - hash_free(zvrf->slsp_table); + hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL); + hash_clean(zvrf->lsp_table, NULL); + hash_free(zvrf->lsp_table); + hash_clean(zvrf->slsp_table, NULL); + hash_free(zvrf->slsp_table); } /* * Allocate MPLS tables for this VRF and do other initialization. * NOTE: Currently supported only for default VRF. */ -void -zebra_mpls_init_tables (struct zebra_vrf *zvrf) +void zebra_mpls_init_tables(struct zebra_vrf *zvrf) { - if (!zvrf) - return; - zvrf->slsp_table = hash_create(label_hash, label_cmp, NULL); - zvrf->lsp_table = hash_create(label_hash, label_cmp, NULL); - zvrf->fec_table[AFI_IP] = route_table_init(); - zvrf->fec_table[AFI_IP6] = route_table_init(); - zvrf->mpls_flags = 0; - zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL; - zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL; + if (!zvrf) + return; + zvrf->slsp_table = hash_create(label_hash, label_cmp, NULL); + zvrf->lsp_table = hash_create(label_hash, label_cmp, NULL); + zvrf->fec_table[AFI_IP] = route_table_init(); + zvrf->fec_table[AFI_IP6] = route_table_init(); + zvrf->mpls_flags = 0; + zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL; + zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL; } /* * Global MPLS initialization. */ -void -zebra_mpls_init (void) +void zebra_mpls_init(void) { - mpls_enabled = 0; + mpls_enabled = 0; - if (mpls_kernel_init () < 0) - { - zlog_warn ("Disabling MPLS support (no kernel support)"); - return; - } + if (mpls_kernel_init() < 0) { + zlog_warn("Disabling MPLS support (no kernel support)"); + return; + } - if (! mpls_processq_init (&zebrad)) - mpls_enabled = 1; + if (!mpls_processq_init(&zebrad)) + mpls_enabled = 1; } |