summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
authorDon Slice <dslice@cumulusnetworks.com>2017-02-02 18:58:33 +0100
committerDonald Sharp <sharpd@cumulusnetworks.com>2017-04-06 16:29:19 +0200
commita64448baa6150a7431d55e0e65d0b51d62c4b5be (patch)
treeadb195d3f8e26c4ae893f85fb1020e1d55d73241 /zebra
parentbgpd: update debugs enance (diff)
downloadfrr-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.h2
-rw-r--r--zebra/zebra_mpls.c384
-rw-r--r--zebra/zebra_mpls.h29
-rw-r--r--zebra/zebra_mpls_null.c18
-rw-r--r--zebra/zebra_mpls_vty.c6
-rw-r--r--zebra/zebra_rib.c47
-rw-r--r--zebra/zserv.c60
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);