summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Westphal <renato@openbsd.org>2018-12-20 16:59:28 +0100
committerGitHub <noreply@github.com>2018-12-20 16:59:28 +0100
commit96def26e5a2764ebfa3dba13418627451eaba0ce (patch)
treef160bbc733cfa24b088bbb965f1ca34522d3c1b0
parentMerge pull request #3516 from qlyoung/doc-ip-nht-resolve-via-default (diff)
parentbgpd, zebra: auto assign labels from label pool to regular prefixes in BGP la... (diff)
downloadfrr-96def26e5a2764ebfa3dba13418627451eaba0ce.tar.xz
frr-96def26e5a2764ebfa3dba13418627451eaba0ce.zip
Merge pull request #3327 from adeg/feature/bgp-lu-auto-labels
bgpd, zebra: auto assign labels to regular labeled-unicast prefixes
-rw-r--r--bgpd/bgp_label.c137
-rw-r--r--bgpd/bgp_label.h8
-rw-r--r--bgpd/bgp_labelpool.h1
-rw-r--r--bgpd/bgp_route.c22
-rw-r--r--lib/zclient.h4
-rw-r--r--lib/zebra.h3
-rw-r--r--zebra/zapi_msg.c12
-rw-r--r--zebra/zebra_errors.c6
-rw-r--r--zebra/zebra_errors.h1
-rw-r--r--zebra/zebra_mpls.c64
-rw-r--r--zebra/zebra_mpls.h11
11 files changed, 214 insertions, 55 deletions
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index dcaaea686..a219c407d 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -120,20 +120,141 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,
return rn->local_label;
}
+/**
+ * This is passed as the callback function to bgp_labelpool.c:bgp_lp_get()
+ * by bgp_reg_dereg_for_label() when a label needs to be obtained from
+ * label pool.
+ * Note that it will reject the allocated label if a label index is found,
+ * because the label index supposes predictable labels
+ */
+int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
+ bool allocated)
+{
+ struct bgp_path_info *pi = (struct bgp_path_info *)labelid;
+ struct bgp_node *rn = (struct bgp_node *)pi->net;
+ char addr[PREFIX_STRLEN];
+
+ prefix2str(&rn->p, addr, PREFIX_STRLEN);
+
+ if (BGP_DEBUG(labelpool, LABELPOOL))
+ zlog_debug("%s: FEC %s label=%u, allocated=%d", __func__, addr,
+ new_label, allocated);
+
+ if (!allocated) {
+ /*
+ * previously-allocated label is now invalid
+ */
+ if (pi->attr->label_index == MPLS_INVALID_LABEL_INDEX
+ && pi->attr->label != MPLS_LABEL_NONE
+ && CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
+ bgp_unregister_for_label(rn);
+ label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1,
+ &rn->local_label);
+ bgp_set_valid_label(&rn->local_label);
+ }
+ return 0;
+ }
+
+ /*
+ * label index is assigned, this should be handled by SR-related code,
+ * so retry FEC registration and then reject label allocation for
+ * it to be released to label pool
+ */
+ if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) {
+ flog_err(
+ EC_BGP_LABEL,
+ "%s: FEC %s Rejecting allocated label %u as Label Index is %u",
+ __func__, addr, new_label, pi->attr->label_index);
+
+ bgp_register_for_label(pi->net, pi);
+
+ return -1;
+ }
+
+ if (pi->attr->label != MPLS_INVALID_LABEL) {
+ if (new_label == pi->attr->label) {
+ /* already have same label, accept but do nothing */
+ return 0;
+ }
+ /* Shouldn't happen: different label allocation */
+ flog_err(EC_BGP_LABEL,
+ "%s: %s had label %u but got new assignment %u",
+ __func__, addr, pi->attr->label, new_label);
+ /* continue means use new one */
+ }
+
+ label_ntop(new_label, 1, &rn->local_label);
+ bgp_set_valid_label(&rn->local_label);
+
+ /*
+ * Get back to registering the FEC
+ */
+ bgp_register_for_label(pi->net, pi);
+
+ return 0;
+}
+
void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,
- int reg)
+ bool reg)
{
+ bool with_label_index = false;
struct stream *s;
struct prefix *p;
+ mpls_label_t *local_label;
int command;
uint16_t flags = 0;
size_t flags_pos = 0;
+ char addr[PREFIX_STRLEN];
+
+ p = &(rn->p);
+ local_label = &(rn->local_label);
+ /* this prevents the loop when we're called by
+ * bgp_reg_for_label_callback()
+ */
+ bool have_label_to_reg = bgp_is_valid_label(local_label)
+ && label_pton(local_label) != MPLS_LABEL_IMPLICIT_NULL;
+
+ if (reg) {
+ assert(pi);
+ /*
+ * Determine if we will let zebra should derive label from
+ * label index instead of bgpd requesting from label pool
+ */
+ if (CHECK_FLAG(pi->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))
+ && pi->attr->label_index != BGP_INVALID_LABEL_INDEX) {
+ with_label_index = true;
+ } else {
+ /*
+ * If no label index was provided -- assume any label
+ * from label pool will do. This means that label index
+ * always takes precedence over auto-assigned labels.
+ */
+ if (!have_label_to_reg) {
+ if (BGP_DEBUG(labelpool, LABELPOOL)) {
+ prefix2str(p, addr, PREFIX_STRLEN);
+ zlog_debug("%s: Requesting label from LP for %s",
+ __func__, addr);
+ }
+ /* bgp_reg_for_label_callback() will call back
+ * __func__ when it gets a label from the pool.
+ * This means we'll never register FECs without
+ * valid labels.
+ */
+ bgp_lp_get(LP_TYPE_BGP_LU, pi,
+ bgp_reg_for_label_callback);
+ return;
+ }
+ }
+ }
/* Check socket. */
if (!zclient || zclient->sock < 0)
return;
- p = &(rn->p);
+ /* If the route node has a local_label assigned or the
+ * path node has an MPLS SR label index allowing zebra to
+ * derive the label, proceed with registration. */
s = zclient->obuf;
stream_reset(s);
command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
@@ -143,12 +264,12 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,
stream_putw(s, PREFIX_FAMILY(p));
stream_put_prefix(s, p);
if (reg) {
- assert(pi);
- if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
- if (pi->attr->label_index != BGP_INVALID_LABEL_INDEX) {
- flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
- stream_putl(s, pi->attr->label_index);
- }
+ if (have_label_to_reg) {
+ flags |= ZEBRA_FEC_REGISTER_LABEL;
+ stream_putl(s, label_pton(local_label));
+ } else if (with_label_index) {
+ flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+ stream_putl(s, pi->attr->label_index);
}
SET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
} else
diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
index b0fc07e54..89bc9aabb 100644
--- a/bgpd/bgp_label.h
+++ b/bgpd/bgp_label.h
@@ -30,8 +30,10 @@ struct bgp_node;
struct bgp_path_info;
struct peer;
+extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
+ bool allocated);
extern void bgp_reg_dereg_for_label(struct bgp_node *rn,
- struct bgp_path_info *pi, int reg);
+ struct bgp_path_info *pi, bool reg);
extern int bgp_parse_fec_update(void);
extern mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *to, afi_t afi, safi_t safi);
@@ -87,12 +89,12 @@ static inline void bgp_unset_valid_label(mpls_label_t *label)
static inline void bgp_register_for_label(struct bgp_node *rn,
struct bgp_path_info *pi)
{
- bgp_reg_dereg_for_label(rn, pi, 1);
+ bgp_reg_dereg_for_label(rn, pi, true);
}
static inline void bgp_unregister_for_label(struct bgp_node *rn)
{
- bgp_reg_dereg_for_label(rn, NULL, 0);
+ bgp_reg_dereg_for_label(rn, NULL, false);
}
/* Label stream to value */
diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h
index fa35cde0e..0507e6548 100644
--- a/bgpd/bgp_labelpool.h
+++ b/bgpd/bgp_labelpool.h
@@ -29,6 +29,7 @@
* Types used in bgp_lp_get for debug tracking; add more as needed
*/
#define LP_TYPE_VRF 0x00000001
+#define LP_TYPE_BGP_LU 0x00000002
struct labelpool {
struct skiplist *ledger; /* all requests */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 23002fb74..2c361bef4 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2265,20 +2265,26 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
/* 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 except if the label
- * index changes
+ * necessary to do this upon changes to best path. Exceptions:
+ * - label index has changed -> recalculate resulting label
+ * - path_info sub_type changed -> switch to/from implicit-null
+ * - no valid label (due to removed static label binding) -> get new one
*/
if (bgp->allocate_mpls_labels[afi][safi]) {
if (new_select) {
if (!old_select
|| bgp_label_index_differs(new_select, old_select)
- || new_select->sub_type != old_select->sub_type) {
+ || new_select->sub_type != old_select->sub_type
+ || !bgp_is_valid_label(&rn->local_label)) {
+ /* Enforced penultimate hop popping:
+ * implicit-null for local routes, aggregate
+ * and redistributed routes
+ */
if (new_select->sub_type == BGP_ROUTE_STATIC
- && new_select->attr->flag
- & ATTR_FLAG_BIT(
- BGP_ATTR_PREFIX_SID)
- && new_select->attr->label_index
- != BGP_INVALID_LABEL_INDEX) {
+ || new_select->sub_type
+ == BGP_ROUTE_AGGREGATE
+ || new_select->sub_type
+ == BGP_ROUTE_REDISTRIBUTE) {
if (CHECK_FLAG(
rn->flags,
BGP_NODE_REGISTERED_FOR_LABEL))
diff --git a/lib/zclient.h b/lib/zclient.h
index adb48b252..8fe711f31 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -58,6 +58,10 @@
#define ZEBRA_IPTABLES_FORWARD 0
#define ZEBRA_IPTABLES_DROP 1
+/* Zebra FEC register command flags. */
+#define ZEBRA_FEC_REGISTER_LABEL 0x1
+#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2
+
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
diff --git a/lib/zebra.h b/lib/zebra.h
index 0f3f45f7b..09115951e 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -452,9 +452,6 @@ extern const char *zserv_command_string(unsigned int command);
*/
#define ZEBRA_FLAG_ONLINK 0x80
-/* 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/zapi_msg.c b/zebra/zapi_msg.c
index 9b84a6e58..26a3cd5b4 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1187,6 +1187,7 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
unsigned short l = 0;
struct prefix p;
uint16_t flags;
+ uint32_t label = MPLS_INVALID_LABEL;
uint32_t label_index = MPLS_INVALID_LABEL_INDEX;
s = msg;
@@ -1229,12 +1230,15 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
l += 5;
STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
- if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) {
+ if (flags & ZEBRA_FEC_REGISTER_LABEL) {
+ STREAM_GETL(s, label);
+ l += 4;
+ } else if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX) {
STREAM_GETL(s, label_index);
l += 4;
- } else
- label_index = MPLS_INVALID_LABEL_INDEX;
- zebra_mpls_fec_register(zvrf, &p, label_index, client);
+ }
+
+ zebra_mpls_fec_register(zvrf, &p, label, label_index, client);
}
stream_failure:
diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c
index 32f665383..d7c17829c 100644
--- a/zebra/zebra_errors.c
+++ b/zebra/zebra_errors.c
@@ -86,6 +86,12 @@ static struct log_ref ferr_zebra_err[] = {
.suggestion = "Notify a developer.",
},
{
+ .code = EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
+ .title = "Refused to add FEC for MPLS client with both label index and label specified",
+ .description = "A client requested a label binding for a new FEC specifying a label index and a label at the same time.",
+ .suggestion = "Notify a developer.",
+ },
+ {
.code = EC_ZEBRA_FEC_RM_FAILED,
.title = "Failed to remove FEC for MPLS client",
.description = "Zebra was unable to find and remove a FEC in its internal table.",
diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h
index cf2d6a7cf..c3cdc4ed4 100644
--- a/zebra/zebra_errors.h
+++ b/zebra/zebra_errors.h
@@ -37,6 +37,7 @@ enum zebra_log_refs {
EC_ZEBRA_DP_INVALID_RC,
EC_ZEBRA_WQ_NONEXISTENT,
EC_ZEBRA_FEC_ADD_FAILED,
+ EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
EC_ZEBRA_FEC_RM_FAILED,
EC_ZEBRA_IRDP_LEN_MISMATCH,
EC_ZEBRA_RNH_UNKNOWN_FAMILY,
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 5fe011615..c0764cd4b 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -1813,17 +1813,22 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
* NOTE: If there is a manually configured label binding, that is used.
* Otherwise, if a 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.
+ * is acceptable. If no label index then just register the specified label.
+ * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
+ * by the calling function. Register requests with both will be rejected.
*/
int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
- uint32_t label_index, struct zserv *client)
+ uint32_t label, uint32_t label_index,
+ struct zserv *client)
{
struct route_table *table;
zebra_fec_t *fec;
char buf[BUFSIZ];
- int new_client;
- int label_change = 0;
+ bool new_client;
+ bool label_change = false;
uint32_t old_label;
+ bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
+ bool is_configured_fec = false; /* indicate statically configured FEC */
table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
if (!table)
@@ -1832,12 +1837,20 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
if (IS_ZEBRA_DEBUG_MPLS)
prefix2str(p, buf, BUFSIZ);
+ if (label != MPLS_INVALID_LABEL && have_label_index) {
+ flog_err(
+ EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
+ "Rejecting FEC register for %s with both label %u and Label Index %u specified, client %s",
+ buf, label, label_index,
+ zebra_route_string(client->proto));
+ return -1;
+ }
+
/* Locate FEC */
fec = fec_find(table, p);
if (!fec) {
- fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index);
+ fec = fec_add(table, p, label, 0, label_index);
if (!fec) {
- prefix2str(p, buf, BUFSIZ);
flog_err(
EC_ZEBRA_FEC_ADD_FAILED,
"Failed to add FEC %s upon register, client %s",
@@ -1846,16 +1859,19 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
}
old_label = MPLS_INVALID_LABEL;
- new_client = 1;
+ new_client = true;
} else {
+ /* Check if the FEC has been statically defined in the config */
+ is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
/* 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)
+ if (!new_client && fec->label_index == label_index
+ && fec->label == label)
/* Duplicate register */
return 0;
- /* Save current label, update label index */
+ /* Save current label, update the FEC */
old_label = fec->label;
fec->label_index = label_index;
}
@@ -1864,21 +1880,29 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
listnode_add(fec->client_list, client);
if (IS_ZEBRA_DEBUG_MPLS)
- zlog_debug("FEC %s Label Index %u %s by client %s", buf,
- label_index, new_client ? "registered" : "updated",
- zebra_route_string(client->proto));
-
- /* If not a configured FEC, derive the local label (from label index)
- * or reset it.
+ zlog_debug("FEC %s label%s %u %s by client %s%s", buf,
+ have_label_index ? " index" : "",
+ have_label_index ? label_index : label,
+ new_client ? "registered" : "updated",
+ zebra_route_string(client->proto),
+ is_configured_fec
+ ? ", but using statically configured label"
+ : "");
+
+ /* If not a statically configured FEC, derive the local label
+ * from label index or use the provided label
*/
- if (!(fec->flags & FEC_FLAG_CONFIGURED)) {
- fec_derive_label_from_index(zvrf, fec);
+ if (!is_configured_fec) {
+ if (have_label_index)
+ fec_derive_label_from_index(zvrf, fec);
+ else
+ fec->label = label;
/* If no label change, exit. */
if (fec->label == old_label)
return 0;
- label_change = 1;
+ label_change = true;
}
/* If new client or label change, update client and install or uninstall
@@ -2106,8 +2130,8 @@ int 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 label index %u", buf,
- fec->label_index);
+ zlog_debug("Delete fec %s label %u label index %u", buf,
+ fec->label, fec->label_index);
}
old_label = fec->label;
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 86bee129c..c250fc405 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -191,16 +191,9 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *re);
-/*
- * 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,
- uint32_t label_index, struct zserv *client);
+ uint32_t label, uint32_t label_index,
+ struct zserv *client);
/*
* Deregistration from a client for the label binding for a FEC. The FEC