bgpd: add show commands for bgp labelpool

These commands allow the bgp labelpool lists and counts to be
viewed for debug purposes.

Signed-off-by: Pat Ruddy <pat@voltanet.io>
This commit is contained in:
Pat Ruddy 2020-12-04 12:14:26 +00:00
parent a7f52fb0f7
commit e3ea65039e
5 changed files with 399 additions and 0 deletions

View File

@ -538,6 +538,7 @@ void bgp_lp_event_zebra_up(void)
struct lp_lcb *lcb; struct lp_lcb *lcb;
int lm_init_ok; int lm_init_ok;
lp->reconnect_count++;
/* /*
* Get label chunk allocation request dispatched to zebra * Get label chunk allocation request dispatched to zebra
*/ */
@ -607,3 +608,370 @@ void bgp_lp_event_zebra_up(void)
skiplist_delete_first(lp->inuse); skiplist_delete_first(lp->inuse);
} }
} }
DEFUN(show_bgp_labelpool_summary, show_bgp_labelpool_summary_cmd,
"show bgp labelpool summary [json]",
SHOW_STR BGP_STR
"BGP Labelpool information\n"
"BGP Labelpool summary\n" JSON_STR)
{
bool uj = use_json(argc, argv);
json_object *json = NULL;
if (!lp) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "No existing BGP labelpool\n");
return (CMD_WARNING);
}
if (uj) {
json = json_object_new_object();
json_object_int_add(json, "Ledger", skiplist_count(lp->ledger));
json_object_int_add(json, "InUse", skiplist_count(lp->inuse));
json_object_int_add(json, "Requests",
lp_fifo_count(&lp->requests));
json_object_int_add(json, "LabelChunks", listcount(lp->chunks));
json_object_int_add(json, "Pending", lp->pending_count);
json_object_int_add(json, "Reconnects", lp->reconnect_count);
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else {
vty_out(vty, "Labelpool Summary\n");
vty_out(vty, "-----------------\n");
vty_out(vty, "%-13s %d\n",
"Ledger:", skiplist_count(lp->ledger));
vty_out(vty, "%-13s %d\n", "InUse:", skiplist_count(lp->inuse));
vty_out(vty, "%-13s %zu\n",
"Requests:", lp_fifo_count(&lp->requests));
vty_out(vty, "%-13s %d\n",
"LabelChunks:", listcount(lp->chunks));
vty_out(vty, "%-13s %d\n", "Pending:", lp->pending_count);
vty_out(vty, "%-13s %d\n", "Reconnects:", lp->reconnect_count);
}
return CMD_SUCCESS;
}
DEFUN(show_bgp_labelpool_ledger, show_bgp_labelpool_ledger_cmd,
"show bgp labelpool ledger [json]",
SHOW_STR BGP_STR
"BGP Labelpool information\n"
"BGP Labelpool ledger\n" JSON_STR)
{
bool uj = use_json(argc, argv);
json_object *json = NULL, *json_elem = NULL;
struct lp_lcb *lcb = NULL;
struct bgp_path_info *pi;
void *cursor = NULL;
const struct prefix *p;
int rc, count;
if (!lp) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "No existing BGP labelpool\n");
return (CMD_WARNING);
}
if (uj) {
count = skiplist_count(lp->ledger);
if (!count) {
vty_out(vty, "{}\n");
return CMD_SUCCESS;
}
json = json_object_new_array();
} else {
vty_out(vty, "Prefix Label\n");
vty_out(vty, "---------------------------\n");
}
for (rc = skiplist_next(lp->ledger, (void **)&pi, (void **)&lcb,
&cursor);
!rc; rc = skiplist_next(lp->ledger, (void **)&pi, (void **)&lcb,
&cursor)) {
if (uj) {
json_elem = json_object_new_object();
json_object_array_add(json, json_elem);
}
switch (lcb->type) {
case LP_TYPE_BGP_LU:
if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
if (uj) {
json_object_string_add(
json_elem, "prefix", "INVALID");
json_object_int_add(json_elem, "label",
lcb->label);
} else
vty_out(vty, "%-18s %u\n",
"INVALID", lcb->label);
else {
char buf[PREFIX2STR_BUFFER];
p = bgp_dest_get_prefix(pi->net);
prefix2str(p, buf, sizeof(buf));
if (uj) {
json_object_string_add(json_elem,
"prefix", buf);
json_object_int_add(json_elem, "label",
lcb->label);
} else
vty_out(vty, "%-18s %u\n", buf,
lcb->label);
}
break;
case LP_TYPE_VRF:
if (uj) {
json_object_string_add(json_elem, "prefix",
"VRF");
json_object_int_add(json_elem, "label",
lcb->label);
} else
vty_out(vty, "%-18s %u\n", "VRF",
lcb->label);
break;
}
}
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
DEFUN(show_bgp_labelpool_inuse, show_bgp_labelpool_inuse_cmd,
"show bgp labelpool inuse [json]",
SHOW_STR BGP_STR
"BGP Labelpool information\n"
"BGP Labelpool inuse\n" JSON_STR)
{
bool uj = use_json(argc, argv);
json_object *json = NULL, *json_elem = NULL;
struct bgp_path_info *pi;
mpls_label_t label;
struct lp_lcb *lcb;
void *cursor = NULL;
const struct prefix *p;
int rc, count;
if (!lp) {
vty_out(vty, "No existing BGP labelpool\n");
return (CMD_WARNING);
}
if (!lp) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "No existing BGP labelpool\n");
return (CMD_WARNING);
}
if (uj) {
count = skiplist_count(lp->inuse);
if (!count) {
vty_out(vty, "{}\n");
return CMD_SUCCESS;
}
json = json_object_new_array();
} else {
vty_out(vty, "Prefix Label\n");
vty_out(vty, "---------------------------\n");
}
for (rc = skiplist_next(lp->inuse, (void **)&label, (void **)&pi,
&cursor);
!rc; rc = skiplist_next(lp->ledger, (void **)&label, (void **)&pi,
&cursor)) {
if (skiplist_search(lp->ledger, pi, (void **)&lcb))
continue;
if (uj) {
json_elem = json_object_new_object();
json_object_array_add(json, json_elem);
}
switch (lcb->type) {
case LP_TYPE_BGP_LU:
if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
if (uj) {
json_object_string_add(
json_elem, "prefix", "INVALID");
json_object_int_add(json_elem, "label",
label);
} else
vty_out(vty, "INVALID %u\n",
label);
else {
char buf[PREFIX2STR_BUFFER];
p = bgp_dest_get_prefix(pi->net);
prefix2str(p, buf, sizeof(buf));
if (uj) {
json_object_string_add(json_elem,
"prefix", buf);
json_object_int_add(json_elem, "label",
label);
} else
vty_out(vty, "%-18s %u\n", buf,
label);
}
break;
case LP_TYPE_VRF:
if (uj) {
json_object_string_add(json_elem, "prefix",
"VRF");
json_object_int_add(json_elem, "label", label);
} else
vty_out(vty, "%-18s %u\n", "VRF",
label);
break;
}
}
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
DEFUN(show_bgp_labelpool_requests, show_bgp_labelpool_requests_cmd,
"show bgp labelpool requests [json]",
SHOW_STR BGP_STR
"BGP Labelpool information\n"
"BGP Labelpool requests\n" JSON_STR)
{
bool uj = use_json(argc, argv);
json_object *json = NULL, *json_elem = NULL;
struct bgp_path_info *pi;
const struct prefix *p;
char buf[PREFIX2STR_BUFFER];
struct lp_fifo *item, *next;
int count;
if (!lp) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "No existing BGP labelpool\n");
return (CMD_WARNING);
}
if (uj) {
count = lp_fifo_count(&lp->requests);
if (!count) {
vty_out(vty, "{}\n");
return CMD_SUCCESS;
}
json = json_object_new_array();
} else {
vty_out(vty, "Prefix \n");
vty_out(vty, "----------------\n");
}
for (item = lp_fifo_first(&lp->requests); item; item = next) {
next = lp_fifo_next_safe(&lp->requests, item);
pi = item->lcb.labelid;
if (uj) {
json_elem = json_object_new_object();
json_object_array_add(json, json_elem);
}
switch (item->lcb.type) {
case LP_TYPE_BGP_LU:
if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) {
if (uj)
json_object_string_add(
json_elem, "prefix", "INVALID");
else
vty_out(vty, "INVALID\n");
} else {
p = bgp_dest_get_prefix(pi->net);
prefix2str(p, buf, sizeof(buf));
if (uj)
json_object_string_add(json_elem,
"prefix", buf);
else
vty_out(vty, "%-18s\n", buf);
}
break;
case LP_TYPE_VRF:
if (uj)
json_object_string_add(json_elem, "prefix",
"VRF");
else
vty_out(vty, "VRF\n");
break;
}
}
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
DEFUN(show_bgp_labelpool_chunks, show_bgp_labelpool_chunks_cmd,
"show bgp labelpool chunks [json]",
SHOW_STR BGP_STR
"BGP Labelpool information\n"
"BGP Labelpool chunks\n" JSON_STR)
{
bool uj = use_json(argc, argv);
json_object *json = NULL, *json_elem;
struct listnode *node;
struct lp_chunk *chunk;
int count;
if (!lp) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "No existing BGP labelpool\n");
return (CMD_WARNING);
}
if (uj) {
count = listcount(lp->chunks);
if (!count) {
vty_out(vty, "{}\n");
return CMD_SUCCESS;
}
json = json_object_new_array();
} else {
vty_out(vty, "First Last\n");
vty_out(vty, "--------------\n");
}
for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) {
if (uj) {
json_elem = json_object_new_object();
json_object_array_add(json, json_elem);
json_object_int_add(json_elem, "first", chunk->first);
json_object_int_add(json_elem, "last", chunk->last);
} else
vty_out(vty, "%-10u %-10u\n", chunk->first,
chunk->last);
}
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
void bgp_lp_vty_init(void)
{
install_element(VIEW_NODE, &show_bgp_labelpool_summary_cmd);
install_element(VIEW_NODE, &show_bgp_labelpool_ledger_cmd);
install_element(VIEW_NODE, &show_bgp_labelpool_inuse_cmd);
install_element(VIEW_NODE, &show_bgp_labelpool_requests_cmd);
install_element(VIEW_NODE, &show_bgp_labelpool_chunks_cmd);
}

View File

@ -40,6 +40,7 @@ struct labelpool {
struct lp_fifo_head requests; /* blocked on zebra */ struct lp_fifo_head requests; /* blocked on zebra */
struct work_queue *callback_q; struct work_queue *callback_q;
uint32_t pending_count; /* requested from zebra */ uint32_t pending_count; /* requested from zebra */
uint32_t reconnect_count; /* zebra reconnections */
}; };
extern void bgp_lp_init(struct thread_master *master, struct labelpool *pool); extern void bgp_lp_init(struct thread_master *master, struct labelpool *pool);
@ -50,5 +51,6 @@ 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(uint8_t keep, uint32_t first, uint32_t last);
extern void bgp_lp_event_zebra_down(void); extern void bgp_lp_event_zebra_down(void);
extern void bgp_lp_event_zebra_up(void); extern void bgp_lp_event_zebra_up(void);
extern void bgp_lp_vty_init(void);
#endif /* _FRR_BGP_LABELPOOL_H */ #endif /* _FRR_BGP_LABELPOOL_H */

View File

@ -7613,6 +7613,8 @@ void bgp_init(unsigned short instance)
/* BFD init */ /* BFD init */
bgp_bfd_init(); bgp_bfd_init();
bgp_lp_vty_init();
cmd_variable_handler_register(bgp_viewvrf_var_handlers); cmd_variable_handler_register(bgp_viewvrf_var_handlers);
} }

View File

@ -18,6 +18,7 @@ vtysh_scan += \
bgpd/bgp_evpn_mh.c \ bgpd/bgp_evpn_mh.c \
bgpd/bgp_evpn_vty.c \ bgpd/bgp_evpn_vty.c \
bgpd/bgp_filter.c \ bgpd/bgp_filter.c \
bgpd/bgp_labelpool.c \
bgpd/bgp_mplsvpn.c \ bgpd/bgp_mplsvpn.c \
bgpd/bgp_nexthop.c \ bgpd/bgp_nexthop.c \
bgpd/bgp_route.c \ bgpd/bgp_route.c \

View File

@ -3373,6 +3373,32 @@ attribute.
If ``json`` option is specified, output is displayed in JSON format. If ``json`` option is specified, output is displayed in JSON format.
.. index:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json]
.. clicmd:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json]
These commands display information about the BGP labelpool used for
the association of MPLS labels with routes for L3VPN and Labeled Unicast
If ``chunks`` option is specified, output shows the current list of label
chunks granted to BGP by Zebra, indicating the start and end label in
each chunk
If ``inuse`` option is specified, output shows the current inuse list of
label to prefix mappings
If ``ledger`` option is specified, output shows ledger list of all
label requests made per prefix
If ``requests`` option is specified, output shows current list of label
requests which have not yet been fulfilled by the labelpool
If ``summary`` option is specified, output is a summary of the counts for
the chunks, inuse, ledger and requests list along with the count of
outstanding chunk requests to Zebra and the nummber of zebra reconnects
that have happened
If ``json`` option is specified, output is displayed in JSON format.
.. _bgp-display-routes-by-lcommunity: .. _bgp-display-routes-by-lcommunity:
Displaying Routes by Large Community Attribute Displaying Routes by Large Community Attribute