Skip to content

Commit

Permalink
Merge pull request #3327 from adeg/feature/bgp-lu-auto-labels
Browse files Browse the repository at this point in the history
bgpd, zebra: auto assign labels to regular labeled-unicast prefixes
  • Loading branch information
rwestphal committed Dec 20, 2018
2 parents bbfaa70 + 57592a5 commit 96def26
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 55 deletions.
137 changes: 129 additions & 8 deletions bgpd/bgp_label.c
Expand Up @@ -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;
Expand All @@ -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
Expand Down
8 changes: 5 additions & 3 deletions bgpd/bgp_label.h
Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_labelpool.h
Expand Up @@ -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 */
Expand Down
22 changes: 14 additions & 8 deletions bgpd/bgp_route.c
Expand Up @@ -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))
Expand Down
4 changes: 4 additions & 0 deletions lib/zclient.h
Expand Up @@ -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;

Expand Down
3 changes: 0 additions & 3 deletions lib/zebra.h
Expand Up @@ -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
Expand Down
12 changes: 8 additions & 4 deletions zebra/zapi_msg.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions zebra/zebra_errors.c
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions zebra/zebra_errors.h
Expand Up @@ -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,
Expand Down

0 comments on commit 96def26

Please sign in to comment.