pimd: show ip igmp statistics command

Command showing IGMP Rx statistics, useful for analyzing IGMP
activity on interfaces.

Signed-off-by: Mladen Sablic <mladen.sablic@gmail.com>
This commit is contained in:
Mladen Sablic 2018-05-04 13:25:38 +02:00
parent 1c96f2fb96
commit 21313cbfda
10 changed files with 225 additions and 0 deletions

View File

@ -24,6 +24,7 @@ verification commands:
show ip igmp groups retransmissions IGMP group retransmission
show ip igmp sources IGMP sources information
show ip igmp sources retransmissions IGMP source retransmission
show ip igmp statistics IGMP statistics information
show ip pim address PIM interface address
show ip pim assert PIM interface assert
show ip pim assert-internal PIM interface internal assert state

View File

@ -1294,6 +1294,76 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
}
}
static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
const char *ifname, uint8_t uj)
{
struct interface *ifp;
struct igmp_stats rx_stats;
igmp_stats_init(&rx_stats);
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
struct listnode *sock_node;
struct igmp_sock *igmp;
pim_ifp = ifp->info;
if (!pim_ifp)
continue;
if (ifname && strcmp(ifname, ifp->name))
continue;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
igmp)) {
igmp_stats_add(&rx_stats, &igmp->rx_stats);
}
}
if (uj) {
json_object *json = NULL;
json_object *json_row = NULL;
json = json_object_new_object();
json_row = json_object_new_object();
json_object_string_add(json_row, "name", ifname ? ifname :
"global");
json_object_int_add(json_row, "queryV1", rx_stats.query_v1);
json_object_int_add(json_row, "queryV2", rx_stats.query_v2);
json_object_int_add(json_row, "queryV3", rx_stats.query_v3);
json_object_int_add(json_row, "leaveV3", rx_stats.leave_v2);
json_object_int_add(json_row, "reportV1", rx_stats.report_v1);
json_object_int_add(json_row, "reportV2", rx_stats.report_v2);
json_object_int_add(json_row, "reportV3", rx_stats.report_v3);
json_object_int_add(json_row, "mtraceResponse",
rx_stats.mtrace_rsp);
json_object_int_add(json_row, "mtraceRequest",
rx_stats.mtrace_req);
json_object_int_add(json_row, "unsupported",
rx_stats.unsupported);
json_object_object_add(json, ifname ? ifname : "global",
json_row);
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, "IGMP RX statistics\n");
vty_out(vty, "Interface : %s\n",
ifname ? ifname : "global");
vty_out(vty, "V1 query : %u\n", rx_stats.query_v1);
vty_out(vty, "V2 query : %u\n", rx_stats.query_v2);
vty_out(vty, "V3 query : %u\n", rx_stats.query_v3);
vty_out(vty, "V2 leave : %u\n", rx_stats.leave_v2);
vty_out(vty, "V1 report : %u\n", rx_stats.report_v1);
vty_out(vty, "V2 report : %u\n", rx_stats.report_v2);
vty_out(vty, "V3 report : %u\n", rx_stats.report_v3);
vty_out(vty, "mtrace response : %u\n", rx_stats.mtrace_rsp);
vty_out(vty, "mtrace request : %u\n", rx_stats.mtrace_req);
vty_out(vty, "unsupported : %u\n", rx_stats.unsupported);
}
}
static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
uint8_t uj)
{
@ -3527,6 +3597,33 @@ DEFUN (show_ip_igmp_sources_retransmissions,
return CMD_SUCCESS;
}
DEFUN (show_ip_igmp_statistics,
show_ip_igmp_statistics_cmd,
"show ip igmp [vrf NAME] statistics [interface WORD] [json]",
SHOW_STR
IP_STR
IGMP_STR
VRF_CMD_HELP_STR
"IGMP statistics\n"
"interface\n"
"IGMP interface\n"
JSON_STR)
{
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
uint8_t uj = use_json(argc, argv);
if (!vrf)
return CMD_WARNING;
if (argv_find(argv, argc, "WORD", &idx))
igmp_show_statistics(vrf->info, vty, argv[idx]->arg, uj);
else
igmp_show_statistics(vrf->info, vty, NULL, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_assert,
show_ip_pim_assert_cmd,
"show ip pim [vrf NAME] assert",
@ -8644,6 +8741,7 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
install_element(VIEW_NODE, &show_ip_igmp_sources_cmd);
install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd);
install_element(VIEW_NODE, &show_ip_igmp_statistics_cmd);
install_element(VIEW_NODE, &show_ip_pim_assert_cmd);
install_element(VIEW_NODE, &show_ip_pim_assert_internal_cmd);
install_element(VIEW_NODE, &show_ip_pim_assert_metric_cmd);

View File

@ -303,6 +303,21 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version,
return -1;
}
/* Collecting IGMP Rx stats */
switch (query_version) {
case 1:
igmp->rx_stats.query_v1++;
break;
case 2:
igmp->rx_stats.query_v2++;
break;
case 3:
igmp->rx_stats.query_v3++;
break;
default:
igmp->rx_stats.unsupported++;
}
/*
* RFC 3376 defines some guidelines on operating in backwards
* compatibility with older versions of IGMP but there are some gaps in
@ -400,6 +415,9 @@ static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from,
return -1;
}
/* Collecting IGMP Rx stats */
igmp->rx_stats.report_v1++;
if (PIM_DEBUG_IGMP_TRACE) {
zlog_warn("%s %s: FIXME WRITEME", __FILE__,
__PRETTY_FUNCTION__);
@ -524,6 +542,9 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
/* Collecting IGMP Rx stats */
igmp->rx_stats.unsupported++;
return -1;
}
@ -867,6 +888,8 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
pim_ifp->igmp_default_robustness_variable;
igmp->sock_creation = pim_time_monotonic_sec();
igmp_stats_init(&igmp->rx_stats);
if (mtrace_only) {
igmp->mtrace_only = mtrace_only;
return igmp;

View File

@ -25,6 +25,7 @@
#include <zebra.h>
#include "vty.h"
#include "linklist.h"
#include "pim_igmp_stats.h"
/*
The following sizes are likely to support
@ -94,6 +95,8 @@ struct igmp_sock {
struct list *igmp_group_list; /* list of struct igmp_group */
struct hash *igmp_group_hash;
struct igmp_stats rx_stats;
};
struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list,

View File

@ -671,6 +671,9 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
return -1;
}
/* Collecting IGMP Rx stats */
igmp->rx_stats.mtrace_req++;
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
@ -881,6 +884,9 @@ int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr,
mtracep->checksum = checksum;
/* Collecting IGMP Rx stats */
igmp->rx_stats.mtrace_rsp++;
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);

42
pimd/pim_igmp_stats.c Normal file
View File

@ -0,0 +1,42 @@
/*
* PIM for FRRouting
* Copyright (C) 2018 Mladen Sablic
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "pim_igmp_stats.h"
void igmp_stats_init(struct igmp_stats *stats)
{
memset(stats, 0, sizeof(struct igmp_stats));
}
void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b)
{
if (!a || !b)
return;
a->query_v1 += b->query_v1;
a->query_v2 += b->query_v2;
a->query_v3 += b->query_v3;
a->report_v1 += b->report_v1;
a->report_v2 += b->report_v2;
a->report_v3 += b->report_v3;
a->leave_v2 += b->leave_v2;
a->mtrace_rsp += b->mtrace_rsp;
a->mtrace_req += b->mtrace_req;
a->unsupported += b->unsupported;
}

41
pimd/pim_igmp_stats.h Normal file
View File

@ -0,0 +1,41 @@
/*
* PIM for FRRouting
* Copyright (C) 2018 Mladen Sablic
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PIM_IGMP_STATS_H
#define PIM_IGMP_STATS_H
#include <zebra.h>
struct igmp_stats {
uint32_t query_v1;
uint32_t query_v2;
uint32_t query_v3;
uint32_t report_v1;
uint32_t report_v2;
uint32_t report_v3;
uint32_t leave_v2;
uint32_t mtrace_rsp;
uint32_t mtrace_req;
uint32_t unsupported;
};
void igmp_stats_init(struct igmp_stats *stats);
void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b);
#endif /* PIM_IGMP_STATS_H */

View File

@ -121,6 +121,9 @@ int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from,
return -1;
}
/* Collecting IGMP Rx stats */
igmp->rx_stats.report_v2++;
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
if (PIM_DEBUG_IGMP_PACKETS) {
@ -167,6 +170,9 @@ int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from,
return -1;
}
/* Collecting IGMP Rx stats */
igmp->rx_stats.leave_v2++;
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
if (PIM_DEBUG_IGMP_PACKETS) {

View File

@ -1900,6 +1900,9 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
return -1;
}
/* Collecting IGMP Rx stats */
igmp->rx_stats.report_v3++;
num_groups = ntohs(
*(uint16_t *)(igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
if (num_groups < 1) {

View File

@ -20,6 +20,7 @@ pimd_libpim_a_SOURCES = \
pimd/pim_ifchannel.c \
pimd/pim_igmp.c \
pimd/pim_igmp_mtrace.c \
pimd/pim_igmp_stats.c \
pimd/pim_igmpv2.c \
pimd/pim_igmpv3.c \
pimd/pim_instance.c \
@ -69,6 +70,7 @@ noinst_HEADERS += \
pimd/pim_igmp.h \
pimd/pim_igmp_join.h \
pimd/pim_igmp_mtrace.h \
pimd/pim_igmp_stats.h \
pimd/pim_igmpv2.h \
pimd/pim_igmpv3.h \
pimd/pim_instance.h \