X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=bgpd%2Fbgp_labelpool.c;h=feda0328bd5af13228421d60914f716df65f9d71;hb=fbace230b0047d8f7cda2642a7fcaa64bcf1dc1a;hp=7a7a400278ada435753ef474785558a62c28b0c6;hpb=e8275c22b4c5dd5a6ff4a66befb61646e787ed0c;p=mirror_frr.git diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 7a7a40027..feda0328b 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -25,16 +25,17 @@ #include "stream.h" #include "mpls.h" #include "vty.h" -#include "fifo.h" #include "linklist.h" #include "skiplist.h" #include "workqueue.h" #include "zclient.h" +#include "mpls.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_labelpool.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_errors.h" +#include "bgpd/bgp_route.h" /* * Definitions and external declarations. @@ -50,34 +51,10 @@ static struct labelpool *lp; #define LP_CHUNK_SIZE 50 DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk") -DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO") +DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item") DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment") DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback") -#define LABEL_FIFO_ADD(F, N) \ - do { \ - FIFO_ADD((F), (N)); \ - (F)->count++; \ - } while (0) - -#define LABEL_FIFO_DEL(F, N) \ - do { \ - FIFO_DEL((N)); \ - (F)->count--; \ - } while (0) - -#define LABEL_FIFO_INIT(F) \ - do { \ - FIFO_INIT((F)); \ - (F)->count = 0; \ - } while (0) - -#define LABEL_FIFO_COUNT(F) ((F)->count) - -#define LABEL_FIFO_EMPTY(F) FIFO_EMPTY(F) - -#define LABEL_FIFO_HEAD(F) ((F)->next == (F) ? NULL : (F)->next) - struct lp_chunk { uint32_t first; uint32_t last; @@ -98,15 +75,13 @@ struct lp_lcb { int (*cbfunc)(mpls_label_t label, void *lblid, bool alloc); }; -/* XXX same first elements as "struct fifo" */ struct lp_fifo { - struct lp_fifo *next; - struct lp_fifo *prev; - - uint32_t count; + struct lp_fifo_item fifo; struct lp_lcb lcb; }; +DECLARE_LIST(lp_fifo, struct lp_fifo, fifo) + struct lp_cbq_item { int (*cbfunc)(mpls_label_t label, void *lblid, bool alloc); int type; @@ -180,14 +155,12 @@ static void lp_cbq_item_free(struct work_queue *wq, void *data) static void lp_lcb_free(void *goner) { - if (goner) - XFREE(MTYPE_BGP_LABEL_CB, goner); + XFREE(MTYPE_BGP_LABEL_CB, goner); } static void lp_chunk_free(void *goner) { - if (goner) - XFREE(MTYPE_BGP_LABEL_CHUNK, goner); + XFREE(MTYPE_BGP_LABEL_CHUNK, goner); } void bgp_lp_init(struct thread_master *master, struct labelpool *pool) @@ -201,8 +174,7 @@ void bgp_lp_init(struct thread_master *master, struct labelpool *pool) lp->inuse = skiplist_new(0, NULL, NULL); lp->chunks = list_new(); lp->chunks->del = lp_chunk_free; - lp->requests = XCALLOC(MTYPE_BGP_LABEL_FIFO, sizeof(struct lp_fifo)); - LABEL_FIFO_INIT(lp->requests); + lp_fifo_init(&lp->requests); lp->callback_q = work_queue_new(master, "label callbacks"); lp->callback_q->spec.workfunc = lp_cbq_docallback; @@ -210,9 +182,24 @@ void bgp_lp_init(struct thread_master *master, struct labelpool *pool) lp->callback_q->spec.max_retries = 0; } +/* check if a label callback was for a BGP LU path, and if so, unlock it */ +static void check_bgp_lu_cb_unlock(struct lp_lcb *lcb) +{ + if (lcb->type == LP_TYPE_BGP_LU) + bgp_path_info_unlock(lcb->labelid); +} + +/* check if a label callback was for a BGP LU path, and if so, lock it */ +static void check_bgp_lu_cb_lock(struct lp_lcb *lcb) +{ + if (lcb->type == LP_TYPE_BGP_LU) + bgp_path_info_lock(lcb->labelid); +} + void bgp_lp_finish(void) { struct lp_fifo *lf; + struct work_queue_item *item, *titem; if (!lp) return; @@ -223,15 +210,22 @@ void bgp_lp_finish(void) skiplist_free(lp->inuse); lp->inuse = NULL; - list_delete_and_null(&lp->chunks); + list_delete(&lp->chunks); - while ((lf = LABEL_FIFO_HEAD(lp->requests))) { - - LABEL_FIFO_DEL(lp->requests, lf); + while ((lf = lp_fifo_pop(&lp->requests))) { + check_bgp_lu_cb_unlock(&lf->lcb); XFREE(MTYPE_BGP_LABEL_FIFO, lf); } - XFREE(MTYPE_BGP_LABEL_FIFO, lp->requests); - lp->requests = NULL; + lp_fifo_fini(&lp->requests); + + /* we must unlock path infos for LU callbacks; but we cannot do that + * in the deletion callback of the workqueue, as that is also called + * to remove an element from the queue after it has been run, resulting + * in a double unlock. Hence we need to iterate over our queues and + * lists and manually perform the unlocking (ugh) + */ + STAILQ_FOREACH_SAFE (item, &lp->callback_q->items, wq, titem) + check_bgp_lu_cb_unlock(item->data); work_queue_free_and_null(&lp->callback_q); @@ -362,6 +356,9 @@ void bgp_lp_get( q->labelid = lcb->labelid; q->allocated = true; + /* if this is a LU request, lock path info before queueing */ + check_bgp_lu_cb_lock(lcb); + work_queue_add(lp->callback_q, q); return; @@ -387,13 +384,17 @@ void bgp_lp_get( sizeof(struct lp_fifo)); lf->lcb = *lcb; - LABEL_FIFO_ADD(lp->requests, lf); + /* if this is a LU request, lock path info before queueing */ + check_bgp_lu_cb_lock(lcb); - if (LABEL_FIFO_COUNT(lp->requests) > lp->pending_count) { - if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE)) { - lp->pending_count += LP_CHUNK_SIZE; + lp_fifo_add_tail(&lp->requests, lf); + + if (lp_fifo_count(&lp->requests) > lp->pending_count) { + if (!zclient || zclient->sock < 0) return; - } + if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE, + MPLS_LABEL_BASE_ANY)) + lp->pending_count += LP_CHUNK_SIZE; } } @@ -443,11 +444,11 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) lp->pending_count -= (last - first + 1); if (debug) { - zlog_debug("%s: %u pending requests", __func__, - LABEL_FIFO_COUNT(lp->requests)); + zlog_debug("%s: %zu pending requests", __func__, + lp_fifo_count(&lp->requests)); } - while ((lf = LABEL_FIFO_HEAD(lp->requests))) { + while ((lf = lp_fifo_first(&lp->requests))) { struct lp_lcb *lcb; void *labelid = lf->lcb.labelid; @@ -470,6 +471,10 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) __func__, labelid, lcb->label, lcb->label, lcb); } + /* if this was a BGP_LU request, unlock path info node + */ + check_bgp_lu_cb_unlock(lcb); + goto finishedrequest; } @@ -506,7 +511,7 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) work_queue_add(lp->callback_q, q); finishedrequest: - LABEL_FIFO_DEL(lp->requests, lf); + lp_fifo_del(&lp->requests, lf); XFREE(MTYPE_BGP_LABEL_FIFO, lf); } } @@ -530,18 +535,27 @@ void bgp_lp_event_zebra_up(void) int chunks_needed; void *labelid; struct lp_lcb *lcb; + int lm_init_ok; /* * Get label chunk allocation request dispatched to zebra */ - labels_needed = LABEL_FIFO_COUNT(lp->requests) + + labels_needed = lp_fifo_count(&lp->requests) + skiplist_count(lp->inuse); /* round up */ chunks_needed = (labels_needed / LP_CHUNK_SIZE) + 1; labels_needed = chunks_needed * LP_CHUNK_SIZE; - zclient_send_get_label_chunk(zclient, 0, labels_needed); + lm_init_ok = lm_label_manager_connect(zclient, 1) == 0; + + if (!lm_init_ok) { + zlog_err("%s: label manager connection error", __func__); + return; + } + + zclient_send_get_label_chunk(zclient, 0, labels_needed, + MPLS_LABEL_BASE_ANY); lp->pending_count = labels_needed; /* @@ -572,6 +586,7 @@ void bgp_lp_event_zebra_up(void) q->label = lcb->label; q->labelid = lcb->labelid; q->allocated = false; + check_bgp_lu_cb_lock(lcb); work_queue_add(lp->callback_q, q); lcb->label = MPLS_LABEL_NONE; @@ -584,7 +599,8 @@ void bgp_lp_event_zebra_up(void) sizeof(struct lp_fifo)); lf->lcb = *lcb; - LABEL_FIFO_ADD(lp->requests, lf); + check_bgp_lu_cb_lock(lcb); + lp_fifo_add_tail(&lp->requests, lf); } skiplist_delete_first(lp->inuse);