Lots of Changes.

- Added auto-specify code in new() and specify()
    - Added BigInt / 64 Bit Counter code
    - Added SNMP::Info::Layer2::Aironet
    - GLOBALs (scalar SNMP data) are now cached
    - Added Interface Statistics methods (i_pkts_*, i_octet_*)
This commit is contained in:
Max Baker
2003-04-17 21:20:26 +00:00
parent 3c3c040471
commit c2bbd03c2f

338
Info.pm
View File

@@ -13,13 +13,12 @@ use strict;
use Exporter;
use SNMP;
use Carp;
use Math::BigInt;
@SNMP::Info::ISA = qw/Exporter/;
@SNMP::Info::EXPORT_OK = qw//;
use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE $AUTOLOAD $INIT $DEBUG %SPEED_MAP/;
$DEBUG=0;
use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE $AUTOLOAD $INIT $DEBUG %SPEED_MAP $BIGINT/;
=head1 NAME
@@ -65,27 +64,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=head1 SYNOPSIS
# Connect with generic Info object
use SNMP::Info
my $info = new SNMP::Info( DestHost => 'router' ,
Community => 'public' );
my $info = new SNMP::Info(
# Auto Discover more specific Device Class
AutoSpecify => 1,
Debug => 1,
# The rest is passed to SNMP::Session
DestHost => 'router',
Community => 'public',
Version => 2 )
or die;
$name = $info->name();
# Try and find a more specific subclass of SNMP::Info
my $object_class = $info->device_type();
my $more_specific_device = new $object_class(
'Desthost' => 'mydevice',
'Community' => 'public');
# Let's see what sub-class it picked for us
print "Device is of type : ", $info->class(), "\n";
# Find out the Duplex status for the ports
my $interfaces = $more_specific_device->interfaces();
my $i_duplex = $more_specific_device->i_duplex();
my $interfaces = $info->interfaces();
my $i_duplex = $info->i_duplex();
# Get CDP Neighbor info
my $c_ip = $more_specific_device->c_ip();
my $c_port = $more_specific_device->c_port();
my $c_ip = $info->c_ip();
my $c_port = $info->c_port();
foreach my $iid (keys %$interfaces){
@@ -349,11 +351,30 @@ probably available for any network device that speaks SNMP.
Creates a new object and connects via SNMP::Session.
Arguments given are passed to SNMP::Session and can be used to overide defaults.
my $info = new SNMP::Info( 'Debug' => 1,
'AutoSpecify' => 1,
'BigInt' => 1
'DestHost' => 'myrouter',
'Community' => 'public',
'Version' => 2
) or die;
Arguments :
AutoSpecify = Returns an object of a more specific device class
*See specify() entry*
Debug = Prints Lots of debugging messages
Session = SNMP::Session object to use instead of connecting on own.
BigInt = Return Math::BigInt objects for 64 bit counters.
All other arguments are passed to SNMP::Session.
See SNMP::Session for a list of other possible arguments.
=cut
sub new {
my $class = shift;
my $proto = shift;
my $class = ref($proto) || $proto;
my %args = @_;
my $new_obj = {};
bless $new_obj,$class;
@@ -380,18 +401,36 @@ sub new {
$$init_ref=1;
}
# These session defaults can be overwritten with @_
my $sess = new SNMP::Session(
#'Version' => 2,
'UseEnums' => 1,
%args
);
# SNMP::Info specific args :
my $auto_specific = 0;
if (defined $args{AutoSpecify}){
$auto_specific = $args{AutoSpecify} || 0;
delete $args{AutoSpecify};
}
if (defined $args{Debug}){
$DEBUG = $args{Debug};
delete $args{Debug};
}
my $sess = undef;
if (defined $args{Session}){
$sess = $args{Session};
delete $args{Session};
}
if (defined $args{BigInt}){
$BIGINT = $args{BigInt};
delete $args{BigInt};
}
# Save Args for later
$new_obj->{_args} = \%args;
# Connects to device unless open session is provided.
$sess = new SNMP::Session( 'UseEnums' => 1,
%args
) unless defined $sess;
unless (defined $sess){
# How do i get error messages back from SNMP?
#print $SNMP::ErrorStr;
print "SNMP::Info::new() $sess->{ErrorStr}\n"
if ($DEBUG and $sess->{ErrorStr});
$DEBUG and carp("SNMP::Info::new() Failed to Create Session. ", defined $sess->{ErrorStr} ? $sess->{ErrorStr} : '', "\n");
return undef;
}
@@ -400,7 +439,8 @@ sub new {
my $store = {};
$new_obj->{store} = $store;
return $new_obj;
return $auto_specific ?
$new_obj->specify() : $new_obj;
}
=back
@@ -442,6 +482,7 @@ Algorithm for SubClass Detection:
Catalyst 3550 -> SNMP::Info::Layer3::C3550
Foundry -> SNMP::Info::Layer3::Foundry
Elsif Layer2 (no Layer3) -> SNMP::Info::Layer2
Aironet (Cisco) AP1100 -> SNMP::Info::Layer2::Aironet
Bay Networks -> SNMP::Info::Layer2::Bay
Catalyst 1900 -> SNMP::Info::Layer2::C1900
Catalyst 2900XL (IOS) -> SNMP::Info::Layer2::C2900
@@ -499,6 +540,9 @@ sub device_type {
# Bay Switch
$objtype = 'SNMP::Info::Layer2::Bay' if ($desc =~ /bay/i);
# Aironet
$objtype = 'SNMP::Info::Layer2::Aironet' if ($desc =~ /C1100/);
} elsif ($info->has_layer(1)) {
$objtype = 'SNMP::Info::Layer1';
@@ -510,6 +554,47 @@ sub device_type {
return $objtype;
}
=item $info->specify()
Returns an object of a more-specific subclass.
my $info = new SNMP::Info(...);
# Returns more specific object type
$info = $info->specific();
See device_type() entry for how a sub class is chosen.
=cut
sub specify {
my $self = shift;
my $device_type = $self->device_type();
unless (defined $device_type) {
carp("SNMP::Info::specify() - Could not get info from device.\n");
return $self;
}
return $self if $device_type eq 'SNMP::Info';
# Load Sub Class
# By evaling a string the contents of device_type now becomes a bareword.
eval "require $device_type;";
if ($@) {
print "SNMP::Info::specify() Loading $device_type Failed. $@\n";
}
my $args = $self->args();
my $session = $self->session();
my $sub_obj = $device_type->new(%$args,'Session'=>$session);
unless (defined $sub_obj) {
carp("SNMP::Info::specify() - Could not connect with new class ($device_type).\n");
return $self;
}
$DEBUG and print "SNMP::Info::specify() - Changed Class to $device_type.\n";
return $sub_obj;
}
=item $info->has_layer(3)
Returns non-zero if the device has the supplied layer in the OSI Model
@@ -573,7 +658,7 @@ Each of these methods returns a hash_reference to a hash keyed on the interface
Example : $cdp->c_ip() returns
{ '304' => '123.123.231.12' }
=head3 Interfaces
=head3 Interface Information
=over
@@ -672,6 +757,74 @@ set field like i_name().
=back
=head3 Interface Statistics
=over
=item $info->i_octet_in(), $info->i_octets_out(),
$info->i_octet_in64(), $info->i_octets_out64()
Bandwidth.
Number of octets sent/received on the interface including framing characters.
64 bit version may not exist on all devices.
NOTE: To manipulate 64 bit counters you need to use Math::BigInt, since the values
are too large for a normal Perl scalar. Set the global $SNMP::Info::BIGINT to 1 , or
pass the BigInt value to new() if you want SNMP::Info to do it for you.
(B<ifInOctets>) (B<ifOutOctets>)
(B<ifHCInOctets>) (B<ifHCOutOctets>)
=item $info->i_errors_in(), $info->i_errors_out()
Number of packets that contained an error prventing delivery. See IF-MIB for more info.
(B<ifInErrors>) (B<ifOutErrors>)
=item $info->i_pkts_ucast_in(), $info->i_pkts_ucast_out(),
$info->i_pkts_ucast_in64(), $info->i_pkts_ucast_out64()
Number of packets not sent to a multicast or broadcast address.
64 bit version may not exist on all devices.
(B<ifInUcastPkts>) (B<ifOutUcastPkts>)
(B<ifHCInUcastPkts>) (B<ifHCOutUcastPkts>)
=item $info->i_pkts_nucast_in(), $info->i_pkts_nucast_out(),
Number of packets sent to a multicast or broadcast address.
These methods are depricated by i_pkts_multi_in() and i_pkts_bcast_in()
according to IF-MIB. Actual device usage may vary.
(B<ifInNUcastPkts>) (B<ifOutNUcastPkts>)
=item $info->i_pkts_multi_in() $info->i_pkts_multi_out(),
$info->i_pkts_multi_in64(), $info->i_pkts_multi_out64()
Number of packets sent to a multicast address.
64 bit version may not exist on all devices.
(B<ifInMulticastPkts>) (B<ifOutMulticastPkts>)
(B<ifHCInMulticastPkts>) (B<ifHCOutMulticastPkts>)
=item $info->i_pkts_bcast_in() $info->i_pkts_bcast_out(),
$info->i_pkts_bcast_in64() $info->i_pkts_bcast_out64()
Number of packets sent to a broadcast address on an interface.
64 bit version may not exist on all devices.
(B<ifInBroadcastPkts>) (B<ifOutBroadcastPkts>)
(B<ifHCInBroadcastPkts>) (B<ifHCOutBroadcastPkts>)
=back
=head3 IP Address Table
Each entry in this table is an IP address in use on this device. Usually
@@ -763,23 +916,44 @@ These are table entries, such as the IfIndex
=cut
%FUNCS = (
'interfaces' => 'ifIndex',
'interfaces' => 'ifIndex',
# from SNMPv2-MIB
'i_index' => 'ifIndex',
'i_description' => 'ifDescr',
'i_type' => 'ifType',
'i_mtu' => 'ifMtu',
'i_speed' => 'ifSpeed',
'i_mac' => 'ifPhysAddress',
'i_up' => 'ifOperStatus',
'i_up_admin' => 'ifAdminStatus',
'i_name' => 'ifName',
'i_alias' => 'ifAlias',
'i_index' => 'ifIndex',
'i_description' => 'ifDescr',
'i_type' => 'ifType',
'i_mtu' => 'ifMtu',
'i_speed' => 'ifSpeed',
'i_mac' => 'ifPhysAddress',
'i_up' => 'ifOperStatus',
'i_up_admin' => 'ifAdminStatus',
'i_name' => 'ifName',
'i_octet_in' => 'ifInOctets',
'i_octet_out' => 'ifOutOctets',
'i_errors_in' => 'ifInErrors',
'i_errors_out' => 'ifOutErrors',
'i_pkts_ucast_in' => 'ifInUcastPkts',
'i_pkts_ucast_out' => 'ifOutUcastPkts',
'i_pkts_nucast_in' => 'ifInNUcastPkts',
'i_pkts_nucast_out' => 'ifOutNUcastPkts',
# IP Address Table
'ip_index' => 'ipAdEntIfIndex',
'ip_table' => 'ipAdEntAddr',
'ip_netmask' => 'ipAdEntNetMask',
'ip_broadcast' => 'ipAdEntBcastAddr',
'ip_index' => 'ipAdEntIfIndex',
'ip_table' => 'ipAdEntAddr',
'ip_netmask' => 'ipAdEntNetMask',
'ip_broadcast' => 'ipAdEntBcastAddr',
# ifXTable - Extension Table
'i_pkts_multi_in' => 'ifInMulticastPkts',
'i_pkts_multi_out' => 'ifOutMulticastPkts',
'i_pkts_bcast_in' => 'ifInBroadcastPkts',
'i_pkts_bcast_out' => 'ifOutBroadcastPkts',
'i_octet_in64' => 'ifHCInOctets',
'i_octet_out64' => 'ifHCOutOctets',
'i_pkts_ucast_in64' => 'ifHCInUcastPkts',
'i_pkts_ucast_out64' => 'ifHCOutUcastPkts',
'i_pkts_multi_in64' => 'ifHCInMulticastPkts',
'i_pkts_multi_out64' => 'ifHCOutMulticastPkts',
'i_pkts_bcast_in64' => 'ifHCInBroadcastPkts',
'i_pkts_bcast_out64' => 'ifHCOutBroadcastPkts',
'i_alias' => 'ifAlias'
);
=item %MIBS
@@ -804,11 +978,19 @@ it should return that same data in a more human friendly format.
=cut
%MUNGE = ('ip' => \&munge_ip,
'mac' => \&munge_mac,
'i_mac' => \&munge_mac,
'layers' => \&munge_dec2bin,
'i_speed'=> \&munge_speed
%MUNGE = ('ip' => \&munge_ip,
'mac' => \&munge_mac,
'i_mac' => \&munge_mac,
'layers' => \&munge_dec2bin,
'i_speed' => \&munge_speed,
'i_octet_in64' => \&munge_counter64,
'i_octet_out64' => \&munge_counter64,
'i_pkts_ucast_in64' => \&munge_counter64,
'i_pkts_ucast_out64' => \&munge_counter64,
'i_pkts_mutli_in64' => \&munge_counter64,
'i_pkts_multi_out64' => \&munge_counter64,
'i_pkts_bcast_in64' => \&munge_counter64,
'i_pkts_bcast_out64' => \&munge_counter64,
);
=back
@@ -883,6 +1065,31 @@ Let's make a sample Layer 2 Device subclass :
Be sure and send the debugged version to snmp@warped.org to be
included in the next version of SNMP::Info.
=head2 Package Globals
These are variables that get set by methods, or arguments passed to new()
Avoid modifying them directly
=over
=item $DEBUG
Default 0. Sends copious debug info to stdout. Set with Debug argument in new() or with the
debug() method on an object.
=cut
$DEBUG = 0;
=item $BIGINT
Default 0. Set to true to have 64 bit counters return Math::BigInt objects instead of scalar
string values. See note under Interface Statistics about 64 bit values.
=cut
$BIGINT = 0;
=back
=head2 Data Munging Callback Subs
=over
@@ -1003,6 +1210,21 @@ sub munge_bits {
return unpack("b*",$bits);
}
=item munge_counter64
If $BIGINT is set to true, then a Math::BigInt object is returned.
See Math::BigInt for details.
=cut
sub munge_counter64 {
my $counter = shift;
return unless defined $counter;
return $counter unless $BIGINT;
my $bigint = Math::BigInt->new($counter);
return $bigint;
}
=back
=head2 Internaly Used Functions
@@ -1062,6 +1284,16 @@ sub debug {
}
=item $info->args()
Returns a reference to the argument hash supplied to SNMP::Session
=cut
sub args {
my $self = shift;
return $self->{_args};
}
=item $info->class()
Returns the class name of the object.
@@ -1178,6 +1410,9 @@ sub _global{
$val = &$subref($val);
}
# Save Cached Value
$self->{"__$attr"} = $val;
return $val;
}
@@ -1422,6 +1657,9 @@ sub AUTOLOAD {
# First check %GLOBALS and return _scalar(global)
if (defined $globals{$attr} ){
# Return Cached Value if exists
return $self->{"__${attr}"} if defined $self->{"__${attr}"};
# Fetch New Value
return $self->_global( $attr );
}