diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 137e88adea..16314597c7 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -15,7 +15,6 @@ #include "linklist.h" #include "skiplist.h" #include "workqueue.h" -#include "zclient.h" #include "mpls.h" #include "bgpd/bgpd.h" @@ -32,11 +31,6 @@ #include "bgpd/bgp_labelpool_clippy.c" -/* - * Definitions and external declarations. - */ -extern struct zclient *zclient; - #if BGP_LABELPOOL_ENABLE_TESTS static void lptest_init(void); static void lptest_finish(void); @@ -223,6 +217,8 @@ void bgp_lp_finish(void) { struct lp_fifo *lf; struct work_queue_item *item, *titem; + struct listnode *node; + struct lp_chunk *chunk; #if BGP_LABELPOOL_ENABLE_TESTS lptest_finish(); @@ -236,6 +232,9 @@ void bgp_lp_finish(void) skiplist_free(lp->inuse); lp->inuse = NULL; + for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) + bgp_zebra_release_label_range(chunk->first, chunk->last); + list_delete(&lp->chunks); while ((lf = lp_fifo_pop(&lp->requests))) { @@ -448,15 +447,13 @@ void bgp_lp_get( lp_fifo_add_tail(&lp->requests, lf); if (lp_fifo_count(&lp->requests) > lp->pending_count) { - if (!zclient || zclient->sock < 0) + if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, + lp->next_chunksize)) return; - if (zclient_send_get_label_chunk(zclient, 0, lp->next_chunksize, - MPLS_LABEL_BASE_ANY) != - ZCLIENT_SEND_FAILURE) { - lp->pending_count += lp->next_chunksize; - if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX) - lp->next_chunksize <<= 1; - } + + lp->pending_count += lp->next_chunksize; + if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX) + lp->next_chunksize <<= 1; } } @@ -503,46 +500,12 @@ void bgp_lp_release( } } -/* - * zebra response giving us a chunk of labels - */ -void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) +static void bgp_sync_label_manager(struct event *e) { - struct lp_chunk *chunk; int debug = BGP_DEBUG(labelpool, LABELPOOL); struct lp_fifo *lf; - uint32_t labelcount; - if (last < first) { - flog_err(EC_BGP_LABEL, - "%s: zebra label chunk invalid: first=%u, last=%u", - __func__, first, last); - return; - } - - chunk = XCALLOC(MTYPE_BGP_LABEL_CHUNK, sizeof(struct lp_chunk)); - - labelcount = last - first + 1; - - chunk->first = first; - chunk->last = last; - chunk->nfree = labelcount; - bf_init(chunk->allocated_map, labelcount); - - /* - * Optimize for allocation by adding the new (presumably larger) - * chunk at the head of the list so it is examined first. - */ - listnode_add_head(lp->chunks, chunk); - - lp->pending_count -= labelcount; - - if (debug) { - zlog_debug("%s: %zu pending requests", __func__, - lp_fifo_count(&lp->requests)); - } - - while (labelcount && (lf = lp_fifo_first(&lp->requests))) { + while ((lf = lp_fifo_pop(&lp->requests))) { struct lp_lcb *lcb; void *labelid = lf->lcb.labelid; @@ -588,8 +551,6 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) break; } - labelcount -= 1; - /* * we filled the request from local pool. * Enqueue response work item with new label. @@ -610,9 +571,41 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last) work_queue_add(lp->callback_q, q); finishedrequest: - lp_fifo_del(&lp->requests, lf); XFREE(MTYPE_BGP_LABEL_FIFO, lf); +} + +event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1, + &bm->t_bgp_label_manager); +} + +void bgp_lp_event_chunk(uint32_t first, uint32_t last) +{ + struct lp_chunk *chunk; + uint32_t labelcount; + + if (last < first) { + flog_err(EC_BGP_LABEL, + "%s: zebra label chunk invalid: first=%u, last=%u", + __func__, first, last); + return; } + + chunk = XCALLOC(MTYPE_BGP_LABEL_CHUNK, sizeof(struct lp_chunk)); + + labelcount = last - first + 1; + + chunk->first = first; + chunk->last = last; + chunk->nfree = labelcount; + bf_init(chunk->allocated_map, labelcount); + + /* + * Optimize for allocation by adding the new (presumably larger) + * chunk at the head of the list so it is examined first. + */ + listnode_add_head(lp->chunks, chunk); + + lp->pending_count -= labelcount; } /* @@ -634,7 +627,6 @@ void bgp_lp_event_zebra_up(void) unsigned int chunks_needed; void *labelid; struct lp_lcb *lcb; - int lm_init_ok; lp->reconnect_count++; /* @@ -654,22 +646,16 @@ void bgp_lp_event_zebra_up(void) chunks_needed = (labels_needed / lp->next_chunksize) + 1; labels_needed = chunks_needed * lp->next_chunksize; - 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; - /* * Invalidate current list of chunks */ list_delete_all_node(lp->chunks); + if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, labels_needed)) + return; + + lp->pending_count = labels_needed; + /* * Invalidate any existing labels and requeue them as requests */ @@ -712,6 +698,9 @@ void bgp_lp_event_zebra_up(void) skiplist_delete_first(lp->inuse); } + + event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1, + &bm->t_bgp_label_manager); } DEFUN(show_bgp_labelpool_summary, show_bgp_labelpool_summary_cmd, diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h index 9a110e6297..a17482d112 100644 --- a/bgpd/bgp_labelpool.h +++ b/bgpd/bgp_labelpool.h @@ -38,7 +38,7 @@ 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_release(int type, void *labelid, mpls_label_t label); -extern void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last); +extern void bgp_lp_event_chunk(uint32_t first, uint32_t last); extern void bgp_lp_event_zebra_down(void); extern void bgp_lp_event_zebra_up(void); extern void bgp_lp_vty_init(void); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 6513df33fa..8808f1fcaf 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -55,6 +55,7 @@ /* All information about zebra. */ struct zclient *zclient = NULL; +struct zclient *zclient_sync = NULL; /* hook to indicate vrf status change for SNMP */ DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp), @@ -2854,9 +2855,6 @@ static void bgp_zebra_connected(struct zclient *zclient) bgp_zebra_instance_register(bgp); - /* tell label pool that zebra is connected */ - bgp_lp_event_zebra_up(); - /* TODO - What if we have peers and networks configured, do we have to * kick-start them? */ @@ -3161,54 +3159,6 @@ static int bgp_zebra_process_local_ip_prefix(ZAPI_CALLBACK_ARGS) return 0; } -static int bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) -{ - struct stream *s = NULL; - uint8_t response_keep; - uint32_t first; - uint32_t last; - uint8_t proto; - unsigned short instance; - - s = zclient->ibuf; - STREAM_GETC(s, proto); - STREAM_GETW(s, instance); - STREAM_GETC(s, response_keep); - STREAM_GETL(s, first); - STREAM_GETL(s, last); - - if (zclient->redist_default != proto) { - flog_err(EC_BGP_LM_ERROR, "Got LM msg with wrong proto %u", - proto); - return 0; - } - if (zclient->instance != instance) { - flog_err(EC_BGP_LM_ERROR, "Got LM msg with wrong instance %u", - proto); - return 0; - } - - if (first > last || - first < MPLS_LABEL_UNRESERVED_MIN || - last > MPLS_LABEL_UNRESERVED_MAX) { - - flog_err(EC_BGP_LM_ERROR, "%s: Invalid Label chunk: %u - %u", - __func__, first, last); - return 0; - } - if (BGP_DEBUG(zebra, ZEBRA)) { - zlog_debug("Label Chunk assign: %u - %u (%u) ", - first, last, response_keep); - } - - bgp_lp_event_chunk(response_keep, first, last); - - return 0; - -stream_failure: /* for STREAM_GETX */ - return -1; -} - extern struct zebra_privs_t bgpd_privs; static int bgp_ifp_create(struct interface *ifp) @@ -3427,7 +3377,6 @@ static zclient_handler *const bgp_handlers[] = { [ZEBRA_L3VNI_DEL] = bgp_zebra_process_local_l3vni, [ZEBRA_IP_PREFIX_ROUTE_ADD] = bgp_zebra_process_local_ip_prefix, [ZEBRA_IP_PREFIX_ROUTE_DEL] = bgp_zebra_process_local_ip_prefix, - [ZEBRA_GET_LABEL_CHUNK] = bgp_zebra_process_label_chunk, [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, [ZEBRA_IPSET_NOTIFY_OWNER] = ipset_notify_owner, [ZEBRA_IPSET_ENTRY_NOTIFY_OWNER] = ipset_entry_notify_owner, @@ -3464,8 +3413,45 @@ void bgp_if_init(void) hook_register_prio(if_del, 0, bgp_if_delete_hook); } +static void bgp_zebra_label_manager_connect(void) +{ + /* Connect to label manager. */ + if (zclient_socket_connect(zclient_sync) < 0) { + zlog_warn("%s: failed connecting synchronous zclient!", + __func__); + return; + } + /* make socket non-blocking */ + set_nonblocking(zclient_sync->sock); + + /* Send hello to notify zebra this is a synchronous client */ + if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) { + zlog_warn("%s: failed sending hello for synchronous zclient!", + __func__); + close(zclient_sync->sock); + zclient_sync->sock = -1; + return; + } + + /* Connect to label manager */ + if (lm_label_manager_connect(zclient_sync, 0) != 0) { + zlog_warn("%s: failed connecting to label manager!", __func__); + if (zclient_sync->sock > 0) { + close(zclient_sync->sock); + zclient_sync->sock = -1; + } + return; + } + + /* tell label pool that zebra is connected */ + bgp_lp_event_zebra_up(); +} + void bgp_zebra_init(struct event_loop *master, unsigned short instance) { + struct zclient_options options = zclient_options_default; + + options.synchronous = true; zclient_num_connects = 0; if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up, @@ -3477,6 +3463,16 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance) zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; zclient->instance = instance; + + /* Initialize special zclient for synchronous message exchanges. */ + zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync->sock = -1; + zclient_sync->redist_default = ZEBRA_ROUTE_BGP; + zclient_sync->instance = instance; + zclient_sync->session_id = 1; + zclient_sync->privs = &bgpd_privs; + + bgp_zebra_label_manager_connect(); } void bgp_zebra_destroy(void) @@ -3486,6 +3482,12 @@ void bgp_zebra_destroy(void) zclient_stop(zclient); zclient_free(zclient); zclient = NULL; + + if (zclient_sync == NULL) + return; + zclient_stop(zclient_sync); + zclient_free(zclient_sync); + zclient_sync = NULL; } int bgp_zebra_num_connects(void) @@ -3951,3 +3953,42 @@ void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, /* vrf_id is DEFAULT_VRF */ zebra_send_mpls_labels(zclient, cmd, &zl); } + +bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size) +{ + int ret; + uint32_t start, end; + + if (!zclient_sync || zclient_sync->sock < 0) + return false; + + ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start, + &end); + if (ret < 0) { + zlog_warn("%s: error getting label range!", __func__); + return false; + } + + if (start > end || start < MPLS_LABEL_UNRESERVED_MIN || + end > MPLS_LABEL_UNRESERVED_MAX) { + flog_err(EC_BGP_LM_ERROR, "%s: Invalid Label chunk: %u - %u", + __func__, start, end); + return false; + } + + bgp_lp_event_chunk(start, end); + + return true; +} + +void bgp_zebra_release_label_range(uint32_t start, uint32_t end) +{ + int ret; + + if (!zclient_sync || zclient_sync->sock < 0) + return; + + ret = lm_release_label_chunk(zclient_sync, start, end); + if (ret < 0) + zlog_warn("%s: error releasing label range!", __func__); +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 7c60b542f8..3d7d71d9b4 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -123,4 +123,6 @@ 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 void bgp_zebra_release_label_range(uint32_t start, uint32_t end); #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 27d9c49efb..9edf0bf9f2 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -8062,6 +8062,7 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL; bm->inq_limit = BM_DEFAULT_Q_LIMIT; bm->outq_limit = BM_DEFAULT_Q_LIMIT; + bm->t_bgp_label_manager = NULL; bgp_mac_init(); /* init the rd id space. @@ -8308,6 +8309,7 @@ void bgp_terminate(void) list_delete(&bm->listen_sockets); EVENT_OFF(bm->t_rmap_update); + EVENT_OFF(bm->t_bgp_label_manager); bgp_mac_finish(); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 95bc07d167..0b16f8094e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -165,6 +165,8 @@ struct bgp_master { uint32_t inq_limit; uint32_t outq_limit; + struct event *t_bgp_label_manager; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp_master);