pimd: pim mlag show commands

1. show ip pim mlag summary
provides MLAG session information and stats
2. show ip pim mlag upstream
displays the upstream entries synced across the MLAG switches

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
Anuradha Karuppiah 2020-02-06 09:31:03 -08:00
parent 650d9ad1ac
commit f80427e9e7
3 changed files with 399 additions and 0 deletions

View File

@ -461,6 +461,18 @@ cause great confusion.
Display upstream information for S,G's and the RPF data associated with them.
.. index:: show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json]
.. clicmd:: show ip pim mlag upstream
Display upstream entries that are synced across MLAG switches.
Allow the user to specify sub Source and Groups address filters.
.. index:: show ip pim mlag summary
.. clicmd:: show ip pim mlag summary
Display PIM MLAG (multi-chassis link aggregation) session status and
control message statistics.
.. index:: show ip pim bsr
.. clicmd:: show ip pim bsr

View File

@ -4625,6 +4625,379 @@ DEFUN (show_ip_pim_local_membership,
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_mlag_summary,
show_ip_pim_mlag_summary_cmd,
"show ip pim mlag summary [json]",
SHOW_STR
IP_STR
PIM_STR
"MLAG\n"
"status and stats\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
char role_buf[MLAG_ROLE_STRSIZE];
char addr_buf[INET_ADDRSTRLEN];
if (uj) {
json_object *json = NULL;
json_object *json_stat = NULL;
json = json_object_new_object();
if (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
json_object_boolean_true_add(json, "mlagConnUp");
if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
json_object_boolean_true_add(json, "mlagPeerConnUp");
if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
json_object_boolean_true_add(json, "mlagPeerZebraUp");
json_object_string_add(json, "mlagRole",
mlag_role2str(router->mlag_role,
role_buf, sizeof(role_buf)));
inet_ntop(AF_INET, &router->local_vtep_ip,
addr_buf, INET_ADDRSTRLEN);
json_object_string_add(json, "localVtepIp", addr_buf);
inet_ntop(AF_INET, &router->anycast_vtep_ip,
addr_buf, INET_ADDRSTRLEN);
json_object_string_add(json, "anycastVtepIp", addr_buf);
json_object_string_add(json, "peerlinkRif",
router->peerlink_rif);
json_stat = json_object_new_object();
json_object_int_add(json_stat, "mlagConnFlaps",
router->mlag_stats.mlagd_session_downs);
json_object_int_add(json_stat, "mlagPeerConnFlaps",
router->mlag_stats.peer_session_downs);
json_object_int_add(json_stat, "mlagPeerZebraFlaps",
router->mlag_stats.peer_zebra_downs);
json_object_int_add(json_stat, "mrouteAddRx",
router->mlag_stats.msg.mroute_add_rx);
json_object_int_add(json_stat, "mrouteAddTx",
router->mlag_stats.msg.mroute_add_tx);
json_object_int_add(json_stat, "mrouteDelRx",
router->mlag_stats.msg.mroute_del_rx);
json_object_int_add(json_stat, "mrouteDelTx",
router->mlag_stats.msg.mroute_del_tx);
json_object_int_add(json_stat, "mlagStatusUpdates",
router->mlag_stats.msg.mlag_status_updates);
json_object_int_add(json_stat, "peerZebraStatusUpdates",
router->mlag_stats.msg.peer_zebra_status_updates);
json_object_int_add(json_stat, "pimStatusUpdates",
router->mlag_stats.msg.pim_status_updates);
json_object_int_add(json_stat, "vxlanUpdates",
router->mlag_stats.msg.vxlan_updates);
json_object_object_add(json, "connStats", json_stat);
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
return CMD_SUCCESS;
}
vty_out(vty, "MLAG daemon connection: %s\n",
(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
? "up" : "down");
vty_out(vty, "MLAG peer state: %s\n",
(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
? "up" : "down");
vty_out(vty, "Zebra peer state: %s\n",
(router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
? "up" : "down");
vty_out(vty, "MLAG role: %s\n",
mlag_role2str(router->mlag_role, role_buf, sizeof(role_buf)));
inet_ntop(AF_INET, &router->local_vtep_ip,
addr_buf, INET_ADDRSTRLEN);
vty_out(vty, "Local VTEP IP: %s\n", addr_buf);
inet_ntop(AF_INET, &router->anycast_vtep_ip,
addr_buf, INET_ADDRSTRLEN);
vty_out(vty, "Anycast VTEP IP: %s\n", addr_buf);
vty_out(vty, "Peerlink: %s\n", router->peerlink_rif);
vty_out(vty, "Session flaps: mlagd: %d mlag-peer: %d zebra-peer: %d\n",
router->mlag_stats.mlagd_session_downs,
router->mlag_stats.peer_session_downs,
router->mlag_stats.peer_zebra_downs);
vty_out(vty, "Message Statistics:\n");
vty_out(vty, " mroute adds: rx: %d, tx: %d\n",
router->mlag_stats.msg.mroute_add_rx,
router->mlag_stats.msg.mroute_add_tx);
vty_out(vty, " mroute dels: rx: %d, tx: %d\n",
router->mlag_stats.msg.mroute_del_rx,
router->mlag_stats.msg.mroute_del_tx);
vty_out(vty, " peer zebra status updates: %d\n",
router->mlag_stats.msg.peer_zebra_status_updates);
vty_out(vty, " PIM status updates: %d\n",
router->mlag_stats.msg.pim_status_updates);
vty_out(vty, " VxLAN updates: %d\n",
router->mlag_stats.msg.vxlan_updates);
return CMD_SUCCESS;
}
static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
struct vty *vty, struct pim_upstream *up,
char *src_str, char *grp_str, json_object *json)
{
if (json) {
json_object *json_row = NULL;
json_object *own_list = NULL;
json_object *json_group = NULL;
json_object_object_get_ex(json, grp_str, &json_group);
if (!json_group) {
json_group = json_object_new_object();
json_object_object_add(json, grp_str,
json_group);
}
json_row = json_object_new_object();
json_object_string_add(json_row, "source", src_str);
json_object_string_add(json_row, "group", grp_str);
own_list = json_object_new_array();
if (pim_up_mlag_is_local(up))
json_object_array_add(own_list,
json_object_new_string("local"));
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
json_object_array_add(own_list,
json_object_new_string("peer"));
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
json_object_array_add(
own_list, json_object_new_string("Interface"));
json_object_object_add(json_row, "owners", own_list);
json_object_int_add(json_row, "localCost",
pim_up_mlag_local_cost(up));
json_object_int_add(json_row, "peerCost",
pim_up_mlag_peer_cost(up));
if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
json_object_boolean_false_add(json_row, "df");
else
json_object_boolean_true_add(json_row, "df");
json_object_object_add(json_group, src_str, json_row);
} else {
char own_str[6];
own_str[0] = '\0';
if (pim_up_mlag_is_local(up))
strcpy(own_str + strlen(own_str), "L");
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
strcpy(own_str + strlen(own_str), "P");
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
strcpy(own_str + strlen(own_str), "I");
/* XXX - fixup, print paragraph output */
vty_out(vty,
"%-15s %-15s %-6s %-11u %-10d %2s\n",
src_str, grp_str, own_str,
pim_up_mlag_local_cost(up),
pim_up_mlag_peer_cost(up),
PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
? "n" : "y");
}
}
static void pim_show_mlag_up_detail(struct vrf *vrf,
struct vty *vty, const char *src_or_group,
const char *group, bool uj)
{
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
struct pim_upstream *up;
struct pim_instance *pim = vrf->info;
json_object *json = NULL;
if (uj)
json = json_object_new_object();
else
vty_out(vty,
"Source Group Owner Local-cost Peer-cost DF\n");
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
&& !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
&& !pim_up_mlag_is_local(up))
continue;
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
/* XXX: strcmps are clearly inefficient. we should do uint comps
* here instead.
*/
if (group) {
if (strcmp(src_str, src_or_group) ||
strcmp(grp_str, group))
continue;
} else {
if (strcmp(src_str, src_or_group) &&
strcmp(grp_str, src_or_group))
continue;
}
pim_show_mlag_up_entry_detail(vrf, vty, up,
src_str, grp_str, json);
}
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
}
static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj)
{
json_object *json = NULL;
json_object *json_row;
struct pim_upstream *up;
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
struct pim_instance *pim = vrf->info;
json_object *json_group = NULL;
if (uj) {
json = json_object_new_object();
} else {
vty_out(vty,
"Source Group Owner Local-cost Peer-cost DF\n");
}
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
&& !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
&& !pim_up_mlag_is_local(up))
continue;
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
if (uj) {
json_object *own_list = NULL;
json_object_object_get_ex(json, grp_str, &json_group);
if (!json_group) {
json_group = json_object_new_object();
json_object_object_add(json, grp_str,
json_group);
}
json_row = json_object_new_object();
json_object_string_add(json_row, "vrf", vrf->name);
json_object_string_add(json_row, "source", src_str);
json_object_string_add(json_row, "group", grp_str);
own_list = json_object_new_array();
if (pim_up_mlag_is_local(up)) {
json_object_array_add(own_list,
json_object_new_string("local"));
}
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) {
json_object_array_add(own_list,
json_object_new_string("peer"));
}
json_object_object_add(json_row, "owners", own_list);
json_object_int_add(json_row, "localCost",
pim_up_mlag_local_cost(up));
json_object_int_add(json_row, "peerCost",
pim_up_mlag_peer_cost(up));
if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
json_object_boolean_false_add(json_row, "df");
else
json_object_boolean_true_add(json_row, "df");
json_object_object_add(json_group, src_str, json_row);
} else {
char own_str[6];
own_str[0] = '\0';
if (pim_up_mlag_is_local(up))
strcpy(own_str + strlen(own_str), "L");
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
strcpy(own_str + strlen(own_str), "P");
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
strcpy(own_str + strlen(own_str), "I");
vty_out(vty,
"%-15s %-15s %-6s %-11u %-10u %2s\n",
src_str, grp_str, own_str,
pim_up_mlag_local_cost(up),
pim_up_mlag_peer_cost(up),
PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
? "n" : "y");
}
}
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
}
static void pim_show_mlag_help_string(struct vty *vty, bool uj)
{
if (!uj) {
vty_out(vty, "Owner codes:\n");
vty_out(vty,
"L: EVPN-MLAG Entry, I:PIM-MLAG Entry, "
"P: Peer Entry\n");
}
}
DEFUN(show_ip_pim_mlag_up, show_ip_pim_mlag_up_cmd,
"show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json]",
SHOW_STR
IP_STR
PIM_STR
VRF_CMD_HELP_STR
"MLAG\n"
"upstream\n"
"Unicast or Multicast address\n"
"Multicast address\n" JSON_STR)
{
const char *src_or_group = NULL;
const char *group = NULL;
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
bool uj = use_json(argc, argv);
if (!vrf || !vrf->info) {
vty_out(vty, "%s: VRF or Info missing\n", __func__);
return CMD_WARNING;
}
if (uj)
argc--;
if (argv_find(argv, argc, "A.B.C.D", &idx)) {
src_or_group = argv[idx]->arg;
if (idx + 1 < argc)
group = argv[idx + 1]->arg;
}
pim_show_mlag_help_string(vty, uj);
if (src_or_group || group)
pim_show_mlag_up_detail(vrf, vty, src_or_group, group, uj);
else
pim_show_mlag_up_vrf(vrf, vty, uj);
return CMD_SUCCESS;
}
DEFUN(show_ip_pim_mlag_up_vrf_all, show_ip_pim_mlag_up_vrf_all_cmd,
"show ip pim vrf all mlag upstream [json]",
SHOW_STR IP_STR PIM_STR VRF_CMD_HELP_STR
"MLAG\n"
"upstream\n" JSON_STR)
{
struct vrf *vrf;
bool uj = use_json(argc, argv);
pim_show_mlag_help_string(vty, uj);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
pim_show_mlag_up_vrf(vrf, vty, uj);
}
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_neighbor,
show_ip_pim_neighbor_cmd,
"show ip pim [vrf NAME] neighbor [detail|WORD] [json]",
@ -10471,6 +10844,9 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_pim_join_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_pim_jp_agg_cmd);
install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd);
install_element(VIEW_NODE, &show_ip_pim_mlag_summary_cmd);
install_element(VIEW_NODE, &show_ip_pim_mlag_up_cmd);
install_element(VIEW_NODE, &show_ip_pim_mlag_up_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd);
install_element(VIEW_NODE, &show_ip_pim_neighbor_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_pim_rpf_cmd);
@ -10595,6 +10971,8 @@ void pim_cmd_init(void)
install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
install_element(CONFIG_NODE, &debug_pim_zebra_cmd);
install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd);
install_element(CONFIG_NODE, &debug_pim_mlag_cmd);
install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd);
install_element(CONFIG_NODE, &debug_pim_vxlan_cmd);
install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd);
install_element(CONFIG_NODE, &debug_msdp_cmd);

View File

@ -88,6 +88,12 @@
* This flag is only relevant for (S,G) entries.
*/
#define PIM_UPSTREAM_FLAG_MASK_USE_RPT (1 << 20)
/* PIM Syncs upstream entries to peer Nodes via MLAG in 2 cases.
* one is to support plain PIM Redundancy and another one is to support
* PIM REdundancy.
*/
#define PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE (1 << 21)
#define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF
@ -114,6 +120,7 @@
#define PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(flags) ((flags) &PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE)
#define PIM_UPSTREAM_FLAG_TEST_USE_RPT(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_USE_RPT)
#define PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_IGMP | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM))
#define PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(flags) ((flags)&PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@ -135,6 +142,7 @@
#define PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
#define PIM_UPSTREAM_FLAG_SET_MLAG_PEER(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
#define PIM_UPSTREAM_FLAG_SET_USE_RPT(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_USE_RPT)
#define PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@ -157,6 +165,7 @@
#define PIM_UPSTREAM_FLAG_UNSET_MLAG_PEER(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
#define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE)
#define PIM_UPSTREAM_FLAG_UNSET_USE_RPT(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_USE_RPT)
#define PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
/* The RPF cost is incremented by 10 if the RPF interface is the peerlink-rif.
* This is used to force the MLAG switch with the lowest cost to the RPF