diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 137e88adeadb..8ebb3339507a 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_sync_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_sync_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 9a110e6297e9..a17482d112e8 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 6513df33fad6..3e1fdc62845e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -55,6 +55,8 @@ /* All information about zebra. */ struct zclient *zclient = NULL; +struct zclient *zclient_sync; +static bool bgp_zebra_label_manager_connect(void); /* hook to indicate vrf status change for SNMP */ DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp), @@ -2854,9 +2856,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 +3160,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 +3378,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 +3414,57 @@ void bgp_if_init(void) hook_register_prio(if_del, 0, bgp_if_delete_hook); } +static void bgp_start_label_manager(struct event *start) +{ + bgp_zebra_label_manager_connect(); +} + +static bool bgp_zebra_label_manager_ready(void) +{ + return (zclient_sync->sock > 0); +} + +static bool 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 false; + } + /* 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 false; + } + + /* 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 false; + } + + /* tell label pool that zebra is connected */ + bgp_lp_event_zebra_up(); + + return true; +} + 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 +3476,18 @@ 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; + + if (!bgp_zebra_label_manager_ready()) + event_add_timer(master, bgp_start_label_manager, NULL, 1, + &bm->t_bgp_start_label_manager); } void bgp_zebra_destroy(void) @@ -3486,6 +3497,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 +3968,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 || !bgp_zebra_label_manager_ready()) + 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 || !bgp_zebra_label_manager_ready()) + 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 7c60b542f8f0..3d7d71d9b410 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 27d9c49efbda..619925ab2ccf 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -8062,6 +8062,8 @@ 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_sync_label_manager = NULL; + bm->t_bgp_start_label_manager = NULL; bgp_mac_init(); /* init the rd id space. @@ -8308,6 +8310,8 @@ void bgp_terminate(void) list_delete(&bm->listen_sockets); EVENT_OFF(bm->t_rmap_update); + EVENT_OFF(bm->t_bgp_sync_label_manager); + EVENT_OFF(bm->t_bgp_start_label_manager); bgp_mac_finish(); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 95bc07d1670a..50cd9d17f775 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -165,6 +165,9 @@ struct bgp_master { uint32_t inq_limit; uint32_t outq_limit; + struct event *t_bgp_sync_label_manager; + struct event *t_bgp_start_label_manager; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp_master); diff --git a/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json index 6db8e002f429..c66571f46332 100644 --- a/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json +++ b/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json @@ -2,7 +2,5 @@ "ledger":506, "inUse":506, "requests":0, - "labelChunks":3, - "pending":0, - "reconnects":0 + "labelChunks":3 } diff --git a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json index 9f9e57511c4a..d35e4ef46304 100644 --- a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json +++ b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json @@ -2,7 +2,5 @@ "ledger":0, "inUse":0, "requests":0, - "labelChunks":0, - "pending":0, - "reconnects":0 + "labelChunks":1 } diff --git a/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json b/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json index 59ecd27f7fbe..faeaa3ec5f92 100644 --- a/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json +++ b/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json @@ -2,7 +2,5 @@ "ledger":51, "inUse":51, "requests":0, - "labelChunks":1, - "pending":0, - "reconnects":0 + "labelChunks":1 } diff --git a/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json b/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json index 2c52192cd656..5f9d8e66241e 100644 --- a/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json +++ b/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json @@ -2,7 +2,5 @@ "ledger":1, "inUse":1, "requests":0, - "labelChunks":1, - "pending":0, - "reconnects":0 + "labelChunks":1 } diff --git a/zebra/zserv.c b/zebra/zserv.c index d2367007cf6c..85e1edeca069 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -181,9 +181,10 @@ void zserv_log_message(const char *errmsg, struct stream *msg, */ static void zserv_client_fail(struct zserv *client) { - flog_warn(EC_ZEBRA_CLIENT_IO_ERROR, - "Client '%s' encountered an error and is shutting down.", - zebra_route_string(client->proto)); + flog_warn( + EC_ZEBRA_CLIENT_IO_ERROR, + "Client '%s' (session id %d) encountered an error and is shutting down.", + zebra_route_string(client->proto), client->session_id); atomic_store_explicit(&client->pthread->running, false, memory_order_relaxed); @@ -586,6 +587,13 @@ static void zserv_client_free(struct zserv *client) close(client->sock); + /* If this is a synchronous BGP Zebra client for label/table + * manager, then ignore it. It's not GR-aware, and causes GR to + * be skipped for the session_id == 0 (asynchronous). + */ + if (client->proto == ZEBRA_ROUTE_BGP && client->session_id == 1) + return; + if (DYNAMIC_CLIENT_GR_DISABLED(client)) { zebra_mpls_client_cleanup_vrf_label(client->proto);