diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 72471d7af0..d70c3c0e64 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -387,9 +387,14 @@ cause great confusion. .. clicmd:: show ip igmp [vrf NAME] join [json] Display IGMP static join information for a specific vrf. - If "vrf all" is provided, it displays information for all the vrfs present. + +.. index:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] +.. clicmd:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] -.. clicmd:: show ip igmp groups + Display IGMP static join information for all the vrfs present. + +.. index:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] +.. clicmd:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] Display IGMP groups information. diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 8c75b0a5b5..2e90cf9053 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -67,7 +67,7 @@ static struct cmd_node debug_node = { }; static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], - const int argc, int *idx) + const int argc, int *idx, bool uj) { struct vrf *vrf; @@ -76,9 +76,13 @@ static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], else vrf = vrf_lookup_by_id(VRF_DEFAULT); - if (!vrf) - vty_out(vty, "Specified VRF: %s does not exist\n", - argv[*idx]->arg); + if (!vrf) { + if (uj) + vty_json_empty(vty); + else + vty_out(vty, "Specified VRF: %s does not exist\n", + argv[*idx]->arg); + } return vrf; } @@ -822,19 +826,172 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, } } -static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) +static void igmp_source_json_helper(struct gm_source *src, + json_object *json_sources, char *source_str, + char *mmss, char *uptime) +{ + json_object *json_source = NULL; + + json_source = json_object_new_object(); + if (!json_source) + return; + + json_object_string_add(json_source, "source", source_str); + json_object_string_add(json_source, "timer", mmss); + json_object_boolean_add(json_source, "forwarded", + IGMP_SOURCE_TEST_FORWARDING(src->source_flags)); + json_object_string_add(json_source, "uptime", uptime); + json_object_array_add(json_sources, json_source); +} + +static void igmp_group_print(struct interface *ifp, struct vty *vty, bool uj, + json_object *json, struct gm_group *grp, + time_t now, bool detail) +{ + json_object *json_iface = NULL; + json_object *json_group = NULL; + json_object *json_groups = NULL; + char group_str[INET_ADDRSTRLEN]; + char hhmmss[PIM_TIME_STRLEN]; + char uptime[PIM_TIME_STRLEN]; + + pim_inet4_dump("", grp->group_addr, group_str, + sizeof(group_str)); + pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss), grp->t_group_timer); + pim_time_uptime(uptime, sizeof(uptime), now - grp->group_creation); + + if (uj) { + json_object_object_get_ex(json, ifp->name, &json_iface); + if (!json_iface) { + json_iface = json_object_new_object(); + if (!json_iface) + return; + json_object_pim_ifp_add(json_iface, ifp); + json_object_object_add(json, ifp->name, json_iface); + json_groups = json_object_new_array(); + if (!json_groups) + return; + json_object_object_add(json_iface, "groups", + json_groups); + } + + json_object_object_get_ex(json_iface, "groups", &json_groups); + if (json_groups) { + json_group = json_object_new_object(); + if (!json_group) + return; + + json_object_string_add(json_group, "group", group_str); + if (grp->igmp_version == IGMP_DEFAULT_VERSION) + json_object_string_add( + json_group, "mode", + grp->group_filtermode_isexcl + ? "EXCLUDE" + : "INCLUDE"); + + json_object_string_add(json_group, "timer", hhmmss); + json_object_int_add( + json_group, "sourcesCount", + grp->group_source_list + ? listcount(grp->group_source_list) + : 0); + json_object_int_add(json_group, "version", + grp->igmp_version); + json_object_string_add(json_group, "uptime", uptime); + json_object_array_add(json_groups, json_group); + + if (detail) { + struct listnode *srcnode; + struct gm_source *src; + json_object *json_sources = NULL; + + json_sources = json_object_new_array(); + if (!json_sources) + return; + + json_object_object_add(json_group, "sources", + json_sources); + + for (ALL_LIST_ELEMENTS_RO( + grp->group_source_list, srcnode, + src)) { + char source_str[INET_ADDRSTRLEN]; + char mmss[PIM_TIME_STRLEN]; + char src_uptime[PIM_TIME_STRLEN]; + + pim_inet4_dump( + "", src->source_addr, + source_str, sizeof(source_str)); + pim_time_timer_to_mmss( + mmss, sizeof(mmss), + src->t_source_timer); + pim_time_uptime( + src_uptime, sizeof(src_uptime), + now - src->source_creation); + + igmp_source_json_helper( + src, json_sources, source_str, + mmss, src_uptime); + } + } + } + } else { + if (detail) { + struct listnode *srcnode; + struct gm_source *src; + + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, + srcnode, src)) { + char source_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("", src->source_addr, + source_str, sizeof(source_str)); + + vty_out(vty, + "%-16s %-15s %4s %8s %-15s %d %8s\n", + ifp->name, group_str, + grp->igmp_version == 3 + ? (grp->group_filtermode_isexcl + ? "EXCL" + : "INCL") + : "----", + hhmmss, source_str, grp->igmp_version, + uptime); + } + return; + } + + vty_out(vty, "%-16s %-15s %4s %8s %4d %d %8s\n", ifp->name, + group_str, + grp->igmp_version == 3 + ? (grp->group_filtermode_isexcl ? "EXCL" + : "INCL") + : "----", + hhmmss, + grp->group_source_list + ? listcount(grp->group_source_list) + : 0, + grp->igmp_version, uptime); + } +} + +static void igmp_show_groups_interface_single(struct pim_instance *pim, + struct vty *vty, bool uj, + const char *ifname, + const char *grp_str, bool detail) { struct interface *ifp; time_t now; json_object *json = NULL; - json_object *json_iface = NULL; - json_object *json_group = NULL; - json_object *json_groups = NULL; + struct pim_interface *pim_ifp = NULL; + struct gm_group *grp; now = pim_time_monotonic_sec(); if (uj) { json = json_object_new_object(); + if (!json) + return; json_object_int_add(json, "totalGroups", pim->gm_group_count); json_object_int_add(json, "watermarkLimit", pim->gm_watermark_limit); @@ -843,8 +1000,87 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) vty_out(vty, "Watermark warn limit(%s): %u\n", pim->gm_watermark_limit ? "Set" : "Not Set", pim->gm_watermark_limit); - vty_out(vty, - "Interface Group Mode Timer Srcs V Uptime \n"); + + if (!detail) + vty_out(vty, + "Interface Group Mode Timer Srcs V Uptime\n"); + else + vty_out(vty, + "Interface Group Mode Timer Source V Uptime\n"); + } + + ifp = if_lookup_by_name(ifname, pim->vrf->vrf_id); + if (!ifp) { + if (uj) + vty_json(vty, json); + return; + } + + pim_ifp = ifp->info; + if (!pim_ifp) { + if (uj) + vty_json(vty, json); + return; + } + + if (grp_str) { + struct in_addr group_addr; + struct gm_sock *igmp; + + if (inet_pton(AF_INET, grp_str, &group_addr) == 1) { + igmp = pim_igmp_sock_lookup_ifaddr( + pim_ifp->gm_socket_list, + pim_ifp->primary_address); + if (igmp) { + grp = find_group_by_addr(igmp, group_addr); + if (grp) + igmp_group_print(ifp, vty, uj, json, + grp, now, detail); + } + } + } else { + struct listnode *grpnode; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, grp)) + igmp_group_print(ifp, vty, uj, json, grp, now, detail); + } + + if (uj) { + if (detail) + vty_json_no_pretty(vty, json); + else + vty_json(vty, json); + } +} + +static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj, + const char *grp_str, bool detail) +{ + struct interface *ifp; + time_t now; + json_object *json = NULL; + + now = pim_time_monotonic_sec(); + + if (uj) { + json = json_object_new_object(); + if (!json) + return; + json_object_int_add(json, "totalGroups", pim->gm_group_count); + json_object_int_add(json, "watermarkLimit", + pim->gm_watermark_limit); + } else { + vty_out(vty, "Total IGMP groups: %u\n", pim->gm_group_count); + vty_out(vty, "Watermark warn limit(%s): %u\n", + pim->gm_watermark_limit ? "Set" : "Not Set", + pim->gm_watermark_limit); + if (!detail) + vty_out(vty, + "Interface Group Mode Timer Srcs V Uptime\n"); + else + vty_out(vty, + "Interface Group Mode Timer Source V Uptime\n"); } /* scan interfaces */ @@ -856,78 +1092,38 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) if (!pim_ifp) continue; - /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, - grp)) { - char group_str[INET_ADDRSTRLEN]; - char hhmmss[10]; - char uptime[10]; + if (grp_str) { + struct in_addr group_addr; + struct gm_sock *igmp; - pim_inet4_dump("", grp->group_addr, group_str, - sizeof(group_str)); - pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss), - grp->t_group_timer); - pim_time_uptime(uptime, sizeof(uptime), - now - grp->group_creation); - - if (uj) { - json_object_object_get_ex(json, ifp->name, - &json_iface); - - if (!json_iface) { - json_iface = json_object_new_object(); - json_object_pim_ifp_add(json_iface, - ifp); - json_object_object_add(json, ifp->name, - json_iface); - json_groups = json_object_new_array(); - json_object_object_add(json_iface, - "groups", - json_groups); + if (inet_pton(AF_INET, grp_str, &group_addr) == 1) { + igmp = pim_igmp_sock_lookup_ifaddr( + pim_ifp->gm_socket_list, + pim_ifp->primary_address); + if (igmp) { + grp = find_group_by_addr(igmp, + group_addr); + if (grp) + igmp_group_print(ifp, vty, uj, + json, grp, now, + detail); } - - json_group = json_object_new_object(); - json_object_string_add(json_group, "group", - group_str); - - if (grp->igmp_version == 3) - json_object_string_add( - json_group, "mode", - grp->group_filtermode_isexcl - ? "EXCLUDE" - : "INCLUDE"); - - json_object_string_add(json_group, "timer", - hhmmss); - json_object_int_add( - json_group, "sourcesCount", - grp->group_source_list ? listcount( - grp->group_source_list) - : 0); - json_object_int_add(json_group, "version", - grp->igmp_version); - json_object_string_add(json_group, "uptime", - uptime); - json_object_array_add(json_groups, json_group); - } else { - vty_out(vty, "%-16s %-15s %4s %8s %4d %d %8s\n", - ifp->name, group_str, - grp->igmp_version == 3 - ? (grp->group_filtermode_isexcl - ? "EXCL" - : "INCL") - : "----", - hhmmss, - grp->group_source_list ? listcount( - grp->group_source_list) - : 0, - grp->igmp_version, uptime); } - } /* scan igmp groups */ - } /* scan interfaces */ + } else { + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, + grpnode, grp)) + igmp_group_print(ifp, vty, uj, json, grp, now, + detail); + } + } /* scan interfaces */ - if (uj) - vty_json(vty, json); + if (uj) { + if (detail) + vty_json_no_pretty(vty, json); + else + vty_json(vty, json); + } } static void igmp_show_group_retransmission(struct pim_instance *pim, @@ -981,24 +1177,175 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, } /* scan interfaces */ } +static void igmp_sources_print(struct interface *ifp, char *group_str, + struct gm_source *src, time_t now, + json_object *json, struct vty *vty, bool uj) +{ + json_object *json_iface = NULL; + json_object *json_group = NULL; + json_object *json_sources = NULL; + char source_str[INET_ADDRSTRLEN]; + char mmss[PIM_TIME_STRLEN]; + char uptime[PIM_TIME_STRLEN]; + + pim_inet4_dump("", src->source_addr, source_str, + sizeof(source_str)); + pim_time_timer_to_mmss(mmss, sizeof(mmss), src->t_source_timer); + pim_time_uptime(uptime, sizeof(uptime), now - src->source_creation); + + if (uj) { + json_object_object_get_ex(json, ifp->name, &json_iface); + if (!json_iface) { + json_iface = json_object_new_object(); + if (!json_iface) + return; + json_object_string_add(json_iface, "name", ifp->name); + json_object_object_add(json, ifp->name, json_iface); + } + + json_object_object_get_ex(json_iface, group_str, &json_group); + if (!json_group) { + json_group = json_object_new_object(); + if (!json_group) + return; + json_object_string_add(json_group, "group", group_str); + json_object_object_add(json_iface, group_str, + json_group); + json_sources = json_object_new_array(); + if (!json_sources) + return; + json_object_object_add(json_group, "sources", + json_sources); + } + + json_object_object_get_ex(json_group, "sources", &json_sources); + if (json_sources) + igmp_source_json_helper(src, json_sources, source_str, + mmss, uptime); + } else { + vty_out(vty, "%-16s %-15s %-15s %5s %3s %8s\n", ifp->name, + group_str, source_str, mmss, + IGMP_SOURCE_TEST_FORWARDING(src->source_flags) ? "Y" + : "N", + uptime); + } +} + +static void igmp_show_sources_interface_single(struct pim_instance *pim, + struct vty *vty, bool uj, + const char *ifname, + const char *grp_str) +{ + struct interface *ifp; + time_t now; + json_object *json = NULL; + struct pim_interface *pim_ifp; + struct gm_group *grp; + + now = pim_time_monotonic_sec(); + + if (uj) { + json = json_object_new_object(); + if (!json) + return; + } else { + vty_out(vty, + "Interface Group Source Timer Fwd Uptime \n"); + } + + ifp = if_lookup_by_name(ifname, pim->vrf->vrf_id); + if (!ifp) { + if (uj) + vty_json(vty, json); + return; + } + + pim_ifp = ifp->info; + if (!pim_ifp) { + if (uj) + vty_json(vty, json); + return; + } + + if (grp_str) { + struct in_addr group_addr; + struct gm_sock *igmp; + struct listnode *srcnode; + struct gm_source *src; + char group_str[INET_ADDRSTRLEN]; + int res; + + res = inet_pton(AF_INET, grp_str, &group_addr); + if (res <= 0) { + if (uj) + vty_json(vty, json); + return; + } + + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, + pim_ifp->primary_address); + if (!igmp) { + if (uj) + vty_json(vty, json); + return; + } + + grp = find_group_by_addr(igmp, group_addr); + if (!grp) { + if (uj) + vty_json(vty, json); + return; + } + pim_inet4_dump("", grp->group_addr, group_str, + sizeof(group_str)); + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) + igmp_sources_print(ifp, group_str, src, now, json, vty, + uj); + } else { + struct listnode *grpnode; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, + grp)) { + char group_str[INET_ADDRSTRLEN]; + struct listnode *srcnode; + struct gm_source *src; + + pim_inet4_dump("", grp->group_addr, group_str, + sizeof(group_str)); + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, + srcnode, src)) + igmp_sources_print(ifp, group_str, src, now, + json, vty, uj); + + } /* scan igmp groups */ + } + + if (uj) + vty_json(vty, json); +} + static void igmp_show_sources(struct pim_instance *pim, struct vty *vty, bool uj) { struct interface *ifp; time_t now; json_object *json = NULL; - json_object *json_iface = NULL; - json_object *json_group = NULL; - json_object *json_source = NULL; - json_object *json_sources = NULL; now = pim_time_monotonic_sec(); - if (uj) + if (uj) { json = json_object_new_object(); - else + if (!json) + return; + } else { vty_out(vty, - "Interface Group Source Timer Fwd Uptime \n"); + "Interface Group Source Timer Fwd Uptime\n"); + } /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -1021,82 +1368,12 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty, /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, - srcnode, src)) { - char source_str[INET_ADDRSTRLEN]; - char mmss[10]; - char uptime[10]; - - pim_inet4_dump("", src->source_addr, - source_str, sizeof(source_str)); - - pim_time_timer_to_mmss(mmss, sizeof(mmss), - src->t_source_timer); - - pim_time_uptime(uptime, sizeof(uptime), - now - src->source_creation); - - if (uj) { - json_object_object_get_ex( - json, ifp->name, &json_iface); - if (!json_iface) { - json_iface = - json_object_new_object(); - json_object_string_add( - json_iface, "name", - ifp->name); - json_object_object_add( - json, ifp->name, - json_iface); - } - json_object_object_get_ex(json_iface, - group_str, - &json_group); - - if (!json_group) { - json_group = - json_object_new_object(); - json_object_string_add( - json_group, "group", - group_str); - json_object_object_add( - json_iface, group_str, - json_group); - json_sources = - json_object_new_array(); - json_object_object_add( - json_group, "sources", - json_sources); - } - json_source = json_object_new_object(); - json_object_string_add(json_source, - "source", - source_str); - json_object_string_add(json_source, - "timer", mmss); - json_object_boolean_add( - json_source, "forwarded", - IGMP_SOURCE_TEST_FORWARDING( - src->source_flags)); - json_object_string_add( - json_source, "uptime", uptime); - json_object_array_add(json_sources, - json_source); - - } else { - vty_out(vty, - "%-16s %-15s %-15s %5s %3s %8s\n", - ifp->name, group_str, - source_str, mmss, - IGMP_SOURCE_TEST_FORWARDING( - src->source_flags) - ? "Y" - : "N", - uptime); - } - - } /* scan group sources */ + srcnode, src)) + igmp_sources_print(ifp, group_str, src, now, + json, vty, uj); } /* scan igmp groups */ } /* scan interfaces */ + if (uj) vty_json(vty, json); } @@ -1227,7 +1504,7 @@ DEFUN (clear_ip_interfaces, VRF_CMD_HELP_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1247,7 +1524,7 @@ DEFUN (clear_ip_igmp_interfaces, "Reset IGMP interfaces\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1355,7 +1632,7 @@ DEFUN (clear_ip_pim_bsr_db, "Reset pim bsr data\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1378,8 +1655,8 @@ DEFUN (show_ip_igmp_interface, JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -1444,8 +1721,8 @@ DEFUN (show_ip_igmp_join, JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -1487,39 +1764,47 @@ DEFUN (show_ip_igmp_join_vrf_all, return CMD_SUCCESS; } -DEFUN (show_ip_igmp_groups, - show_ip_igmp_groups_cmd, - "show ip igmp [vrf NAME] groups [json]", - SHOW_STR - IP_STR - IGMP_STR - VRF_CMD_HELP_STR - IGMP_GROUP_STR - JSON_STR) +DEFPY(show_ip_igmp_groups, + show_ip_igmp_groups_cmd, + "show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail$detail] [json$json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + IGMP_GROUP_STR + "Interface name\n" + "Group address\n" + "Detailed Information\n" + JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); - bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json); if (!vrf) return CMD_WARNING; - igmp_show_groups(vrf->info, vty, uj); + if (ifname) + igmp_show_groups_interface_single(vrf->info, vty, !!json, + ifname, grp_str, !!detail); + else + igmp_show_groups(vrf->info, vty, !!json, NULL, !!detail); return CMD_SUCCESS; } -DEFUN (show_ip_igmp_groups_vrf_all, - show_ip_igmp_groups_vrf_all_cmd, - "show ip igmp vrf all groups [json]", - SHOW_STR - IP_STR - IGMP_STR - VRF_CMD_HELP_STR - IGMP_GROUP_STR - JSON_STR) +DEFPY(show_ip_igmp_groups_vrf_all, + show_ip_igmp_groups_vrf_all_cmd, + "show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + IGMP_GROUP_STR + "Group address\n" + "Detailed Information\n" + JSON_STR) { - bool uj = use_json(argc, argv); + bool uj = !!json; struct vrf *vrf; bool first = true; @@ -1533,7 +1818,7 @@ DEFUN (show_ip_igmp_groups_vrf_all, first = false; } else vty_out(vty, "VRF: %s\n", vrf->name); - igmp_show_groups(vrf->info, vty, uj); + igmp_show_groups(vrf->info, vty, uj, grp_str, !!detail); } if (uj) vty_out(vty, "}\n"); @@ -1552,7 +1837,7 @@ DEFUN (show_ip_igmp_groups_retransmissions, "IGMP group retransmissions\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1562,23 +1847,29 @@ DEFUN (show_ip_igmp_groups_retransmissions, return CMD_SUCCESS; } -DEFUN (show_ip_igmp_sources, - show_ip_igmp_sources_cmd, - "show ip igmp [vrf NAME] sources [json]", - SHOW_STR - IP_STR - IGMP_STR - VRF_CMD_HELP_STR - IGMP_SOURCE_STR - JSON_STR) +DEFPY(show_ip_igmp_sources, + show_ip_igmp_sources_cmd, + "show ip igmp [vrf NAME$vrf_name] sources [INTERFACE$ifname [GROUP$grp_str]] [json$json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + IGMP_SOURCE_STR + "Interface name\n" + "Group address\n" + JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json); if (!vrf) return CMD_WARNING; - igmp_show_sources(vrf->info, vty, use_json(argc, argv)); + if (ifname) + igmp_show_sources_interface_single(vrf->info, vty, !!json, + ifname, grp_str); + else + igmp_show_sources(vrf->info, vty, !!json); return CMD_SUCCESS; } @@ -1594,7 +1885,7 @@ DEFUN (show_ip_igmp_sources_retransmissions, "IGMP source retransmissions\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1617,8 +1908,8 @@ DEFUN (show_ip_igmp_statistics, JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -1746,7 +2037,7 @@ DEFUN (show_ip_pim_assert, "PIM interface assert\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1766,7 +2057,7 @@ DEFUN (show_ip_pim_assert_internal, "PIM interface internal assert state\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1786,7 +2077,7 @@ DEFUN (show_ip_pim_assert_metric, "PIM interface assert metric\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -1806,7 +2097,7 @@ DEFUN (show_ip_pim_assert_winner_metric, "PIM interface assert winner metric\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -2125,8 +2416,8 @@ DEFUN(show_ip_pim_mlag_up, show_ip_pim_mlag_up_cmd, 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); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf || !vrf->info) { vty_out(vty, "%s: VRF or Info missing\n", __func__); @@ -2598,7 +2889,7 @@ DEFUN (show_ip_rib, "Unicast address\n") { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); struct in_addr addr; const char *addr_str; struct pim_nexthop nexthop; @@ -2686,7 +2977,7 @@ DEFUN (show_ip_ssmpingd, VRF_CMD_HELP_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); if (!vrf) return CMD_WARNING; @@ -3141,8 +3432,8 @@ DEFUN (show_ip_pim_ssm_range, JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -3192,8 +3483,8 @@ DEFUN (show_ip_pim_group_type, JSON_STR) { int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -5086,7 +5377,7 @@ DEFUN (show_ip_msdp_mesh_group, bool uj = use_json(argc, argv); int idx = 2; struct pim_msdp_mg *mg; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); struct pim_instance *pim; struct json_object *json = NULL; @@ -5322,7 +5613,7 @@ DEFUN (show_ip_msdp_peer_detail, { bool uj = use_json(argc, argv); int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -5562,7 +5853,7 @@ DEFUN (show_ip_msdp_sa_detail, { bool uj = use_json(argc, argv); int idx = 2; - struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -5677,7 +5968,7 @@ DEFUN (show_ip_msdp_sa_sg, struct vrf *vrf; int idx = 2; - vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -5947,7 +6238,7 @@ DEFUN (show_ip_pim_vxlan_sg, struct vrf *vrf; int idx = 2; - vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; @@ -6007,7 +6298,7 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work, struct vrf *vrf; int idx = 2; - vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); if (!vrf) return CMD_WARNING; diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index fb6693491b..d39d77cd2f 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -60,4 +60,5 @@ void pim_cmd_init(void); +#define PIM_TIME_STRLEN 10 #endif /* PIM_CMD_H */ diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json new file mode 100644 index 0000000000..715aa1de72 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json @@ -0,0 +1 @@ +{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json new file mode 100644 index 0000000000..3bbcce1370 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json @@ -0,0 +1,51 @@ +{ + "totalGroups":5, + "watermarkLimit":0, + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "state":"up", + "address":"10.0.8.2", + "index":"*", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "groups":[ + { + "group":"225.1.1.1", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.2", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.3", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.4", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + }, + { + "group":"225.1.1.5", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + } + ] + } +} + diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json new file mode 100644 index 0000000000..876befa1b8 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json @@ -0,0 +1 @@ +{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json new file mode 100644 index 0000000000..a3fb496d25 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json @@ -0,0 +1,22 @@ +{ + "totalGroups":5, + "watermarkLimit":0, + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "state":"up", + "address":"10.0.8.2", + "index":"*", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "groups":[ + { + "group":"225.1.1.5", + "timer":"*", + "sourcesCount":1, + "version":2, + "uptime":"*" + } + ] + } +} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json new file mode 100644 index 0000000000..11ac5a01e7 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json @@ -0,0 +1 @@ +{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_group_all.json b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_group_all.json new file mode 100644 index 0000000000..10ae1afc90 --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_group_all.json @@ -0,0 +1,61 @@ +{ + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "225.1.1.1":{ + "group":"225.1.1.1", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.2":{ + "group":"225.1.1.2", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.3":{ + "group":"225.1.1.3", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.4":{ + "group":"225.1.1.4", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + }, + "225.1.1.5":{ + "group":"225.1.1.5", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + } + } +} + diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_single_group.json b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_single_group.json new file mode 100644 index 0000000000..7a19975bee --- /dev/null +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_source_single_if_single_group.json @@ -0,0 +1,16 @@ +{ + "l1-i1-eth1":{ + "name":"l1-i1-eth1", + "225.1.1.4":{ + "group":"225.1.1.4", + "sources":[ + { + "source":"*", + "timer":"*", + "forwarded":true, + "uptime":"*" + } + ] + } + } +} diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py index 2ffd3a3ac0..2c1241c0cc 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -42,6 +42,8 @@ import time import datetime import pytest from time import sleep +import json +import functools pytestmark = pytest.mark.pimd @@ -54,8 +56,8 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers -from lib.topogen import Topogen, get_topogen - +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen from lib.common_config import ( start_topology, write_test_header, @@ -1510,6 +1512,108 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): ) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + # IGMP JSON verification + step("Verify IGMP group and source JSON for single interface and group") + router = tgen.gears["l1"] + + reffile = os.path.join(CWD, "igmp_group_all_detail.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups detail json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group detailed output on l1 for all interfaces and all groups is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_group_all_brief.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group output on l1 for all groups in interface l1-i1-eth1 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_group_all_detail.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 detail json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group detailed output on l1 for all groups in interface l1-i1-eth1 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_single_group_brief.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 225.1.1.5 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group output on l1 for interface l1-i1-eth1 and group 225.1.1.5 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_single_if_single_group_detail.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp vrf default groups l1-i1-eth1 225.1.1.5 detail json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP group detailed output on l1 for interface l1-i1-eth1 and group 225.1.1.5 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_source_single_if_group_all.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp sources l1-i1-eth1 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP source output on l1 for interface l1-i1-eth1 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + + reffile = os.path.join(CWD, "igmp_source_single_if_single_group.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip igmp sources l1-i1-eth1 225.1.1.4 json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "IGMP source output on l1 for interface l1-i1-eth1 and group 225.1.1.4 is not as expected. Expected: {}".format( + expected + ) + assert res is None, assertmsg + step( "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from" " receiver interface of FRR1"