summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_label.c27
-rw-r--r--bgpd/bgp_label.h9
-rw-r--r--bgpd/bgp_route.c46
-rw-r--r--lib/mpls.h5
-rw-r--r--lib/zebra.h3
-rw-r--r--zebra/zebra_mpls.c176
-rw-r--r--zebra/zebra_mpls.h11
-rw-r--r--zebra/zebra_mpls_null.c2
-rw-r--r--zebra/zserv.c12
9 files changed, 250 insertions, 41 deletions
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index e2c4a54044..0c331c5d59 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -125,11 +125,14 @@ bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to,
}
void
-bgp_reg_dereg_for_label (struct bgp_node *rn, int reg)
+bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+ int reg)
{
struct stream *s;
struct prefix *p;
int command;
+ u_int16_t flags = 0;
+ size_t flags_pos = 0;
/* Check socket. */
if (!zclient || zclient->sock < 0)
@@ -140,17 +143,29 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, int reg)
stream_reset (s);
command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
zclient_create_header (s, command, VRF_DEFAULT);
+ flags_pos = stream_get_endp (s); /* save position of 'flags' */
+ stream_putw(s, flags); /* initial flags */
stream_putw(s, PREFIX_FAMILY(p));
stream_put_prefix(s, p);
- stream_putw_at (s, 0, stream_get_endp (s));
-
if (reg)
- SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+ {
+ assert (ri);
+ if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ {
+ assert (ri->attr->extra);
+ flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+ stream_putl (s, ri->attr->extra->label_index);
+ }
+ SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+ }
else
UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
- zclient_send_message(zclient);
- return;
+ /* Set length and flags */
+ stream_putw_at (s, 0, stream_get_endp (s));
+ stream_putw_at (s, flags_pos, flags);
+
+ zclient_send_message(zclient);
}
static int
diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
index a7e7d5c47b..49a7b945ab 100644
--- a/bgpd/bgp_label.h
+++ b/bgpd/bgp_label.h
@@ -30,7 +30,8 @@ struct bgp_node;
struct bgp_info;
struct peer;
-extern void bgp_reg_dereg_for_label (struct bgp_node *rn, int reg);
+extern void bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+ int reg);
extern int bgp_parse_fec_update(void);
extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri,
struct peer *to, afi_t afi, safi_t safi);
@@ -84,15 +85,15 @@ bgp_unset_valid_label (u_char *t)
}
static inline void
-bgp_register_for_label (struct bgp_node *rn)
+bgp_register_for_label (struct bgp_node *rn, struct bgp_info *ri)
{
- bgp_reg_dereg_for_label (rn, 1);
+ bgp_reg_dereg_for_label (rn, ri, 1);
}
static inline void
bgp_unregister_for_label (struct bgp_node *rn)
{
- bgp_reg_dereg_for_label (rn, 0);
+ bgp_reg_dereg_for_label (rn, NULL, 0);
}
/* Label stream to value */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 451b54edab..b016122a7f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -298,6 +298,20 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
}
}
+static int
+bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2)
+{
+ u_int32_t ri1_label_index = BGP_INVALID_LABEL_INDEX;
+ u_int32_t ri2_label_index = BGP_INVALID_LABEL_INDEX;
+
+ if (ri1->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ ri1_label_index = ri1->attr->extra->label_index;
+
+ if (ri2->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ ri2_label_index = ri2->attr->extra->label_index;
+
+ return (!(ri1_label_index == ri2_label_index));
+}
/* Set/unset bgp_info flags, adjusting any other state as needed.
* This is here primarily to keep prefix-count in check.
@@ -1908,7 +1922,6 @@ bgp_process_main (struct work_queue *wq, void *data)
struct bgp_info *new_select;
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
- int label_valid;
/* Is it end of initial update? (after startup) */
if (!rn)
@@ -1935,28 +1948,31 @@ bgp_process_main (struct work_queue *wq, void *data)
/* Do we need to allocate or free labels?
* Right now, since we only deal with per-prefix labels, it is not necessary
- * to do this upon changes to best path.
+ * to do this upon changes to best path except of the label index changes.
*/
bgp_table_lock (bgp_node_table (rn));
if (bgp_labeled_safi (safi))
{
- label_valid = bgp_is_valid_label (rn->local_label);
- if (!old_select && new_select && !label_valid)
+ if (new_select)
{
- if (new_select->sub_type == BGP_ROUTE_STATIC &&
- new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ if (!old_select ||
+ bgp_label_index_differs (new_select, old_select) ||
+ new_select->sub_type != old_select->sub_type)
{
- label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
- bgp_set_valid_label(rn->local_label);
+ if (new_select->sub_type == BGP_ROUTE_STATIC &&
+ new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+ {
+ if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+ bgp_unregister_for_label (rn);
+ label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
+ bgp_set_valid_label(rn->local_label);
+ }
+ else
+ bgp_register_for_label (rn, new_select);
}
- else
- bgp_register_for_label (rn);
- }
- else if (old_select && !new_select)
- {
- if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
- bgp_unregister_for_label (rn);
}
+ else if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+ bgp_unregister_for_label (rn);
}
/* If best route remains the same and this is not due to user-initiated
diff --git a/lib/mpls.h b/lib/mpls.h
index 5a91883753..f4f360c957 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -123,6 +123,11 @@ mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label,
*ttl = MPLS_LABEL_TTL(local_lse);
}
+/* Invalid label index value (when used with BGP Prefix-SID). Should
+ * match the BGP definition.
+ */
+#define MPLS_INVALID_LABEL_INDEX 0xFFFFFFFF
+
/* Printable string for labels (with consideration for reserved values). */
static inline char *
diff --git a/lib/zebra.h b/lib/zebra.h
index ef261eedc1..cd72dc67f8 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -393,6 +393,9 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
+/* Zebra FEC flags. */
+#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1
+
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
#endif
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 85ce147d25..42738f8fb9 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -60,6 +60,10 @@ extern struct zebra_t zebrad;
/* static function declarations */
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add);
+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 rib *rib);
@@ -77,7 +81,7 @@ 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 flags, u_int32_t label_index);
static int
fec_del (zebra_fec_t *fec);
@@ -353,6 +357,84 @@ lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label)
}
/*
+ * This function is invoked upon change to label block configuration; it
+ * 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, int add)
+{
+ 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++)
+ {
+ 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;
+ if (add)
+ {
+ new_label = zvrf->mpls_srgb.start_label + fec->label_index;
+ if (new_label >= zvrf->mpls_srgb.end_label)
+ new_label = MPLS_INVALID_LABEL;
+ }
+ else
+ 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 %s",
+ buf, new_label, add ? "ADD" : "DEL");
+
+ fec->label = new_label;
+ fec_update_clients (fec);
+
+ /* Update label forwarding entries appropriately */
+ fec_change_update_lsp (zvrf, fec, old_label);
+ }
+ }
+}
+
+/*
+ * Derive (if possible) and update the local label for the FEC based on
+ * 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)
+{
+ 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;
+
+ return fec->label;
+}
+
+/*
* There is a change for this FEC. Install or uninstall label forwarding
* entries, as appropriate.
*/
@@ -457,6 +539,8 @@ fec_print (zebra_fec_t *fec, struct vty *vty)
prefix2str(&rn->p, buf, BUFSIZ);
vty_out(vty, "%s%s", buf, VTY_NEWLINE);
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, "%s", VTY_NEWLINE);
if (!list_isempty(fec->client_list))
{
@@ -491,7 +575,7 @@ 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)
+ mpls_label_t label, u_int32_t flags, u_int32_t label_index)
{
struct route_node *rn;
zebra_fec_t *fec;
@@ -519,6 +603,7 @@ fec_add (struct route_table *table, struct prefix *p,
else
route_unlock_node (rn); /* for the route_node_get */
+ fec->label_index = label_index;
fec->flags = flags;
return fec;
@@ -1743,14 +1828,21 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct
/*
* Registration from a client for the label binding for a FEC. If a binding
* already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * 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,
- struct zserv *client)
+ 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)
@@ -1763,7 +1855,7 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
fec = fec_find (table, p);
if (!fec)
{
- fec = fec_add (table, p, MPLS_INVALID_LABEL, 0);
+ fec = fec_add (table, p, MPLS_INVALID_LABEL, 0, label_index);
if (!fec)
{
prefix2str(p, buf, BUFSIZ);
@@ -1771,27 +1863,60 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
buf, zebra_route_string(client->proto));
return -1;
}
+
+ old_label = MPLS_INVALID_LABEL;
+ new_client = 1;
}
else
{
- if (listnode_lookup(fec->client_list, client))
+ /* 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;
}
- listnode_add (fec->client_list, client);
+ if (new_client)
+ listnode_add (fec->client_list, client);
if (IS_ZEBRA_DEBUG_MPLS)
- zlog_debug("FEC %s registered by client %s",
- buf, zebra_route_string(client->proto));
+ 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;
- if (fec->label != MPLS_INVALID_LABEL)
+ 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;
}
@@ -1830,8 +1955,17 @@ zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
zlog_debug("FEC %s unregistered by client %s",
buf, zebra_route_string(client->proto));
- if (list_isempty(fec->client_list) && (fec->label == MPLS_INVALID_LABEL))
- fec_del (fec);
+ /* 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;
}
@@ -1943,7 +2077,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
fec = fec_find (table, p);
if (!fec)
{
- fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED);
+ fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED,
+ MPLS_INVALID_LABEL_INDEX);
if (!fec)
{
prefix2str(p, buf, BUFSIZ);
@@ -1979,6 +2114,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
/*
* Remove static FEC to label binding. If there are no clients registered
* for this FEC, delete the FEC; else notify clients
+ * 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)
@@ -2003,7 +2140,8 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
if (IS_ZEBRA_DEBUG_MPLS)
{
prefix2str(p, buf, BUFSIZ);
- zlog_debug ("Delete fec %s", buf);
+ zlog_debug ("Delete fec %s label index %u",
+ buf, fec->label_index);
}
old_label = fec->label;
@@ -2017,6 +2155,12 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
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 */
@@ -2744,6 +2888,9 @@ zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_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, 1);
return 0;
}
@@ -2755,6 +2902,9 @@ zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
{
zvrf->mpls_srgb.start_label = 0;
zvrf->mpls_srgb.end_label = 0;
+
+ /* Process registered FECs to clear their local label, if needed. */
+ fec_evaluate (zvrf, 0);
return 0;
}
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index f8e95fa100..e271edd2eb 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -159,6 +159,9 @@ struct zebra_fec_t_
/* In-label - either statically bound or derived from label block. */
mpls_label_t label;
+ /* Label index (into global label block), if valid */
+ u_int32_t label_index;
+
/* Flags. */
u_int32_t flags;
#define FEC_FLAG_CONFIGURED (1 << 0)
@@ -217,10 +220,14 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct
/*
* Registration from a client for the label binding for a FEC. If a binding
* already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * 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,
- struct zserv *client);
+ u_int32_t label_index, struct zserv *client);
/*
* Deregistration from a client for the label binding for a FEC. The FEC
@@ -265,6 +272,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
/*
* Remove static FEC to label binding. If there are no clients registered
* for this FEC, delete the FEC; else notify clients.
+ * 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);
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
index 12176c024e..6b0a91de02 100644
--- a/zebra/zebra_mpls_null.c
+++ b/zebra/zebra_mpls_null.c
@@ -175,7 +175,7 @@ zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
int
zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
- struct zserv *client)
+ u_int32_t label_index, struct zserv *client)
{
return 0;
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index c11f1bf3fd..7c8e6de765 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -942,6 +942,8 @@ zserv_fec_register (struct zserv *client, int sock, u_short length)
struct zebra_vrf *zvrf;
u_short l = 0;
struct prefix p;
+ u_int16_t flags;
+ u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
s = client->ibuf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -950,12 +952,18 @@ zserv_fec_register (struct zserv *client, int sock, u_short length)
while (l < length)
{
+ flags = stream_getw(s);
p.family = stream_getw(s);
p.prefixlen = stream_getc(s);
l += 5;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
- zebra_mpls_fec_register (zvrf, &p, client);
+ if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX)
+ {
+ label_index = stream_getl(s);
+ l += 4;
+ }
+ zebra_mpls_fec_register (zvrf, &p, label_index, client);
}
return 0;
@@ -969,6 +977,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length)
struct zebra_vrf *zvrf;
u_short l = 0;
struct prefix p;
+ u_int16_t flags;
s = client->ibuf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -977,6 +986,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length)
while (l < length)
{
+ flags = stream_getw(s);
p.family = stream_getw(s);
p.prefixlen = stream_getc(s);
l += 5;