mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-23 10:13:51 +00:00
bgpd: Fix crash in bgp_labelpool
The bgp labelpool code is grabbing the vpn policy data structure. This vpn_policy has a pointer to the bgp data structure. If a item placed on the bgp label pool workqueue happens to sit there for the microsecond or so and the operator issues a `no router bgp...` command that corresponds to the vpn_policy bgp pointer, when the workqueue is run it will crash because the bgp pointer is now freed and something else owns it. Modify the labelpool code to store the vrf id associated with the request on the workqueue. When you wake up if the vrf id still has a bgp pointer allow the request to continue, else drop it. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
This commit is contained in:
parent
baf4c1a78f
commit
14eac319e8
@ -387,6 +387,8 @@ void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi,
|
||||
*/
|
||||
if (!have_label_to_reg) {
|
||||
SET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
|
||||
struct bgp_table *table;
|
||||
|
||||
if (BGP_DEBUG(labelpool, LABELPOOL))
|
||||
zlog_debug(
|
||||
"%s: Requesting label from LP for %pFX",
|
||||
@ -396,7 +398,9 @@ void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi,
|
||||
* the pool. This means we'll never register
|
||||
* FECs withoutvalid labels.
|
||||
*/
|
||||
bgp_lp_get(LP_TYPE_BGP_LU, dest,
|
||||
table = bgp_dest_table(dest);
|
||||
|
||||
bgp_lp_get(LP_TYPE_BGP_LU, dest, table->bgp->vrf_id,
|
||||
bgp_reg_for_label_callback);
|
||||
return;
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ struct lp_lcb {
|
||||
mpls_label_t label; /* MPLS_LABEL_NONE = not allocated */
|
||||
int type;
|
||||
void *labelid; /* unique ID */
|
||||
vrf_id_t vrf_id;
|
||||
/*
|
||||
* callback for label allocation and loss
|
||||
*
|
||||
@ -97,6 +98,7 @@ struct lp_cbq_item {
|
||||
int type;
|
||||
mpls_label_t label;
|
||||
void *labelid;
|
||||
vrf_id_t vrf_id;
|
||||
bool allocated; /* false = lost */
|
||||
};
|
||||
|
||||
@ -105,6 +107,7 @@ static wq_item_status lp_cbq_docallback(struct work_queue *wq, void *data)
|
||||
struct lp_cbq_item *lcbq = data;
|
||||
int rc;
|
||||
int debug = BGP_DEBUG(labelpool, LABELPOOL);
|
||||
struct bgp *bgp = bgp_lookup_by_vrf_id(lcbq->vrf_id);
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%s: calling callback with labelid=%p label=%u allocated=%d",
|
||||
@ -117,6 +120,9 @@ static wq_item_status lp_cbq_docallback(struct work_queue *wq, void *data)
|
||||
return WQ_SUCCESS;
|
||||
}
|
||||
|
||||
if (!bgp)
|
||||
return WQ_SUCCESS;
|
||||
|
||||
rc = (*(lcbq->cbfunc))(lcbq->label, lcbq->labelid, lcbq->allocated);
|
||||
|
||||
if (lcbq->allocated && rc) {
|
||||
@ -320,10 +326,8 @@ static mpls_label_t get_label_from_pool(void *labelid)
|
||||
/*
|
||||
* Success indicated by value of "label" field in returned LCB
|
||||
*/
|
||||
static struct lp_lcb *lcb_alloc(
|
||||
int type,
|
||||
void *labelid,
|
||||
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated))
|
||||
static struct lp_lcb *lcb_alloc(int type, void *labelid, vrf_id_t vrf_id,
|
||||
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated))
|
||||
{
|
||||
/*
|
||||
* Set up label control block
|
||||
@ -334,6 +338,7 @@ static struct lp_lcb *lcb_alloc(
|
||||
new->label = get_label_from_pool(labelid);
|
||||
new->type = type;
|
||||
new->labelid = labelid;
|
||||
new->vrf_id = vrf_id;
|
||||
new->cbfunc = cbfunc;
|
||||
|
||||
return new;
|
||||
@ -365,10 +370,8 @@ static struct lp_lcb *lcb_alloc(
|
||||
* Prior requests for a given labelid are detected so that requests and
|
||||
* assignments are not duplicated.
|
||||
*/
|
||||
void bgp_lp_get(
|
||||
int type,
|
||||
void *labelid,
|
||||
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated))
|
||||
void bgp_lp_get(int type, void *labelid, vrf_id_t vrf_id,
|
||||
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated))
|
||||
{
|
||||
struct lp_lcb *lcb;
|
||||
int requested = 0;
|
||||
@ -383,7 +386,7 @@ void bgp_lp_get(
|
||||
if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
|
||||
requested = 1;
|
||||
} else {
|
||||
lcb = lcb_alloc(type, labelid, cbfunc);
|
||||
lcb = lcb_alloc(type, labelid, vrf_id, cbfunc);
|
||||
if (debug)
|
||||
zlog_debug("%s: inserting lcb=%p label=%u",
|
||||
__func__, lcb, lcb->label);
|
||||
@ -413,6 +416,7 @@ void bgp_lp_get(
|
||||
q->type = lcb->type;
|
||||
q->label = lcb->label;
|
||||
q->labelid = lcb->labelid;
|
||||
q->vrf_id = lcb->vrf_id;
|
||||
q->allocated = true;
|
||||
|
||||
/* if this is a LU request, lock node before queueing */
|
||||
@ -580,6 +584,7 @@ static void bgp_sync_label_manager(struct event *e)
|
||||
q->type = lcb->type;
|
||||
q->label = lcb->label;
|
||||
q->labelid = lcb->labelid;
|
||||
q->vrf_id = lcb->vrf_id;
|
||||
q->allocated = true;
|
||||
|
||||
if (debug)
|
||||
@ -693,6 +698,7 @@ void bgp_lp_event_zebra_up(void)
|
||||
q->type = lcb->type;
|
||||
q->label = lcb->label;
|
||||
q->labelid = lcb->labelid;
|
||||
q->vrf_id = lcb->vrf_id;
|
||||
q->allocated = false;
|
||||
check_bgp_lu_cb_lock(lcb);
|
||||
work_queue_add(lp->callback_q, q);
|
||||
|
@ -35,8 +35,8 @@ struct labelpool {
|
||||
|
||||
extern void bgp_lp_init(struct event_loop *master, struct labelpool *pool);
|
||||
extern void bgp_lp_finish(void);
|
||||
extern void bgp_lp_get(int type, void *labelid,
|
||||
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated));
|
||||
extern void bgp_lp_get(int type, void *labelid, vrf_id_t vrf_id,
|
||||
int (*cbfunc)(mpls_label_t label, void *labelid, bool allocated));
|
||||
extern void bgp_lp_release(int type, void *labelid, mpls_label_t label);
|
||||
extern void bgp_lp_event_chunk(uint32_t first, uint32_t last);
|
||||
extern void bgp_lp_event_zebra_down(void);
|
||||
|
@ -1450,7 +1450,7 @@ _vpn_leak_from_vrf_get_per_nexthop_label(struct bgp_path_info *pi,
|
||||
/* request a label to zebra for this nexthop
|
||||
* the response from zebra will trigger the callback
|
||||
*/
|
||||
bgp_lp_get(LP_TYPE_NEXTHOP, blnc,
|
||||
bgp_lp_get(LP_TYPE_NEXTHOP, blnc, from_bgp->vrf_id,
|
||||
bgp_mplsvpn_get_label_per_nexthop_cb);
|
||||
}
|
||||
|
||||
@ -1490,7 +1490,8 @@ static mpls_label_t bgp_mplsvpn_get_vpn_label(struct vpn_policy *bgp_policy)
|
||||
{
|
||||
if (bgp_policy->tovpn_label == MPLS_LABEL_NONE &&
|
||||
CHECK_FLAG(bgp_policy->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
|
||||
bgp_lp_get(LP_TYPE_VRF, bgp_policy, vpn_leak_label_callback);
|
||||
bgp_lp_get(LP_TYPE_VRF, bgp_policy, bgp_policy->bgp->vrf_id,
|
||||
vpn_leak_label_callback);
|
||||
return MPLS_INVALID_LABEL;
|
||||
}
|
||||
return bgp_policy->tovpn_label;
|
||||
@ -4387,7 +4388,7 @@ void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp,
|
||||
label);
|
||||
bmnc->bgp_vpn = bgp;
|
||||
bmnc->allocation_in_progress = true;
|
||||
bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc,
|
||||
bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc, bgp->vrf_id,
|
||||
bgp_mplsvpn_nh_label_bind_get_local_label_cb);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user