Merge pull request #3327 from adeg/feature/bgp-lu-auto-labels

bgpd, zebra: auto assign labels to regular labeled-unicast prefixes
This commit is contained in:
Renato Westphal 2018-12-20 13:59:28 -02:00 committed by GitHub
commit 96def26e5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 214 additions and 55 deletions

View File

@ -120,20 +120,141 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,
return rn->local_label; return rn->local_label;
} }
void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi, /**
int reg) * 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,
bool reg)
{
bool with_label_index = false;
struct stream *s; struct stream *s;
struct prefix *p; struct prefix *p;
mpls_label_t *local_label;
int command; int command;
uint16_t flags = 0; uint16_t flags = 0;
size_t flags_pos = 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. */ /* Check socket. */
if (!zclient || zclient->sock < 0) if (!zclient || zclient->sock < 0)
return; 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; s = zclient->obuf;
stream_reset(s); stream_reset(s);
command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER; command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
@ -143,13 +264,13 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,
stream_putw(s, PREFIX_FAMILY(p)); stream_putw(s, PREFIX_FAMILY(p));
stream_put_prefix(s, p); stream_put_prefix(s, p);
if (reg) { if (reg) {
assert(pi); if (have_label_to_reg) {
if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) { flags |= ZEBRA_FEC_REGISTER_LABEL;
if (pi->attr->label_index != BGP_INVALID_LABEL_INDEX) { stream_putl(s, label_pton(local_label));
} else if (with_label_index) {
flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
stream_putl(s, pi->attr->label_index); stream_putl(s, pi->attr->label_index);
} }
}
SET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); SET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
} else } else
UNSET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); UNSET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);

View File

@ -30,8 +30,10 @@ struct bgp_node;
struct bgp_path_info; struct bgp_path_info;
struct peer; 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, 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 int bgp_parse_fec_update(void);
extern mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi, 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); 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, static inline void bgp_register_for_label(struct bgp_node *rn,
struct bgp_path_info *pi) 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) 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 */ /* Label stream to value */

View File

@ -29,6 +29,7 @@
* Types used in bgp_lp_get for debug tracking; add more as needed * Types used in bgp_lp_get for debug tracking; add more as needed
*/ */
#define LP_TYPE_VRF 0x00000001 #define LP_TYPE_VRF 0x00000001
#define LP_TYPE_BGP_LU 0x00000002
struct labelpool { struct labelpool {
struct skiplist *ledger; /* all requests */ struct skiplist *ledger; /* all requests */

View File

@ -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? /* Do we need to allocate or free labels?
* Right now, since we only deal with per-prefix labels, it is not * 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 * necessary to do this upon changes to best path. Exceptions:
* index changes * - 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 (bgp->allocate_mpls_labels[afi][safi]) {
if (new_select) { if (new_select) {
if (!old_select if (!old_select
|| bgp_label_index_differs(new_select, 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 if (new_select->sub_type == BGP_ROUTE_STATIC
&& new_select->attr->flag || new_select->sub_type
& ATTR_FLAG_BIT( == BGP_ROUTE_AGGREGATE
BGP_ATTR_PREFIX_SID) || new_select->sub_type
&& new_select->attr->label_index == BGP_ROUTE_REDISTRIBUTE) {
!= BGP_INVALID_LABEL_INDEX) {
if (CHECK_FLAG( if (CHECK_FLAG(
rn->flags, rn->flags,
BGP_NODE_REGISTERED_FOR_LABEL)) BGP_NODE_REGISTERED_FOR_LABEL))

View File

@ -58,6 +58,10 @@
#define ZEBRA_IPTABLES_FORWARD 0 #define ZEBRA_IPTABLES_FORWARD 0
#define ZEBRA_IPTABLES_DROP 1 #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 struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len; extern socklen_t zclient_addr_len;

View File

@ -452,9 +452,6 @@ extern const char *zserv_command_string(unsigned int command);
*/ */
#define ZEBRA_FLAG_ONLINK 0x80 #define ZEBRA_FLAG_ONLINK 0x80
/* Zebra FEC flags. */
#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1
#ifndef INADDR_LOOPBACK #ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
#endif #endif

View File

@ -1187,6 +1187,7 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
unsigned short l = 0; unsigned short l = 0;
struct prefix p; struct prefix p;
uint16_t flags; uint16_t flags;
uint32_t label = MPLS_INVALID_LABEL;
uint32_t label_index = MPLS_INVALID_LABEL_INDEX; uint32_t label_index = MPLS_INVALID_LABEL_INDEX;
s = msg; s = msg;
@ -1229,12 +1230,15 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
l += 5; l += 5;
STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen)); STREAM_GET(&p.u.prefix, s, PSIZE(p.prefixlen));
l += 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); STREAM_GETL(s, label_index);
l += 4; 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: stream_failure:

View File

@ -85,6 +85,12 @@ static struct log_ref ferr_zebra_err[] = {
.description = "A client requested a label binding for a new FEC, but Zebra was unable to add the FEC to its internal table.", .description = "A client requested a label binding for a new FEC, but Zebra was unable to add the FEC to its internal table.",
.suggestion = "Notify a developer.", .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, .code = EC_ZEBRA_FEC_RM_FAILED,
.title = "Failed to remove FEC for MPLS client", .title = "Failed to remove FEC for MPLS client",

View File

@ -37,6 +37,7 @@ enum zebra_log_refs {
EC_ZEBRA_DP_INVALID_RC, EC_ZEBRA_DP_INVALID_RC,
EC_ZEBRA_WQ_NONEXISTENT, EC_ZEBRA_WQ_NONEXISTENT,
EC_ZEBRA_FEC_ADD_FAILED, EC_ZEBRA_FEC_ADD_FAILED,
EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
EC_ZEBRA_FEC_RM_FAILED, EC_ZEBRA_FEC_RM_FAILED,
EC_ZEBRA_IRDP_LEN_MISMATCH, EC_ZEBRA_IRDP_LEN_MISMATCH,
EC_ZEBRA_RNH_UNKNOWN_FAMILY, EC_ZEBRA_RNH_UNKNOWN_FAMILY,

View File

@ -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. * 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 * 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 * 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, 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; struct route_table *table;
zebra_fec_t *fec; zebra_fec_t *fec;
char buf[BUFSIZ]; char buf[BUFSIZ];
int new_client; bool new_client;
int label_change = 0; bool label_change = false;
uint32_t old_label; 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))]; table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
if (!table) if (!table)
@ -1832,12 +1837,20 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
if (IS_ZEBRA_DEBUG_MPLS) if (IS_ZEBRA_DEBUG_MPLS)
prefix2str(p, buf, BUFSIZ); 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 */ /* Locate FEC */
fec = fec_find(table, p); fec = fec_find(table, p);
if (!fec) { if (!fec) {
fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index); fec = fec_add(table, p, label, 0, label_index);
if (!fec) { if (!fec) {
prefix2str(p, buf, BUFSIZ);
flog_err( flog_err(
EC_ZEBRA_FEC_ADD_FAILED, EC_ZEBRA_FEC_ADD_FAILED,
"Failed to add FEC %s upon register, client %s", "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; old_label = MPLS_INVALID_LABEL;
new_client = 1; new_client = true;
} else { } 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. */ /* Client may register same FEC with different label index. */
new_client = new_client =
(listnode_lookup(fec->client_list, client) == NULL); (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 */ /* Duplicate register */
return 0; return 0;
/* Save current label, update label index */ /* Save current label, update the FEC */
old_label = fec->label; old_label = fec->label;
fec->label_index = label_index; 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); listnode_add(fec->client_list, client);
if (IS_ZEBRA_DEBUG_MPLS) if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug("FEC %s Label Index %u %s by client %s", buf, zlog_debug("FEC %s label%s %u %s by client %s%s", buf,
label_index, new_client ? "registered" : "updated", have_label_index ? " index" : "",
zebra_route_string(client->proto)); 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 configured FEC, derive the local label (from label index) /* If not a statically configured FEC, derive the local label
* or reset it. * from label index or use the provided label
*/ */
if (!(fec->flags & FEC_FLAG_CONFIGURED)) { if (!is_configured_fec) {
if (have_label_index)
fec_derive_label_from_index(zvrf, fec); fec_derive_label_from_index(zvrf, fec);
else
fec->label = label;
/* If no label change, exit. */ /* If no label change, exit. */
if (fec->label == old_label) if (fec->label == old_label)
return 0; return 0;
label_change = 1; label_change = true;
} }
/* If new client or label change, update client and install or uninstall /* 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) { if (IS_ZEBRA_DEBUG_MPLS) {
prefix2str(p, buf, BUFSIZ); prefix2str(p, buf, BUFSIZ);
zlog_debug("Delete fec %s label index %u", buf, zlog_debug("Delete fec %s label %u label index %u", buf,
fec->label_index); fec->label, fec->label_index);
} }
old_label = fec->label; old_label = fec->label;

View File

@ -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, int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *re); 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, 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 * Deregistration from a client for the label binding for a FEC. The FEC