NAME
Net::SNMP::Util - Utility functions for Net::SNMP
SYNOPSIS
@hosts = qw( host1 host2 host3 );
%oids = (
'ifData => [ '1.3.6.1.2.1.2.2.1.2', # ifDescr
'1.3.6.1.2.1.2.2.1.3' ], # ifType
'someMib' => '1.3.6.1.4.1.99999.12.3'
);
%snmpparams = (
-version => 2,
-community => "comname"
);
# Blocking Function
use Net::SNMP::Util;
($result,$error) = snmpawlk(
hosts => \@hosts,
oids => \%oids,
snmp => \%snmpparams
);
die "[ERROR] $error\n" unless defined $result;
# NonBlocking One
use Net::SNMP::Util qw(:para);
($result,$error) = snmpparawalk(
hosts => \@hosts,
oids => \%oids,
snmp => \%snmpparams
);
die "[ERROR] $error\n" unless defined $result;
# result
foreach $h ( @hosts ){
foreach $index ( sort keys %{$result->{$h}{ifData}[0]} ){
printf "$h - $index - %s (%d)\n",
$result->{$h}{ifData}[0]{$index}, # ifDescr
$result->{$h}{ifData}[1]{$index}; # ifType
}
while ( ($index, $val) = each %{$result->{$h}{someMib}} ){
print "$h - .1.3.6.1.4.1.99999.12.3.$index - $val\n";
}
}
DESCRIPTION
This module, Net::SNMP::Util
, gives you functions of SNMP getting operation interfaces using Net::SNMP
.
OVERVIEW
Functions of Net::SNMP::Util
are grouped by type whether using Blocking mode or NonBlocking mode.
Blocking Functions
Blocking functions, snmpget()
, snmpwalk()
and snmpbulk()
, are exported by defalut. These functions use Net::SNMP
blocking object and exchange SNMP messages serially by specified hosts ordering.
NonBlocking Functions
Using tag ":para"
or ":parallel"
, NonBlocking functions which use Net::SNMP
non-blocking object are exported. These functions exchange SNMP messages to hosts and treat responsed MIB values in order of message receiving while the loop. These functions will apparently behave in parallel, so they have "para" in its own names.
Parameters
The way of passing parameters is unified whether function is NonBlocking or Blocking. Basically pass parametes with name and following value like hash pair below;
$r = snmpwalk( hosts => $hostsval,
oids => $oidval,
snmp => $snmpval );
Original Net::SNMP
functions' parameters are able to be passed.
$r = snmpparabulk(
hosts => $hostsval, oids => $oidval, snmp => $snmpval
-maxrepetitions => 20,
-delay => 2,
);
But some original parameter, -callback
, -nonrepeaters
and -varbindlist
are not supported by reason of algorithm.
- Parameter "hosts"
-
Specify hosts list by parameter
"hosts"
with following a hash or array reference or hostname. Following a hash reference, it is possible to use preparedNet::SNMP
object like below;# Using hash reference with prepared Net::SNMP object $session1 = Net::SNMP->session( -hostname=>"www.freshes.org", ... ); $session2 = Net::SNMP->session( -hostname=>"192.168.10.8", ... ); $r = snmpwalk( hosts => { "peach" => $session1, "berry" => $session2, ... }, ... );
Note that host names of keys above are not set for target hosts to communicate with SNMP but just used to classfy result.
Except the way of using prepered object above, temporary
Net::SNMP
session object will be made, used and deleted internally and automaticaly.Hash reference case as following, values will be passed to
Net::SNMP->session()
as its parameters.# Using hash reference with parameters $r = snmpwalk( hosts => { "pine" => { -hostname => "192.168.20.8", -version => 2, }, }, ... );
More parameter
"snmp"
paired with hash reference, it regards as common parameters for each temporary session making.# Using hash reference with parameters $r = snmpwalk( hosts => { "peach" => { -hostname => "www.freshes.org" }, "berry" => { -hostname => "192.168.10.8" }, "pine" => { -hostname => "192.168.20.8", -version => 2, }, }, snmp => { -community => "secchan", -timeout => 10 }, );
In this hash case, host names of keys (e.g. "www1", "www2" and "www3" above) are also just used for classfying.
Array reference using and host name specifying are here. Use parameter
"snmp"
as case above for common parameter specifying.# Using array reference $r = snmpwalk( hosts => [ "www.freshes.org", "192.168.10.8", "192.168.20.8" ], # hosts => "www.freshes.org", # check just only this one snmp => { -version => 2, -community => "myprecures", -timeout => 10 }, );
Note that, against hashref case, in the way above, specified hosts or IP address are used for SNMP communication and also used result classfying.
- Parameter "oids"
-
Specify OIDs by parameter
"oids"
with following hash reference.This hash's key must be a convinient MIB name to classfy. Values must be a array reference listing OIDs, or OID string.
$r = snmpwalk( hosts => \@hosts, oids => { "system" => "1.3.6.1.2.1.1", "ifInfo" => [ "1.3.6.1.2.1.2.2.1.3", # ifType "1.3.6.1.2.1.31.1.1.1.1", # ifName ] }, ... );
Each value of this
"oids"
hash will be a set of Var Bindings. So giving several OIDs with array reference, Var Bindings will contains all of OIDs in the array. - Parameter "snmp"
-
If parameter
"hosts"
specified, parameter "snmp" will behave common parameter toNet::SNMP->session()
mentioned above.Well, it is possible to omit parameter
"host"
. In this case, value of"snmp"
will be used to specify the target. Same as "hosts", preparedNet::SNMP
session object and giving a hash reference are allowed.# Prepared session $session = Net::SNMP->session( -hostname => "blossom", ... ); $r = snmpwalk( snmp => $session, oid => ... , ... ); # Temporary session $r = snmpwalk( snmp => { -hostname => "marine", -community => "heartcatchers", }, oid => ... , ... );
- Forbidding for parameter specifying
-
It will be an error below;
Parameter
"snmp"
with preparedNet::SNMP
object is specified at the same time"hosts"
specified. Chomp parameter"hosts"
or make parameter"snmp"
hash reference.# NG $session = Net::SNMP->session( ... ); $r = snmpwalk( hosts => \%something, snmp => $session, );
NonBlocking prepared
Net::SNMP
object are given as"hosts"
or"snmp"
value to Blocking functions.Blocking prepared
Net::SNMP
object are given as"hosts"
or"snmp"
value to NonBlocking functions.
Return Values
Errors
In list context, result value and errors message string will be return. In scalar, only result value will be return. In both case, critical errors will make result value undef and make errors message string.
If several host checking and error occured while communicating with some hosts, error messages string will be chained with these messages. For checking errors by host individually or in scalar context, use functions get_errhash()
. This function will return a hash reference which contains messages for each hosts.
Gained MIB Values
In success, gained MIB value will be packed into a hash with key as specified MIB name.
For example, snmpget()
and snmpparaget()
operations;
snmpget( oids => {
sysDescr => "1.3.6.1.2.1.1.1.0",
sysUpTime => "1.3.6.1.2.1.1.3.0", }
... );
yeilds;
{
sysDescr => "Description...",
sysUpTime => "24 days, 23:55:24.00",
}
And other functions, value will be a more hash which contains pairs of key as sub OID and its values. For example;
snmpwalk( oids => {
ifType => "1.3.6.1.2.1.2.2.1.3",
ifName => "1.3.6.1.2.1.31.1.1.1.1", }
... );
yeilds;
{
"ifType" => {
"1" => 62, # 1.3.6.1.2.1.2.2.1.3.1
"10101" => 62, # 1.3.6.1.2.1.2.2.1.3.10101
...
},
"ifName" => {
# Sub OID
"1" => "mgmt", # 1.3.6.1.2.1.31.1.1.1.1.1
"10101" => "1/1", # 1.3.6.1.2.1.31.1.1.1.1.10101
...
}
}
If specifying OID with array reference, values will be contained in an array. For example;
snmpget( oids => {
system => [ "1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0" ]
}, ... );
yeilds;
{
'system' => [
'8860 System Panel 8.1.0.1.4635 (MIB = 8.1.8.1)',
'25 days, 00:41:40.00'
]
}
and;
snmpwalk( oids => {
ifData => [ "1.3.6.1.2.1.2.2.1.3", "1.3.6.1.2.1.31.1.1.1.1" ]
}, ... );
yeilds;
{
'ifData' => [
{
"1" => 62, # 1.3.6.1.2.1.2.2.1.3.1
"10101" => 62, # 1.3.6.1.2.1.2.2.1.3.10101
...
},
{
"1" => "mgmt", # 1.3.6.1.2.1.31.1.1.1.1.1
"10101" => "1/1", # 1.3.6.1.2.1.31.1.1.1.1.10101
...
}
]
}
If parameter "snmp"
decides target host without "hosts"
, result data will be the same as above. If not so, parameter "hosts"
is specified, result data for each host will be contained to parentally hash which member will be identified by host name.
e.g.;
use Data::Dumper;
print Dumper(scalar(
snmpget(
hosts => [ "bloom", "eaglet" ],
oids => {
system => [ "1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0" ]
}, ...
)
));
will print;
$VAR1 = {
"bloom" => {
"system" => [
...VALUES...
]
},
"eaglet" => {
"system" => [
...VALUES...
]
}
};
Callback function
Apart from original -callback
option of functions of Net::SNMP
, Net::SNMP::Util
functions provides another callback logic. Common option, -mycallback
, is that. This option is possible to be used whether NonBlocking or Blocking.
This callback function will be called when each MIB value recieving. At calling, session object, host name, key name and reference to array of values are passed to the function.
For example, snmpget()
and snmpparaget()
operations, array contains values which order is same as a member of parameter "oids"
specifys.
snmpget(
hosts => \%hosts,
oids => { someMIB1 => $oid1, someMIB2 => [ $oid2, $oid3, $oid4 ] },
-mycallback => sub {
($session, $host, $key, $valref) = @_;
# When $valX is value of $oidX, $valref is;
# [ $val1 ] when $key is "someMIB1"
# or
# [ $val2, $val3, $val4 ] when $key is "someMIB2"
}
);
Other functions, passing array reference will contain more array references which will have two value, sub OID and value. Values ordering rule is, same as above, a member of parameter "oids"
specifys.
snmpwalk(
hosts => \%hosts,
oids => { someMIB1 => $oid1, someMIB2 => [ $oid2, $oid3, $oid4 ] },
-mycallback => sub {
($session, $host, $key, $valref) = @_;
# $valref is;
# [ [ $suboid1, $val1 ] ] when $key is "someMIB1"
# or
# [ [ $suboid2,$val2 ], [ $suboid3,$val3 ], [ $suboid4,$val4 ] ]
# when $key is "someMIB2"
}
);
BLOCKING FUNCTIONS
Net::SNMP::Util
exports bloking functions defalut.
snmpget()
snmpget()
is a Blocking function which gather MIB values with SNMP GetRequest operation via Net::SNMP->get_request()
.
snmpwalk()
snmpwalk()
is a Blocking function which gather MIB values with SNMP GetNextRequest operation via Net::SNMP->get_next_request()
.
snmpbulk()
snmpbulk()
is a Blocking function which gather MIB values with SNMP GetBulkRequest operation via Net::SNMP->get_bulk_request()
. So using this function needs that target devices are acceptable for SNMP version 2c or more.
Note that specify option -maxrepetitions
with some value. Net::SNMP
set this parameter 0 by defalut. Also note that reason of algorithm, -nonrepeaters is not supported.
snmpbulkwalk()
An alias of snmpbulk()
.
NON-BLOCKING FUNCTIONS
Net::SNMP::Util
gives some NonBlocking functions. Use these NonBlocking functions, import them with ":para" tag at use
pragma.
snmpparaget()
snmpparaget()
is a NonBlocking function which gather MIB values with SNMP GetRequest operation via Net::SNMP->get_request()
.
snmpparawalk()
snmpparawalk()
is a NonBlocking function which gather MIB values with SNMP GetNextRequest operation via Net::SNMP->get_next_request()
.
snmpparabulk()
snmpparabulk()
is a NonBlocking function which gather MIB values with SNMP GetBulkRequest operation via Net::SNMP->get_bulk_request()
. So using this function needs that target devices are acceptable for SNMP version 2c or more.
Note that specify option -maxrepetitions
with some value. Net::SNMP
set this parameter 0 by defalut. Also note that reason of algorithm, -nonrepeaters is not supported.
snmpparabulkwalk()
An alias of snmpparabulk()
.
OTHER FUNCTIONS
get_errstr()
$lasterror = get_errstr();
get_errstr()
returns last error message string that is chained all of error messages for each hosts.
get_errhash()
$lasterror = get_errhash();
get_errhash()
returns hash reference which contains last error messages identified by host names.
HINTS
Net::SNMP::Util
has sub modules; Net::SNMP::Util::OID
and Net::SNMP::Util::TC
.
Net::SNMP::Util::OID gives MIBname-OID converter utilities. For example, you can specify basic OIDs when call function like below;
use Net::SNMP::Util::OID qw(if*); # import if* MIB name maps
%oids = (
sysInfo => [
oid("ifDescr","ifType") # '1.3.6.1.2.1.2.2.1.2','1.3.6.1.2.1.2.2.1.3'
],
oidm("ifName") # "ifName" => "1.3.6.1.2.1.31.1.1.1.1"
);
($result,$error) = snmpparaawlk(
hosts => \@hosts,
oids => \%oids,
snmp => \%snmpparams
);
Net::SNMP::Util::TC gives MIBEnumValue-Text convertor utilities. For example, you can convert value of ifAdminStatus, ifOperStatus and ifType like below;
use Net::SNMP::Util::TC;
$tc = Net::SNMP::Util::TC->new;
$astat = $tc->ifAdminStatus( $value_admin_stat ); # "up", "down" or etc.
$ostat = $tc->ifOperStatus( $value_oper_stat );
$iftype = $tc->ifType( $value_iftype ); # "ethernet-csmacd" or etc.
PRACTICAL EXAMPLES
1. Check system information simply
This example get some system entry MIB values from several hosts with snmpget()
.
#!/usr/local/bin/perl
use strict;
use warnings;
use Getopt::Std;
use Net::SNMP::Util;
my %opt;
getopts('hv:c:r:t:', \%opt);
sub HELP_MESSAGE {
print "Usage: $0 [-v VERSION] [-c COMMUNITY_NAME] ".
"[-r RETRIES] [-t TIMEOUT] HOST [,HOST2 ...]\n";
exit 1;
}
HELP_MESSAGE() if ( !@ARGV || $opt{h} );
(my $version = ($opt{v}||2)) =~ tr/1-3//cd; # now "2c" is ok
my ($ret, $err) = snmpget(
hosts => \@ARGV,
snmp => { -version => $version,
-timeout => $opt{t} || 5,
-retries => $opt{r} || 1,
-community => $opt{c} || "public" },
oids => { descr => '1.3.6.1.2.1.1.1.0',
uptime => '1.3.6.1.2.1.1.3.0',
name => '1.3.6.1.2.1.1.5.0',
location => '1.3.6.1.2.1.1.6.0',
}
);
die "[ERROR] $err\n" unless defined $ret;
foreach my $h ( @ARGV ){
if ( $ret->{$h} ){
printf "%s @%s (up %s) - %s\n",
map { $ret->{$h}{$_} or 'N/A' } qw(name location uptime descr);
} else {
printf "%s [ERROR]%s\n", $h, $err->{$h};
}
}
__END__
2. Realtime monitor of host interfaces (SNMPv2c)
This program shows realtime traffic throughput of interfaces of a host on your console with using snmpwalk()
and callbacking.
Notice: This program is for devices which can deal SNMP version 2c.
#!/usr/local/bin/perl
use strict;
use warnings;
use Getopt::Std;
use Term::ANSIScreen qw/:color :screen :constants/;
use Net::SNMP::Util;
my %opt;
getopts('hv:c:w:x:', \%opt);
my $host = shift @ARGV;
sub HELP_MESSAGE {
print "Usage: $0 [-c COMMUNITY_NAME] [-w WAIT] [-x REGEXP] HOST\n";
exit 1;
}
HELP_MESSAGE() if ( !$host || $opt{h} );
my ($wait,$regexp) = ($opt{w}||5, $opt{x}? qr/$opt{x}/: '');
my $console = Term::ANSIScreen->new();
local $| = 1;
# make session
my ($ses, $err) = Net::SNMP->session(
-hostname => $host,
-version => "2",
-community => ($opt{c} || "public")
);
die "[ERROR] $err\n" unless defined $ses;
# main loop
my (%pdata, %cdata); # flag, previous and current octets data
my $first = 1;
while ( 1 ){
%cdata = ();
(my $ret, $err) = snmpwalk(
snmp => $ses,
oids => {
sysUpTime => '1.3.6.1.2.1.1.3',
ifTable => [
'1.3.6.1.2.1.31.1.1.1.1', # [0] ifName
'1.3.6.1.2.1.2.2.1.7', # [1] ifAdminStatus
'1.3.6.1.2.1.2.2.1.8', # [2] ifOperStatus
'1.3.6.1.2.1.31.1.1.1.6', # [3] ifHCInOctets
'1.3.6.1.2.1.31.1.1.1.10', # [4] ifHCOutOctets
'1.3.6.1.2.1.31.1.1.1.15', # [5] ifHighSpeed
] },
-mycallback => sub {
my ($s, $host, $key, $val) = @_;
return 1 if $key ne 'ifTable';
my $name = $val->[0][1];
return 0 if ( $regexp && $name !~ /$regexp/ );
# storing current octets data
$cdata{$name}{t} = time;
$cdata{$name}{i} = $val->[3][1];
$cdata{$name}{o} = $val->[4][1];
return 1;
}
);
die "[ERROR] $err\n" unless $ret;
# header
$console->Cls();
$console->Cursor(0, 0);
printf "%s, up %s - %s\n\n",
BOLD.$host.CLEAR, $ret->{sysUpTime}{0}, scalar(localtime(time));
# matrix
printf "%s%-30s (%-10s) %2s %2s %10s %10s %10s%s\n",
UNDERSCORE, qw/ifName ifIndex Ad Op BW(Mbps) InBps(M) OutBps(M)/, CLEAR;
my $iftable = $ret->{ifTable};
foreach my $i ( sort { $a <=> $b } keys %{$iftable->[1]} )
{
my ($name, $astat, $ostat, $bw)
= map { $iftable->[$_]{$i} } qw( 0 1 2 5 );
if ( $first ){
printf "%-30s (%-10d) %2d %2d %10.1f %10s %10s\n",
$name, $i, $astat, $ostat, $bw/1000, '-', '-';
next; # skip first
}
# calculate (k)bps
my $td = $cdata{$name}{t} - $pdata{$name}{t};
my ($inbps, $outbps) = map {
my $delta = $cdata{$name}{$_} - $pdata{$name}{$_};
$delta<0? 0: $delta / $td / 1000; # Kbps
} qw( i o );
printf "%-30s (%-10d) %2d %2d %10.1f %10.1f %10.1f\n",
$name, $i, $astat, $ostat, map { $_/1000 } ($bw, $inbps, $outbps);
}
%pdata = %cdata;
$first = 0;
sleep $wait;
}
__END__
3. Tiny MRTG with RRDTool (SNMPv2c)
With installing Tobias Oetiker's RRDTool and RRD::Simple, this sample will do like MRTG. (It is better to execute this by cron.)
If Environmental variables, PATH2DATADIR and URL2HTMLDIR, are defined, files will be stored under PATH2DATADIR and URL pathes will include URL2HTMLDIR in html. Or Modify $datadir and $htmldir to decide these path and URL where browser can access through your http service.
Notice: This program is for devices which can deal SNMP version 2c.
#!/usr/local/bin/perl
use strict;
use warnings;
use Getopt::Std;
use CGI qw(:html);
use RRD::Simple; # install the "RRDTool" and RRD::Simple
use Net::SNMP::Util qw(:para);
my %opt;
getopts('hc:x:', \%opt);
my @hosts = @ARGV;
sub HELP_MESSAGE {
print "Usage: $0 [-c COMMUNITY_NAME] [-x REGEXP] HOST [HOST [...]]\n";
exit 1;
}
HELP_MESSAGE() if ( !@hosts || $opt{h} );
my $datadir = $ENV{PATH2DATADIR} || "/path/to/datadir"; # !!! Modify !!!
my $htmldir = $ENV{URL2HTMLDIR} || "/path/to/htmldir"; # !!! Modify !!!
my $regexp = $opt{x}? qr/$opt{x}/: '';
my %sesopts = ( -version => 2, -community=> ($opt{c} || 'public') );
sub escname {
my $n = shift;
$n =~ tr/\\\/\*\?\|"<>:,;%/_/;
return $n;
}
# gather traffic data and store to RRD
my ($result, $error) = snmpparawalk(
hosts => \@hosts,
snmp => \%sesopts,
oids => {
ifData => [ '1.3.6.1.2.1.31.1.1.1.1', # ifName
'1.3.6.1.2.1.31.1.1.1.6', # ifHCInOctets
'1.3.6.1.2.1.31.1.1.1.10' ] # ifHCOutOctets
},
# this callback will work everything of necessary
-mycallback => sub {
my ($s, $host, $key, $val) = @_;
# val=[[index,name], [index,inOcts], [index,outOcts]]
my ($index, $name) = @{$val->[0]};
# check necessarity by ifName
return 0 if ( $regexp && $name !~ /$regexp/ );
my $basename = "$host.".escname($name);
my $rrdfile = "$datadir/$basename.rrd";
# treat RRD
my $rrd = RRD::Simple->new( file => $rrdfile );
#eval { # wanna catch an error, uncomment here.
$rrd->create($rrdfile, 'mrtg',
'in' => 'COUNTER', 'out' => 'COUNTER'
) unless -e $rrdfile;
$rrd->update( $rrdfile, time,
'in' => $val->[1][1], 'out' => $val->[2][1]
);
$rrd->graph( $rrdfile,
destination => $datadir,
basename => $basename,
title => "$host :: $name",
sources => [ qw( in out ) ],
source_labels => [ qw( incoming outgoing ) ],
source_colors => [ qw( 00cc00 0000ff ) ],
source_drawtypes => [ qw( AREA LINE1 ) ]
);
#}; warn "[EVAL ERROR] $@" if $@;
return 1;
}
);
die "[ERROR] $error\n" unless $result;
# make html
sub mkimgtag {
my ($host, $name, $type) = @_;
my $basename = escname($name);
img({ -src => "$htmldir/$host.$basename-$type.png",
-alt => "$host $name $type",
-title => "$type graph of $host $name",
-border=> 0 });
}
open(HTML,"> $datadir/index.html") or die "$!";
print HTML start_html(
-title=> 'Traffic Monitor',
-head => meta({ -http_equiv => 'refresh',
-content => 300 })
), h1('Traffic Monitor');
foreach my $host ( sort @hosts ){
print HTML h2($host);
foreach my $i ( sort keys %{$result->{$host}{ifData}[0]} ){
my $name = $result->{$host}{ifData}[0]{$i};
my $subhtml = "$host.".escname($name).".html";
printf HTML a( {-href=>"$htmldir/$subhtml"},
mkimgtag($host, $name, 'daily')
);
if ( open(HTML2,"> $datadir/$subhtml") ){
print HTML2 start_html(
-title=> 'Traffic Monitor',
-head => meta({ -http_equiv => 'refresh',
-content => 300 }) ),
h1("$host $name"),
(map { h2($_).p(mkimgtag($host, $name, $_)) }
qw(daily weekly monthly annual)),
end_html();
close(HTML2);
} else {
warn "$!";
}
}
}
print HTML end_html();
close(HTML);
__END__
REQUIREMENTS
See Net::SNMP
.
AUTHOR
t.onodera, <cpan :: garakuta.net>
TO DO
- Implementation of simple trapping functions
SEE ALSO
Net::SNMP - Core module of Net::SNMP::Util
which brings us good SNMP implementations. Net::SNMP::Util::OID - Sub module of Net::SNMP::Util
which provides easy and simple functions to treat OID. Net::SNMP::Util::TC - Sub module of Net::SNMP::Util
which provides easy and simple functions to treat textual conversion.
LICENSE AND COPYRIGHT
Copyright(C) 2011- Takahiro Ondoera.
This program is free software; you may redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.