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>
(cherry picked from commit
14eac319e8ae9314f5270f871106a70c4986c60c)
*/
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",
* 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;
}
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
*
int type;
mpls_label_t label;
void *labelid;
+ vrf_id_t vrf_id;
bool allocated; /* false = lost */
};
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",
return WQ_SUCCESS;
}
+ if (!bgp)
+ return WQ_SUCCESS;
+
rc = (*(lcbq->cbfunc))(lcbq->label, lcbq->labelid, lcbq->allocated);
if (lcbq->allocated && rc) {
/*
* 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
new->label = get_label_from_pool(labelid);
new->type = type;
new->labelid = labelid;
+ new->vrf_id = vrf_id;
new->cbfunc = cbfunc;
return new;
* 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;
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);
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 */
q->type = lcb->type;
q->label = lcb->label;
q->labelid = lcb->labelid;
+ q->vrf_id = lcb->vrf_id;
q->allocated = true;
if (debug)
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);
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);
/* 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);
}
{
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;
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);
}