Skip to content

Commit

Permalink
pimd: show ip igmp statistics command
Browse files Browse the repository at this point in the history
Command showing IGMP Rx statistics, useful for analyzing IGMP
activity on interfaces.

Signed-off-by: Mladen Sablic <[email protected]>
  • Loading branch information
msablic committed May 4, 2018
1 parent 1c96f2f commit 21313cb
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 0 deletions.
1 change: 1 addition & 0 deletions pimd/COMMANDS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
98 changes: 98 additions & 0 deletions pimd/pim_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 23 additions & 0 deletions pimd/pim_igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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__);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions pimd/pim_igmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions pimd/pim_igmp_mtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
42 changes: 42 additions & 0 deletions pimd/pim_igmp_stats.c
Original file line number Diff line number Diff line change
@@ -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 changes: 41 additions & 0 deletions pimd/pim_igmp_stats.h
Original file line number Diff line number Diff line change
@@ -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 */
6 changes: 6 additions & 0 deletions pimd/pim_igmpv2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions pimd/pim_igmpv3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions pimd/subdir.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down

0 comments on commit 21313cb

Please sign in to comment.