diff options
author | Don Slice <dslice@cumulusnetworks.com> | 2017-02-02 18:58:33 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-04-06 16:29:19 +0200 |
commit | a64448baa6150a7431d55e0e65d0b51d62c4b5be (patch) | |
tree | adb195d3f8e26c4ae893f85fb1020e1d55d73241 /zebra | |
parent | bgpd: update debugs enance (diff) | |
download | frr-a64448baa6150a7431d55e0e65d0b51d62c4b5be.tar.xz frr-a64448baa6150a7431d55e0e65d0b51d62c4b5be.zip |
zebra: labeled unicast handling
Support install of labeled-unicast routes by a client. This would be
BGP, in order to install routes corresponding to AFI/SAFI 1/4 (IPv4)
or 2/4 (IPv6). Convert labeled-unicast routes into label forwarding
entries (i.e., transit LSPs) when there is a static label binding.
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/rib.h | 2 | ||||
-rw-r--r-- | zebra/zebra_mpls.c | 384 | ||||
-rw-r--r-- | zebra/zebra_mpls.h | 29 | ||||
-rw-r--r-- | zebra/zebra_mpls_null.c | 18 | ||||
-rw-r--r-- | zebra/zebra_mpls_vty.c | 6 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 47 | ||||
-rw-r--r-- | zebra/zserv.c | 60 |
7 files changed, 483 insertions, 63 deletions
diff --git a/zebra/rib.h b/zebra/rib.h index 5381d76b9..8f6cff0d8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -372,7 +372,7 @@ extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto, u_short instance); extern void rib_queue_add (struct route_node *rn); extern void meta_queue_free (struct meta_queue *mq); - +extern int zebra_rib_labeled_unicast (struct rib *rib); extern struct route_table *rib_table_ipv6; extern void rib_unlink (struct route_node *, struct rib *); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 366853cc0..f13a3f4f0 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -61,6 +61,13 @@ extern struct zebra_t zebrad; /* static function declarations */ static int +lsp_install (struct zebra_vrf *zvrf, mpls_label_t label, + struct route_node *rn, struct rib *rib); +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); @@ -69,7 +76,7 @@ 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, u_int32_t label, +fec_add (struct route_table *table, struct prefix *p, mpls_label_t label, u_int32_t flags); static int fec_del (zebra_fec_t *fec); @@ -106,17 +113,19 @@ 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, char *ifname, ifindex_t ifindex); + 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, - char *ifname, ifindex_t ifindex); + 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, - char *ifname, ifindex_t ifindex, mpls_label_t out_label); + 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); @@ -130,14 +139,13 @@ static void * slsp_alloc (void *p); static int snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex); + 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, char *ifname, ifindex_t ifindex); + 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, char *ifname, ifindex_t ifindex, - mpls_label_t out_label); + union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label); static int snhlfe_del (zebra_snhlfe_t *snhlfe); static int @@ -153,6 +161,245 @@ mpls_processq_init (struct zebra_t *zebra); /* Static functions */ /* + * 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 rib *rib) +{ + 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; + + /* See if route entry is selected; we really expect only 1 entry here. */ + if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + return 0; + + lsp_type = lsp_type_from_rib_type (rib->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 = rib->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; +} + +/* + * 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) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + 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); + + /* 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; + + /* See if labeled route exists. */ + rn = route_node_lookup (table, &fec->rn->p); + if (!rn) + return 0; + + RNODE_FOREACH_RIB (rn, rib) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + if (!rib || !zebra_rib_labeled_unicast (rib)) + return 0; + + if (lsp_install (zvrf, fec->label, rn, rib)) + return -1; + + return 0; +} + +/* * Inform about FEC to a registered client. */ static int @@ -760,7 +1007,7 @@ 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, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { struct nexthop *nhop; int cmp = 1; @@ -802,7 +1049,7 @@ nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, 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, - char *ifname, ifindex_t ifindex) + ifindex_t ifindex) { zebra_nhlfe_t *nhlfe; @@ -813,7 +1060,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, { if (nhlfe->type != lsp_type) continue; - if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex)) + if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex)) break; } @@ -827,7 +1074,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, static zebra_nhlfe_t * nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex, mpls_label_t out_label) + ifindex_t ifindex, mpls_label_t out_label) { zebra_nhlfe_t *nhlfe; struct nexthop *nexthop; @@ -917,6 +1164,15 @@ nhlfe_del (zebra_nhlfe_t *nhlfe) 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) @@ -1184,7 +1440,7 @@ slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2) */ static int snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { int cmp = 1; @@ -1216,7 +1472,7 @@ snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, */ static zebra_snhlfe_t * snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { zebra_snhlfe_t *snhlfe; @@ -1225,7 +1481,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next) { - if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex)) + if (!snhlfe_match (snhlfe, gtype, gate, ifindex)) break; } @@ -1239,7 +1495,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype, */ static zebra_snhlfe_t * snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, char *ifname, ifindex_t ifindex, + union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label) { zebra_snhlfe_t *snhlfe; @@ -1388,7 +1644,7 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels, *num_labels = 0; for (i = 0; i < MPLS_MAX_LABELS; i++) { - u_int32_t label; + mpls_label_t label; label = strtoul(label_str, &endp, 0); @@ -1433,6 +1689,58 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, } /* + * Install dynamic LSP entry. + */ +int +zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + struct route_table *table; + zebra_fec_t *fec; + + 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; + + /* 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, rib)) + return -1; + + return 0; +} + +/* + * Uninstall dynamic LSP entry, if any. + */ +int +zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + struct route_table *table; + zebra_fec_t *fec; + + 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; + + /* Uninstall always removes all dynamic NHLFEs. */ + return lsp_uninstall (zvrf, fec->label); +} + +/* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. */ @@ -1611,7 +1919,8 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label) /* * Add static FEC to label binding. If there are clients registered for this - * FEC, notify them. + * 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, @@ -1620,6 +1929,7 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, 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))]; @@ -1652,11 +1962,15 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p, 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; @@ -1671,6 +1985,7 @@ 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))]; @@ -1691,6 +2006,7 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) zlog_debug ("Delete fec %s", buf); } + old_label = fec->label; fec->flags &= ~FEC_FLAG_CONFIGURED; fec->label = MPLS_INVALID_LABEL; @@ -1703,7 +2019,8 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p) fec_update_clients (fec); - return 0; + /* Update label forwarding entries appropriately */ + return fec_change_update_lsp (zvrf, fec, old_label); } /* @@ -1879,7 +2196,7 @@ 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, - char *ifname, ifindex_t ifindex) + ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -1897,7 +2214,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc); if (!lsp) return -1; - nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex); + nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex); if (nhlfe) { struct nexthop *nh = nhlfe->nexthop; @@ -1926,8 +2243,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, else { /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add (lsp, type, gtype, gate, - ifname, ifindex, out_label); + nhlfe = nhlfe_add (lsp, type, gtype, gate, ifindex, out_label); if (!nhlfe) return -1; @@ -1956,7 +2272,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, 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, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -1974,7 +2290,7 @@ mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type, lsp = hash_lookup (lsp_table, &tmp_ile); if (!lsp) return 0; - nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex); + nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex); if (!nhlfe) return 0; @@ -2079,7 +2395,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi) 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, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { struct hash *slsp_table; zebra_ile_t tmp_ile; @@ -2097,7 +2413,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, if (!slsp) return 1; - snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex); + snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); if (snhlfe) { if (snhlfe->out_label == out_label) @@ -2137,7 +2453,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, 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, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { struct hash *slsp_table; zebra_ile_t tmp_ile; @@ -2155,7 +2471,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc); if (!slsp) return -1; - snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex); + snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); if (snhlfe) { if (snhlfe->out_label == out_label) @@ -2174,7 +2490,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, else { /* Add static LSP entry to this nexthop */ - snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label); + snhlfe = snhlfe_add (slsp, gtype, gate, ifindex, out_label); if (!snhlfe) return -1; @@ -2188,7 +2504,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, /* (Re)Install LSP in the main table. */ if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype, - gate, ifname, ifindex)) + gate, ifindex)) return -1; return 0; @@ -2204,7 +2520,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, int zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex) + ifindex_t ifindex) { struct hash *slsp_table; zebra_ile_t tmp_ile; @@ -2237,7 +2553,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, else { /* Find specific NHLFE, exit if not found. */ - snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex); + snhlfe = snhlfe_find (slsp, gtype, gate, ifindex); if (!snhlfe) return 0; @@ -2251,7 +2567,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, /* Uninstall LSP from the main table. */ mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate, - ifname, ifindex); + ifindex); /* Delete static LSP NHLFE */ snhlfe_del (snhlfe); diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 4636a28c1..f9d58a46e 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -184,6 +184,18 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, char *buf, int len); /* + * Install dynamic LSP entry. + */ +int +zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib); + +/* + * Uninstall dynamic LSP entry, if any. + */ +int +zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib); + +/* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. */ @@ -224,7 +236,8 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label); /* * Add static FEC to label binding. If there are clients registered for this - * FEC, notify them. + * 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, @@ -273,7 +286,7 @@ 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, - char *ifname, ifindex_t ifindex); + ifindex_t ifindex); /* * Uninstall a particular NHLFE in the forwarding table. If this is @@ -282,7 +295,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type, 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, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); /* * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. @@ -307,7 +320,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi); 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, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); #endif /* HAVE_CUMULUS */ /* @@ -320,7 +333,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, 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, char *ifname, ifindex_t ifindex); + union g_addr *gate, ifindex_t ifindex); /* * Delete static LSP entry. This may be the delete of one particular @@ -332,7 +345,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, int zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex); + ifindex_t ifindex); /* * Schedule all MPLS label forwarding entries for processing. @@ -415,6 +428,8 @@ lsp_type_from_rib_type (int rib_type) { case ZEBRA_ROUTE_STATIC: return ZEBRA_LSP_STATIC; + case ZEBRA_ROUTE_BGP: + return ZEBRA_LSP_BGP; default: return ZEBRA_LSP_NONE; } @@ -430,6 +445,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type) return "Static"; case ZEBRA_LSP_LDP: return "LDP"; + case ZEBRA_LSP_BGP: + return "BGP"; default: return "Unknown"; } diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 29990928d..d6f99b517 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -44,6 +44,18 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels, return 0; } +int +zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + return 0; +} + +int +zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib) +{ + return 0; +} + void zebra_mpls_init_tables (struct zebra_vrf *zvrf) { @@ -70,7 +82,7 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf) 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, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { return 0; } @@ -78,7 +90,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label, 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, char *ifname, ifindex_t ifindex) + union g_addr *gate, ifindex_t ifindex) { return 0; } @@ -86,7 +98,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, int zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, enum nexthop_types_t gtype, union g_addr *gate, - char *ifname, ifindex_t ifindex) + ifindex_t ifindex) { return 0; } diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index 90624c12a..8d8025682 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -133,7 +133,7 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str, #if defined(HAVE_CUMULUS) /* Check that label value is consistent. */ if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype, - &gate, NULL, 0)) + &gate, 0)) { vty_out (vty, "%% Label value not consistent%s", VTY_NEWLINE); @@ -142,10 +142,10 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str, #endif /* HAVE_CUMULUS */ ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype, - &gate, NULL, 0); + &gate, 0); } else - ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0); + ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, 0); if (ret) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b3e70e46f..e4d583d5f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1084,7 +1084,25 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) return rib->nexthop_active_num; } +/* + * Is this RIB labeled-unicast? It must be of type BGP and all paths + * (nexthops) must have a label. + */ +int +zebra_rib_labeled_unicast (struct rib *rib) +{ + struct nexthop *nexthop = NULL, *tnexthop; + int recursing; + + if (rib->type != ZEBRA_ROUTE_BGP) + return 0; + + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + if (!nexthop->nh_label || !nexthop->nh_label->num_labels) + return 0; + return 1; +} /* Update flag indicates whether this is a "replace" or not. Currently, this * is only used for IPv4. @@ -1177,7 +1195,12 @@ rib_uninstall (struct route_node *rn, struct rib *rib) if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); - UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB); + + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (rib)) + zebra_mpls_lsp_uninstall (info->zvrf, rn, rib); + + UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB); } if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) @@ -1272,6 +1295,10 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, zvrf_id (zvrf), buf, rn, new, new->type); } + /* If labeled-unicast route, install transit LSP. */ + if (zebra_rib_labeled_unicast (new)) + zebra_mpls_lsp_install (zvrf, rn, new); + if (!RIB_SYSTEM_ROUTE (new)) { if (rib_install_kernel (rn, new, NULL)) @@ -1301,6 +1328,10 @@ rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, zvrf_id (zvrf), buf, rn, old, old->type); } + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (old)) + zebra_mpls_lsp_uninstall (zvrf, rn, old); + if (!RIB_SYSTEM_ROUTE (old)) rib_uninstall_kernel (rn, old); @@ -1354,6 +1385,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, /* Non-system route should be installed. */ if (!RIB_SYSTEM_ROUTE (new)) { + /* If labeled-unicast route, install transit LSP. */ + if (zebra_rib_labeled_unicast (new)) + zebra_mpls_lsp_install (zvrf, rn, new); + if (rib_install_kernel (rn, new, old)) { char buf[SRCDEST2STR_BUFFER]; @@ -1368,6 +1403,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, { if (RIB_SYSTEM_ROUTE(new)) { + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (old)) + zebra_mpls_lsp_uninstall (zvrf, rn, old); + if (!RIB_SYSTEM_ROUTE (old)) rib_uninstall_kernel (rn, old); } @@ -1404,6 +1443,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, nh_active ? "install failed" : "nexthop inactive"); } + /* If labeled-unicast route, uninstall transit LSP. */ + if (zebra_rib_labeled_unicast (old)) + zebra_mpls_lsp_uninstall (zvrf, rn, old); + if (!RIB_SYSTEM_ROUTE (old)) rib_uninstall_kernel (rn, old); UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB); @@ -2934,8 +2977,10 @@ rib_tables_iter_next (rib_tables_iter_t *iter) } afi_safis[] = { { AFI_IP, SAFI_UNICAST }, { AFI_IP, SAFI_MULTICAST }, + { AFI_IP, SAFI_LABELED_UNICAST }, { AFI_IP6, SAFI_UNICAST }, { AFI_IP6, SAFI_MULTICAST }, + { AFI_IP6, SAFI_LABELED_UNICAST }, }; table = NULL; diff --git a/zebra/zserv.c b/zebra/zserv.c index 73ea58980..c11f1bf3f 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1129,13 +1129,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) struct rib *rib; struct prefix p; u_char message; - struct in_addr nexthop; + struct in_addr nhop_addr; u_char nexthop_num; u_char nexthop_type; struct stream *s; ifindex_t ifindex; safi_t safi; int ret; + mpls_label_t label; + struct nexthop *nexthop; /* Get input stream. */ s = client->ibuf; @@ -1177,13 +1179,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) rib_nexthop_ifindex_add (rib, ifindex); break; case NEXTHOP_TYPE_IPV4: - nexthop.s_addr = stream_get_ipv4 (s); - rib_nexthop_ipv4_add (rib, &nexthop, NULL); + nhop_addr.s_addr = stream_get_ipv4 (s); + nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL)) + { + label = (mpls_label_t)stream_getl (s); + nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label); + } break; case NEXTHOP_TYPE_IPV4_IFINDEX: - nexthop.s_addr = stream_get_ipv4 (s); + nhop_addr.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); - rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex); break; case NEXTHOP_TYPE_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); @@ -1276,6 +1284,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) break; case NEXTHOP_TYPE_IPV4: nexthop.s_addr = stream_get_ipv4 (s); + /* For labeled-unicast, each nexthop is followed by label, but + * we don't care for delete. + */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL)) + stream_forward_getp (s, sizeof(u_int32_t)); nexthop_p = (union g_addr *)&nexthop; break; case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -1461,7 +1474,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { unsigned int i; struct stream *s; - struct in6_addr nexthop; + struct in6_addr nhop_addr; struct rib *rib; u_char message; u_char nexthop_num; @@ -1472,11 +1485,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) static struct in6_addr nexthops[MULTIPATH_NUM]; static unsigned int ifindices[MULTIPATH_NUM]; int ret; + static mpls_label_t labels[MULTIPATH_NUM]; + mpls_label_t label; + struct nexthop *nexthop; /* Get input stream. */ s = client->ibuf; - memset (&nexthop, 0, sizeof (struct in6_addr)); + memset (&nhop_addr, 0, sizeof (struct in6_addr)); /* Allocate new rib. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); @@ -1525,10 +1541,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) switch (nexthop_type) { case NEXTHOP_TYPE_IPV6: - stream_get (&nexthop, s, 16); - if (nh_count < multipath_num) { - nexthops[nh_count++] = nexthop; - } + stream_get (&nhop_addr, s, 16); + if (nh_count < MULTIPATH_NUM) + { + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL)) + { + label = (mpls_label_t)stream_getl (s); + labels[nh_count++] = label; + } + nexthops[nh_count++] = nhop_addr; + } break; case NEXTHOP_TYPE_IFINDEX: if (if_count < multipath_num) { @@ -1546,9 +1569,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) { if ((i < if_count) && ifindices[i]) - rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); + nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); else - rib_nexthop_ipv6_add (rib, &nexthops[i]); + nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]); + if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL)) + nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]); } else { if ((i < if_count) && ifindices[i]) @@ -1645,6 +1670,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf) { case NEXTHOP_TYPE_IPV6: stream_get (&nexthop, s, 16); + /* For labeled-unicast, each nexthop is followed by label, but + * we don't care for delete. + */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL)) + stream_forward_getp (s, sizeof(u_int32_t)); pnexthop = (union g_addr *)&nexthop; break; case NEXTHOP_TYPE_IFINDEX: @@ -1815,14 +1845,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length, if (command == ZEBRA_MPLS_LABELS_ADD) { mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate, - NULL, ifindex); + ifindex); if (out_label != MPLS_IMP_NULL_LABEL) mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex, distance, out_label); } else if (command == ZEBRA_MPLS_LABELS_DELETE) { - mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex); + mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex); if (out_label != MPLS_IMP_NULL_LABEL) mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex, distance, out_label); |