mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-19 17:03:19 +00:00
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:
commit
96def26e5a
139
bgpd/bgp_label.c
139
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user