diff options
| author | Vivek Venkatraman <vivek@cumulusnetworks.com> | 2017-03-09 12:55:54 -0500 |
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-04-06 10:32:07 -0400 |
| commit | 28d58fd7b166836029656c29ad8ed9a9e8a744ac (patch) | |
| tree | 549a60873cfe73d04c055447fc599e667cb1d71c /zebra/zebra_mpls.c | |
| parent | 6cf48acc1c17d590da4101fa5e0a2764cb931a9c (diff) | |
bgpd, lib, zebra: Implement handling of BGP-Prefix-SID label Index
Implement BGP Prefix-SID IETF draft to be able to signal a labeled-unicast
prefix with a label index (segment ID). This makes it easier to deploy
global MPLS labels with BGP, even without other aspects of Segment Routing
implemented.
This patch implements the handling of the BGP-Prefix-SID Label Index
attribute. When received from a peer and the index is acceptable, the local
label is picked up from the SRGB and is programmed as the incoming label as
well as advertised to peers. If the index is not acceptable, no local label
is assigned. The outgoing label will always be the one advertised by the
downstream neighbor.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Diffstat (limited to 'zebra/zebra_mpls.c')
| -rw-r--r-- | zebra/zebra_mpls.c | 176 |
1 files changed, 163 insertions, 13 deletions
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; } |
