#!/usr/bin/perl
#
# findnonpruners.snmp
# Bill Fenner <fenner@parc.xerox.com> 17 April 1997
# Version 1.0
# $Id: findnonpruners.snmp,v 1.1 1997/06/05 21:08:20 fenner Exp $
#
# HOW TO RUN:
# mstat -M node | findnonpruners.snmp
#
# HOW IT WORKS:
# Try to find non-pruning multicast routers by analyzing the output
# of "mstat -M".  We do this by counting the number of (S,G)
# entries in which an interface is listed against the number of
# (S,G) entries in which that interface is listed as in Forward state.
# A ratio of 100% has one of four meanings:
# 1) The interface is in sparse mode.  This script tries to ignore
#    sparse mode interfaces, but it's untested.  Sparse mode interfaces
#    foil this script's heuristic, so if it points towards a sparse mode
#    interface you can just ignore it.
# 2) The interface has no multicast router neighbors, only group members.
# 3) There are members of every group that traffic is flowing through
#    this router towards that interface.  This is a possibility if the numbers
#    printed are small (e.g. "18/18 (100%)").
# 4) There is a non-pruning router in the direction of that interface.  It's
#    not necessarily the direct neighbor on that interface, but it's somewhere
#    downstream of that neighbor.
#
# A count of over 95% is also marked, as "suspicious".  These may be
# measurement errors and "should" be 100%, or may be normal.
# If you have any "suspicious" entries, you should rerun the script
# at various times of the day and see if/how the percentages change.
# If they indicate PIM dense-mode flooding, the numbers should not stay
# consistently high, but if they indicate a non-pruner they will continue
# to be flagged.


# Walk through "mstat -M" output, noting how many times each
# interface is mentioned at all, and how many times it's in Forward
# state.
while (<>) {
#NTP.MCAST.NET   0.0.0.0/32          1 224.0.1.1       forwarding 938600   0
	if (($grp,$src,$oif,$state) = /^(\S+)\s+(\S+)\s+(\d+)\s+\S+\s+(\S+)/) {
		next if ($src =~ /0\.0\.0\.0/);
		$nchild{$oif}++;
		$nforward{$oif}++ if ($state eq "forwarding");
	}
}

foreach $i (sort keys %nforward) {
	next if ($nforward{$i} == 0 || $nchild{$i} == 0);
	if ($nchild{$i} == 0) {
		print "$i: $nforward{$i}/$nchild{$i}!?\n";
		next;
	}
	printf "%s: %d/%d (%d%%)", $i, $nforward{$i}, $nchild{$i},
				$nforward{$i} * 100 / $nchild{$i};
	if ($nforward{$i} >= $nchild{$i}) {
		print " <- possible non-pruner";
	} elsif ($nforward{$i} / $nchild{$i} > 0.95) {
		print " <- suspicious amount of traffic";
	}
	print "\n";
}
