Skip to content

Commit

Permalink
bgpd: fix hardset l3vpn label available in mpls pool
Browse files Browse the repository at this point in the history
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: ddb5b48 ("bgpd: vpn-vrf route leaking")
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
  • Loading branch information
pguibert6WIND committed Oct 18, 2023
1 parent 1c199f2 commit d162d5f
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 8 deletions.
5 changes: 3 additions & 2 deletions bgpd/bgp_labelpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
20 changes: 20 additions & 0 deletions bgpd/bgp_mplsvpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down Expand Up @@ -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;
}

Expand Down
20 changes: 17 additions & 3 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_AUTO)) {
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) {

/*
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 12 additions & 2 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -3943,7 +3947,13 @@ bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
return false;
}

bgp_lp_event_chunk(start, end);
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;
}
Expand Down
3 changes: 2 additions & 1 deletion bgpd/bgp_zebra.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
2 changes: 2 additions & 0 deletions bgpd/bgpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d162d5f

Please sign in to comment.