bgpd: fix hardset l3vpn label available in mpls pool

Today, when configuring BGP L3VPN mpls, the operator may
use that command to hardset a label value:

> router bgp 65500 vrf vrf1
> address-family ipv4 unicast
> label vpn export <hardset_label_value>

Today, BGP uses this value without checks, leading to potential
conflicts with other control planes like LDP. For instance, if
LDP initiates with a label chunk of [16;72] and BGP also uses the
50 label value, a conflict arises.

The 'label manager' service in zebra oversees label allocations.
While all the control plane daemons use it, BGP doesn't when a
hardset label is in place.

This update fixes this problem. Now, when a hardset label is set for
l3vpn export, a request is made to the label manager for approval,
ensuring no conflicts with other daemons. But, this means some existing
BGP configurations might become non-operational if they conflict with
labels already allocated to another daemon but not used.

note: Labels below 16 are reserved and won't be checked for consistency
by the label manager.

Fixes: ddb5b4880b ("bgpd: vpn-vrf route leaking")
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2023-09-01 17:14:06 +02:00
parent 1c199f219d
commit d162d5f6f5
6 changed files with 56 additions and 8 deletions

View file

@ -448,7 +448,7 @@ void bgp_lp_get(
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY,
lp->next_chunksize))
lp->next_chunksize, true))
return;
lp->pending_count += lp->next_chunksize;
@ -650,7 +650,8 @@ void bgp_lp_event_zebra_up(void)
*/
list_delete_all_node(lp->chunks);
if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, labels_needed))
if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, labels_needed,
true))
return;
lp->pending_count = labels_needed;

View file

@ -13,6 +13,7 @@
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_label.h"
#define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
#define MPLS_LABEL_IS_NULL(label) \
@ -165,6 +166,25 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
return 0;
}
/* Is there a "manual" export label that isn't allocated yet? */
if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
bgp_vrf->vpn_policy[afi].tovpn_label != BGP_PREVENT_VRF_2_VRF_LEAK &&
bgp_vrf->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE &&
(bgp_vrf->vpn_policy[afi].tovpn_label >= MPLS_LABEL_UNRESERVED_MIN &&
!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG))) {
if (!bgp_zebra_request_label_range(bgp_vrf->vpn_policy[afi]
.tovpn_label,
1, false)) {
if (pmsg)
*pmsg = "manual label could not be allocated";
return 0;
}
SET_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG);
}
return 1;
}

View file

@ -9471,9 +9471,16 @@ DEFPY (af_label_vpn_export,
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
/* release any previous auto label */
if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG)) {
bgp_zebra_release_label_range(bgp->vpn_policy[afi].tovpn_label,
bgp->vpn_policy[afi].tovpn_label);
UNSET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG);
} else if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
/* release any previous auto label */
if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) {
/*
@ -9501,9 +9508,16 @@ DEFPY (af_label_vpn_export,
bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi],
vpn_leak_label_callback);
} else {
bgp->vpn_policy[afi].tovpn_label = label;
UNSET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
bgp->vpn_policy[afi].tovpn_label = label;
if (bgp->vpn_policy[afi].tovpn_label >=
MPLS_LABEL_UNRESERVED_MIN &&
bgp_zebra_request_label_range(bgp->vpn_policy[afi]
.tovpn_label,
1, false))
SET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG);
}
} else {
UNSET_FLAG(bgp->vpn_policy[afi].flags,

View file

@ -3423,6 +3423,9 @@ static bool bgp_zebra_label_manager_connect(void)
/* tell label pool that zebra is connected */
bgp_lp_event_zebra_up();
/* tell BGP L3VPN that label manager is available */
if (bgp_get_default())
vpn_leak_postchange_all();
return true;
}
@ -3921,7 +3924,8 @@ void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
zebra_send_mpls_labels(zclient, cmd, &zl);
}
bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size,
bool label_auto)
{
int ret;
uint32_t start, end;
@ -3943,6 +3947,12 @@ bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
return false;
}
if (label_auto)
/* label automatic is serviced by the bgp label pool
* manager, which allocates label chunks in
* pre-pools, and which needs to be notified about
* new chunks availability
*/
bgp_lp_event_chunk(start, end);
return true;

View file

@ -124,6 +124,7 @@ extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
enum lsp_types_t ltype,
struct prefix *p, uint32_t num_labels,
mpls_label_t out_labels[]);
extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size,
bool label_auto);
extern void bgp_zebra_release_label_range(uint32_t start, uint32_t end);
#endif /* _QUAGGA_BGP_ZEBRA_H */

View file

@ -217,6 +217,8 @@ struct vpn_policy {
#define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET (1 << 2)
#define BGP_VPN_POLICY_TOVPN_SID_AUTO (1 << 3)
#define BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP (1 << 4)
/* Manual label is registered with zebra label manager */
#define BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG (1 << 5)
/*
* If we are importing another vrf into us keep a list of