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;
}
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 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

View File

@ -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 */

View File

@ -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 */

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?
* 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))

View File

@ -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;

View File

@ -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

View File

@ -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:

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.",
.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",

View File

@ -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,

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.
* 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));
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 configured FEC, derive the local label (from label index)
* or reset it.
/* 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;

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,
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