Skip to content

Instantly share code, notes, and snippets.

@scottchiefbaker
Created August 30, 2015 05:03
Show Gist options
  • Save scottchiefbaker/1db3b86b847aa16447a5 to your computer and use it in GitHub Desktop.
Save scottchiefbaker/1db3b86b847aa16447a5 to your computer and use it in GitHub Desktop.
Monitor port bandwidth via SNMP
#!/usr/bin/perl
use strict;
use Getopt::Long;
use Time::HiRes qw(time sleep);
use Net::SNMP;
#use Data::Dump::Color;
my $debug = 0;
my $delay = 3; # Default delay is 3 seconds
my $ok = GetOptions(
'debug' => \$debug,
'delay=i' => \$delay,
);
my @p = split(/@/,$ARGV[0]);
my $community = $p[0];
my $host = $p[1];
my $filter = $ARGV[1] || "";
if (!$community || !$host) {
die(usage());
}
print "Connecting to $host using $community\n";
my $s = snmp_connect($host,$community);
my $ints = get_interface_names($s);
my $int_count = scalar(keys(%$ints));
my $last = {};
while(1) {
my $start = time();
# Grab the interface stats
my $cur = get_interface_bandwidth($s);
# If we have previous data, output the bw
if (%$last) {
output_data($cur,$last);
}
my $elapsed = time() - $start;
my $remain = $delay - $elapsed;
if ($debug) {
printf("Sleeping for %0.2f seconds\n",$remain);
}
# Wait X seconds and grab the data again
sleep($remain);
$last = $cur; # Store the data to compare it
}
#############################################################
sub snmp_connect {
my ($host,$community) = @_;
my ($session, $error) = Net::SNMP->session(
-hostname => $host,
-community => $community,
-timeout => "30",
-port => "161"
);
if (!defined($session)) {
printf("ERROR: %s.\n", $error);
return undef;
}
return $session;
}
sub get_interface_bandwidth {
my $session = shift();
my $start = time();
# Get the output bytes
my $ret = {};
my $out_oid = ".1.3.6.1.2.1.2.2.1.16";
my $resp = $session->get_table($out_oid);
my $err = $session->error;
# Store each interface in a hash by name
foreach my $key(keys($resp)) {
my $bw = $resp->{$key};
my $int_num = int_num($key);
my $int_name = $ints->{$int_num};
$ret->{$int_name}->{out} = $bw;
}
if ($debug) {
my $total = sprintf("%0.2f",time() - $start);
print "Fetch out bandwidth took $total seconds\n";
}
##########################################################
$start = time();
# Get the input bytes
my $in_oid = ".1.3.6.1.2.1.2.2.1.17";
my $resp = $session->get_table($in_oid);
my $err = $session->error;
# Store each interface in a hash by name
foreach my $key(keys($resp)) {
my $bw = $resp->{$key};
my $int_num = int_num($key);
my $int_name = $ints->{$int_num};
$ret->{$int_name}->{in} = $bw;
}
if ($debug) {
my $total = sprintf("%0.2f",time() - $start);
print "Fetch in bandwidth took $total seconds\n";
}
return $ret;
}
sub get_interface_names {
my $session = shift();
my $ret = {};
my $oid = "1.3.6.1.2.1.2.2.1.2";
my $start = time();
my $response = $session->get_table($oid);
my $err = $session->error;
if ($debug) {
my $total = sprintf("%0.2f",time() - $start);
print "Fetch interface names took $total seconds\n";
}
# We're maping the IDs to the name of the interface
foreach my $key(keys($response)) {
my $value = $response->{$key};
my $int_num = int_num($key);
$ret->{$int_num} = $value;
}
return $ret;
}
# Convert an OID to an interface number
sub int_num {
my $str = shift();
# Remove everything up to the LAST period
$str =~ s/.+\.//;
return $str;
}
sub output_data {
my ($cur,$last) = @_;
my @ints = sort(keys($cur));
# Find the length of the longest interface name
my $max_len = 0;
foreach (@ints) {
my $len = length($_);
if ($len > $max_len) {
$max_len = $len;
}
}
my $date = mysql_date(1);
# Print the date header
print color("15bold");
printf("$date\n");
print "-" x length($date) . "\n";
print color();
# Loop through each interface, calculate the bytes between the
# previous data and now
foreach my $name (@ints) {
my $prev = $last->{$name}->{out};
my $now = $cur->{$name}->{out};
my $out_total = $now - $prev;
my $out_str = human_size(int($out_total / $delay));
my $prev = $last->{$name}->{in};
my $now = $cur->{$name}->{in};
my $in_total = $now - $prev;
my $in_str = human_size(int($in_total / $delay));
# If there is no filter, or the line matches the filter spit it out
if (!$filter || $name =~ /$filter/) {
my $open_color = color(14);
my $reset_color = color();
printf("$open_color%-${max_len}s$reset_color = $out_str/$in_str\n",$name);
print color();
}
}
print "\n";
}
sub mysql_date {
my ($inc_time,$epoch) = @_;
$epoch ||= time();
my @date = localtime($epoch);
my $ret = sprintf("%04d-%02d-%02d", $date[5] + 1900, $date[4] + 1, $date[3]);
if ($inc_time) { $ret .= sprintf(" %02d:%02d:%02d", $date[2], $date[1], $date[0]); }
return $ret;
}
sub usage {
return "Usage: $0 community\@hostname [filter]\n";
}
# String format: '115', '165bold', '10_on_140', 'reset', 'on_173'
sub color {
my $str = shift();
# If we're connected to a TTY don't do color
if (-t STDOUT == 0) { return ''; }
# No string sent in, so we just reset
if (!$str || $str eq 'reset') {
return "\e[0m";
}
# Get foreground and bold
my ($fc,$bold) = $str =~ /^(\d+)(b|bold)?/g;
# Get the background color (if present)
my ($bc) = $str =~ /on_?(\d+)$/g;
my $ret = '';
if ($bold) { $ret .= "\e[1m"; }
if ($fc) { $ret .= "\e[38;5;${fc}m"; }
if ($bc) { $ret .= "\e[48;5;${bc}m"; }
return $ret;
}
sub human_size {
my $size = shift();
my $color = '';
my $reset = color();
if ($size > 1024**3) {
$color = color(12); # Blue
$size = sprintf("%.1fG",$size / 1024**3);
} elsif ($size > 1024**2) {
$color = color(10); # Green
$size = sprintf("%.1fM",$size / 1024**2);
} elsif ($size > 1024) {
$color = color(11); # Yellow
$size = sprintf("%.1fK",$size / 1024);
} elsif ($size >= 0) {
$color = color(9); # Red
$size = sprintf("%dB",$size);
}
$size = $color . $size . $reset;
return $size;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment