5053 lines
		
	
	
		
			138 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			5053 lines
		
	
	
		
			138 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| # SNMP::Info
 | ||
| #
 | ||
| # Copyright (c) 2003-2012 Max Baker and SNMP::Info Developers
 | ||
| # All rights reserved.
 | ||
| #
 | ||
| # Portions Copyright (c) 2002-2003, Regents of the University of California
 | ||
| # All rights reserved.
 | ||
| #
 | ||
| # See COPYRIGHT at bottom
 | ||
| 
 | ||
| package SNMP::Info;
 | ||
| 
 | ||
| use warnings;
 | ||
| use strict;
 | ||
| use Exporter;
 | ||
| use SNMP;
 | ||
| use Carp;
 | ||
| use Math::BigInt;
 | ||
| use NetAddr::IP::Lite ':lower';
 | ||
| 
 | ||
| @SNMP::Info::ISA       = qw/Exporter/;
 | ||
| @SNMP::Info::EXPORT_OK = qw//;
 | ||
| 
 | ||
| use vars
 | ||
|     qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE $AUTOLOAD $INIT $DEBUG %SPEED_MAP
 | ||
|     $NOSUCH $BIGINT $REPEATERS/;
 | ||
| 
 | ||
| $VERSION = '3.64';
 | ||
| 
 | ||
| =head1 NAME
 | ||
| 
 | ||
| SNMP::Info - OO Interface to Network devices and MIBs through SNMP
 | ||
| 
 | ||
| =head1 VERSION
 | ||
| 
 | ||
| SNMP::Info - Version 3.64
 | ||
| 
 | ||
| =head1 AUTHOR
 | ||
| 
 | ||
| SNMP::Info is maintained by team of Open Source authors headed by Eric Miller,
 | ||
| Bill Fenner, Max Baker, Jeroen van Ingen and Oliver Gorwits.
 | ||
| 
 | ||
| Please visit L<https://github.com/netdisco/snmp-info/> for the most up-to-date
 | ||
| list of developers.
 | ||
| 
 | ||
| SNMP::Info was originally created at UCSC for the Netdisco project L<http://netdisco.org>
 | ||
| by Max Baker.
 | ||
| 
 | ||
| =head1 DEVICES SUPPORTED
 | ||
| 
 | ||
| There are now generic classes for most types of device and so the authors
 | ||
| recommend loading SNMP::Info with AutoSpecify, and then reporting to the mail
 | ||
| list any missing functionality (such as neighbor discovery tables).
 | ||
| 
 | ||
| =head1 SYNOPSIS
 | ||
| 
 | ||
|  use SNMP::Info;
 | ||
| 
 | ||
|  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 "Can't connect to device.\n";
 | ||
| 
 | ||
|  my $err = $info->error();
 | ||
|  die "SNMP Community or Version probably wrong connecting to device. $err\n" if defined $err;
 | ||
| 
 | ||
|  $name  = $info->name();
 | ||
|  $class = $info->class();
 | ||
|  print "SNMP::Info is using this device class : $class\n";
 | ||
| 
 | ||
|  # Find out the Duplex status for the ports
 | ||
|  my $interfaces = $info->interfaces();
 | ||
|  my $i_duplex   = $info->i_duplex();
 | ||
| 
 | ||
|  # Get CDP Neighbor info
 | ||
|  my $c_if       = $info->c_if();
 | ||
|  my $c_ip       = $info->c_ip();
 | ||
|  my $c_port     = $info->c_port();
 | ||
| 
 | ||
|  # Print out data per port
 | ||
|  foreach my $iid (keys %$interfaces){
 | ||
|     my $duplex = $i_duplex->{$iid};
 | ||
|     # Print out physical port name, not snmp iid
 | ||
|     my $port  = $interfaces->{$iid};
 | ||
| 
 | ||
|     print "$port: ";
 | ||
|     print "$duplex duplex" if defined $duplex;
 | ||
| 
 | ||
|     # The CDP Table has table entries different than the interface tables.
 | ||
|     # So we use c_if to get the map from cdp table to interface table.
 | ||
| 
 | ||
|     my %c_map = reverse %$c_if;
 | ||
|     my $c_key = $c_map{$iid};
 | ||
|     unless (defined $c_key) {
 | ||
|          print "\n\n";
 | ||
|          next;
 | ||
|      }
 | ||
|     my $neighbor_ip   = $c_ip->{$c_key};
 | ||
|     my $neighbor_port = $c_port->{$c_key};
 | ||
| 
 | ||
|     print " connected to $neighbor_ip / $neighbor_port\n" if defined $neighbor_ip;
 | ||
|     print "\n";
 | ||
| 
 | ||
|  }
 | ||
| 
 | ||
| =head1 SUPPORT
 | ||
| 
 | ||
| Please direct all support, help, and bug requests to the snmp-info-users
 | ||
| Mailing List at L<http://lists.sourceforge.net/lists/listinfo/snmp-info-users>.
 | ||
| 
 | ||
| =head1 DESCRIPTION
 | ||
| 
 | ||
| SNMP::Info gives an object oriented interface to information obtained through
 | ||
| SNMP.
 | ||
| 
 | ||
| This module is geared towards network devices.  Subclasses exist for a number
 | ||
| of network devices and common MIBs.
 | ||
| 
 | ||
| The idea behind this module is to give a common interface to data from network
 | ||
| devices, leaving the device-specific hacks behind the scenes in subclasses.
 | ||
| 
 | ||
| In the SYNOPSIS example we fetch the name of all the ports on the device and
 | ||
| the duplex setting for that port with two methods -- interfaces() and
 | ||
| i_duplex().
 | ||
| 
 | ||
| The information may be coming from any number of MIB files and is very vendor
 | ||
| specific.  SNMP::Info provides you a common method for all supported devices.
 | ||
| 
 | ||
| Adding support for your own device is easy, and takes little SNMP knowledge.
 | ||
| 
 | ||
| The module is not limited to network devices. Any MIB or device can be given
 | ||
| an objected oriented front-end by making a module that consists of a couple
 | ||
| hashes.  See EXTENDING SNMP::INFO.
 | ||
| 
 | ||
| =head1 REQUIREMENTS
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item 1. Net-SNMP
 | ||
| 
 | ||
| To use this module, you must have Net-SNMP installed on your system.
 | ||
| More specifically you need the Perl modules that come with it.
 | ||
| 
 | ||
| DO NOT INSTALL SNMP:: or Net::SNMP from CPAN!
 | ||
| 
 | ||
| The SNMP module is matched to an install of net-snmp, and must be installed
 | ||
| from the net-snmp source tree.
 | ||
| 
 | ||
| The Perl module C<SNMP> is found inside the net-snmp distribution.  Go to the
 | ||
| F<perl/> directory of the distribution to install it, or run
 | ||
| C<./configure --with-perl-modules> from the top directory of the net-snmp
 | ||
| distribution.
 | ||
| 
 | ||
| Net-SNMP can be found at http://net-snmp.sourceforge.net
 | ||
| 
 | ||
| Version 5.3.2 or greater is recommended.
 | ||
| 
 | ||
| Versions 5.0.1, 5.0301 and 5.0203 have issues with bulkwalk and are not supported.
 | ||
| 
 | ||
| B<Redhat Users>: Some versions that come with certain versions of
 | ||
| Redhat/Fedora don't have the Perl library installed.  Uninstall the RPM and
 | ||
| install by hand.
 | ||
| 
 | ||
| =item 2. MIBS
 | ||
| 
 | ||
| SNMP::Info operates on textual descriptors found in MIBs.
 | ||
| 
 | ||
| If you are using SNMP::Info separate from Netdisco,
 | ||
| download the Netdisco MIB package at L<https://github.com/netdisco/netdisco-mibs/releases/latest/>
 | ||
| 
 | ||
| Make sure that your snmp.conf is updated to point to your MIB directory
 | ||
| and that the MIBs are world-readable.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head1 DESIGN GOALS
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item 1. Use of textual MIB leaf identifier and enumerated values
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item * All values are retrieved via MIB Leaf node names
 | ||
| 
 | ||
| For example SNMP::Info has an entry in its %GLOBALS hash for ``sysName''
 | ||
| instead of 1.3.6.1.2.1.1.5.
 | ||
| 
 | ||
| =item * Data returned is in the enumerated value form.
 | ||
| 
 | ||
| For Example instead of looking up 1.3.6.1.2.1.2.2.1.3 and getting back C<23>
 | ||
| 
 | ||
| SNMP::Info will ask for C<RFC1213-MIB::ifType> and will get back C<ppp>.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =item 2. SNMP::Info is easily extended to new devices
 | ||
| 
 | ||
| You can create a new subclass for a device by providing four hashes :
 | ||
| %GLOBALS, %MIBS, %FUNCS, and %MUNGE.
 | ||
| 
 | ||
| Or you can override any existing methods from a parent class by making a short
 | ||
| subroutine.
 | ||
| 
 | ||
| See the section EXTENDING SNMP::INFO for more details.
 | ||
| 
 | ||
| When you make a new subclass for a device, please be sure to send it back
 | ||
| to the developers (via a github pull request or the mailing list) for inclusion
 | ||
| in the next version.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head1 SUBCLASSES
 | ||
| 
 | ||
| These are the subclasses that implement MIBs and support devices:
 | ||
| 
 | ||
| Required MIBs not included in the install instructions above are noted here.
 | ||
| 
 | ||
| =head2 MIB Subclasses
 | ||
| 
 | ||
| These subclasses implement method to access one or more MIBs.  These are not
 | ||
| used directly, but rather inherited from device subclasses.
 | ||
| 
 | ||
| For more info run C<perldoc> on any of the following module names.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item SNMP::Info::AdslLine
 | ||
| 
 | ||
| SNMP Interface to the ADSL-LINE-MIB for ADSL interfaces.
 | ||
| 
 | ||
| Requires the F<ADSL-LINE-MIB>, down loadable from Cisco.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::AdslLine> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Aggregate
 | ||
| 
 | ||
| SNMP Interface to F<IF-MIB> C<ifStackTable> Aggregated Links
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Aggregate> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Airespace
 | ||
| 
 | ||
| F<AIRESPACE-WIRELESS-MIB> and F<AIRESPACE-SWITCHING-MIB>.  Inherited by
 | ||
| devices based on the Airespace wireless platform.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Airespace> for details.
 | ||
| 
 | ||
| =item SNMP::Info::AMAP
 | ||
| 
 | ||
| F<ALCATEL-IND1-INTERSWITCH-PROTOCOL-MIB>.  Alcatel Mapping Adjacency
 | ||
| Protocol (AMAP) Support.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::AMAP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Bridge
 | ||
| 
 | ||
| F<BRIDGE-MIB> (RFC1286).  F<QBRIDGE-MIB>. Inherited by devices with Layer2
 | ||
| support.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Bridge> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoAgg
 | ||
| 
 | ||
| SNMP Interface to Cisco Aggregated Links
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoAgg> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CDP
 | ||
| 
 | ||
| F<CISCO-CDP-MIB>.  Cisco Discovery Protocol (CDP) Support.  Inherited by
 | ||
| Cisco, Enterasys, and HP devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CDP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoConfig
 | ||
| 
 | ||
| F<CISCO-CONFIG-COPY-MIB>, F<CISCO-FLASH-MIB>, and F<OLD-CISCO-SYS-MIB>.
 | ||
| These OIDs facilitate the writing of configuration files.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoConfig> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoPortSecurity
 | ||
| 
 | ||
| F<CISCO-PORT-SECURITY-MIB> and F<CISCO-PAE-MIB>.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoPortSecurity> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoPower
 | ||
| 
 | ||
| F<CISCO-POWER-ETHERNET-EXT-MIB>.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoPower> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoQOS
 | ||
| 
 | ||
| F<CISCO-CLASS-BASED-QOS-MIB>. A collection of OIDs providing information about
 | ||
| a Cisco device's QOS config.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoQOS> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoRTT
 | ||
| 
 | ||
| F<CISCO-RTTMON-MIB>. A collection of OIDs providing information about a Cisco
 | ||
| device's RTT values.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoRTT> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoStack
 | ||
| 
 | ||
| F<CISCO-STACK-MIB>.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoStack> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoStpExtensions
 | ||
| 
 | ||
| F<CISCO-STP-EXTENSIONS-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoStpExtensions> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoStats
 | ||
| 
 | ||
| F<OLD-CISCO-CPU-MIB>, F<CISCO-PROCESS-MIB>, and F<CISCO-MEMORY-POOL-MIB>.
 | ||
| Provides common interfaces for memory, cpu, and os statistics for Cisco
 | ||
| devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoStats> for details.
 | ||
| 
 | ||
| =item SNMP::Info::CiscoVTP
 | ||
| 
 | ||
| F<CISCO-VTP-MIB>, F<CISCO-VLAN-MEMBERSHIP-MIB>,
 | ||
| F<CISCO-VLAN-IFTABLE-RELATIONSHIP-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::CiscoVTP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::EDP
 | ||
| 
 | ||
| Extreme Discovery Protocol.  F<EXTREME-EDP-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::EDP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Entity
 | ||
| 
 | ||
| F<ENTITY-MIB>.  Used for device info in Cisco and other vendors.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Entity> for details.
 | ||
| 
 | ||
| =item SNMP::Info::EtherLike
 | ||
| 
 | ||
| F<EtherLike-MIB> (RFC1398) - Some Layer3 devices implement this MIB, as well
 | ||
| as some Aironet Layer 2 devices (non Cisco).
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::EtherLike> for details.
 | ||
| 
 | ||
| =item SNMP::Info::FDP
 | ||
| 
 | ||
| Foundry (Brocade) Discovery Protocol.  F<FOUNDRY-SN-SWITCH-GROUP-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::FDP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::IPv6
 | ||
| 
 | ||
| SNMP Interface for obtaining configured IPv6 addresses and mapping IPv6
 | ||
| addresses to MAC addresses and interfaces, using information from F<IP-MIB>,
 | ||
| F<IPV6-MIB> and/or F<CISCO-IETF-IP-MIB>.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::IPv6> for details.
 | ||
| 
 | ||
| =item SNMP::Info::IEEE802dot11
 | ||
| 
 | ||
| F<IEEE802dot11-MIB>.  A collection of OIDs providing information about
 | ||
| standards based 802.11 wireless devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::IEEE802dot11> for details.
 | ||
| 
 | ||
| =item SNMP::Info::IEEE802dot3ad
 | ||
| 
 | ||
| SNMP Interface to IEEE Aggregated Links.  F<IEEE8023-LAG-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::IEEE802dot3ad> for details.
 | ||
| 
 | ||
| =item SNMP::Info::LLDP
 | ||
| 
 | ||
| F<LLDP-MIB>, F<LLDP-EXT-DOT1-MIB>, and F<LLDP-EXT-DOT3-MIB>.  Link Layer
 | ||
| Discovery Protocol (LLDP) Support.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::LLDP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::MAU
 | ||
| 
 | ||
| F<MAU-MIB> (RFC2668).  Some Layer2 devices use this for extended Ethernet
 | ||
| (Media Access Unit) interface information.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::MAU> for details.
 | ||
| 
 | ||
| =item SNMP::Info::MRO
 | ||
| 
 | ||
| Method resolution introspection for SNMP::Info
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::MRO> for details.
 | ||
| 
 | ||
| =item SNMP::Info::NortelStack
 | ||
| 
 | ||
| F<S5-AGENT-MIB>, F<S5-CHASSIS-MIB>.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::NortelStack> for details.
 | ||
| 
 | ||
| =item SNMP::Info::PowerEthernet
 | ||
| 
 | ||
| F<POWER-ETHERNET-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::PowerEthernet> for details.
 | ||
| 
 | ||
| =item SNMP::Info::RapidCity
 | ||
| 
 | ||
| F<RAPID-CITY>.  Inherited by Avaya switches for duplex and VLAN information.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::RapidCity> for details.
 | ||
| 
 | ||
| =item SNMP::Info::SONMP
 | ||
| 
 | ||
| SynOptics Network Management Protocol (SONMP) F<SYNOPTICS-ROOT-MIB>,
 | ||
| F<S5-ETH-MULTISEG-TOPOLOGY-MIB>.  Inherited by
 | ||
| Avaya/Nortel/Bay/Synoptics switches and hubs.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::SONMP> for details.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Device Subclasses
 | ||
| 
 | ||
| These subclasses inherit from one or more classes to provide a common
 | ||
| interface to data obtainable from network devices.
 | ||
| 
 | ||
| All the required MIB files are included in the netdisco-mib package.
 | ||
| (See Above).
 | ||
| 
 | ||
| =over 4
 | ||
| 
 | ||
| =item SNMP::Info::Layer1
 | ||
| 
 | ||
| Generic Layer1 Device subclass.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer1> for details.
 | ||
| 
 | ||
| =over 4
 | ||
| 
 | ||
| =item SNMP::Info::Layer1::Allied
 | ||
| 
 | ||
| Subclass for Allied Telesis Repeaters / Hubs.
 | ||
| 
 | ||
| Requires F<ATI-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer1::Allied> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer1::Asante
 | ||
| 
 | ||
| Subclass for Asante 1012 Hubs.
 | ||
| 
 | ||
| Requires F<ASANTE-HUB1012-MIB>
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer1::Asante> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer1::Bayhub
 | ||
| 
 | ||
| Subclass for Nortel/Bay hubs.  This includes System 5000, 100 series,
 | ||
| 200 series, and probably more.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer1::Bayhub> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer1::Cyclades
 | ||
| 
 | ||
| Subclass for Cyclades/Avocent terminal servers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer1::Cyclades> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer1::S3000
 | ||
| 
 | ||
| Subclass for Bay/Synoptics hubs.  This includes System 3000, 281X, and
 | ||
| probably more.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer1::S3000> for details.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =item SNMP::Info::Layer2
 | ||
| 
 | ||
| Generic Layer2 Device subclass.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2> for details.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::3Com
 | ||
| 
 | ||
| SNMP::Info::Layer2::3Com - SNMP Interface to L2 3Com Switches
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::3Com> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Adtran
 | ||
| 
 | ||
| Subclass for Adtran devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Adtran> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Aerohive
 | ||
| 
 | ||
| Subclass for Aerohive Access Points.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Aerohive> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Airespace
 | ||
| 
 | ||
| Subclass for Cisco (Airespace) wireless controllers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Airespace> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Aironet
 | ||
| 
 | ||
| Class for Cisco Aironet wireless devices that run IOS.  See also
 | ||
| Layer3::Aironet for Aironet devices that don't run IOS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Aironet> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Allied
 | ||
| 
 | ||
| Allied Telesis switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Allied> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Atmedia
 | ||
| 
 | ||
| Subclass for atmedia encryptors.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Atmedia> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Baystack
 | ||
| 
 | ||
| Subclass for Avaya/Nortel/Bay Ethernet Switch/Baystack switches.  This
 | ||
| includes 303, 304, 350, 380, 410, 420, 425, 450, 460, 470 series,
 | ||
| 2500 series, 4000 series, 5000 series, Business Ethernet Switch (BES),
 | ||
| Business Policy Switch (BPS), VSP 7000 series, and probably others.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Baystack> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Kentrox
 | ||
| 
 | ||
| Class for Kentrox DataSMART DSU/CSU. See L<SNMP::Info::Layer2::Kentrox> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::C1900
 | ||
| 
 | ||
| Subclass for Cisco Catalyst 1900 and 1900c Devices running CatOS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::C1900> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::C2900
 | ||
| 
 | ||
| Subclass for Cisco Catalyst 2900, 2950, 3500XL, and 3548 devices running IOS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::C2900> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Catalyst
 | ||
| 
 | ||
| Subclass for Cisco Catalyst switches running CatOS.  These switches usually
 | ||
| report a model number that starts with C<wsc>.   Note that this class
 | ||
| does not support everything that has the name Catalyst.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Catalyst> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Centillion
 | ||
| 
 | ||
| Subclass for Nortel/Bay Centillion and 5000BH ATM switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Centillion> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Cisco
 | ||
| 
 | ||
| Generic Cisco subclass for layer 2 devices that are not yet supported
 | ||
| in more specific subclassesand the base layer 2 Cisco class for
 | ||
| other device specific layer 2 Cisco classes.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Cisco> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::CiscoSB
 | ||
| 
 | ||
| Subclass for Cisco's "Small Business" product line, acquired from
 | ||
| Linksys.  This currently comprises the Sx300/500 line of switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::CiscoSB> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Exinda
 | ||
| 
 | ||
| Subclass for Exinda / GFI Network Orchestrator traffic shapers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Exinda> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::HP
 | ||
| 
 | ||
| Subclass for more recent HP Procurve Switches.
 | ||
| 
 | ||
| Requires F<HP-ICF-OID> and F<ENTITY-MIB> downloaded from HP.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::HP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::HP4000
 | ||
| 
 | ||
| Subclass for older HP Procurve Switches
 | ||
| 
 | ||
| Requires F<HP-ICF-OID> and F<ENTITY-MIB> downloaded from HP.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::HP4000> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::HPVC
 | ||
| 
 | ||
| Subclass for HP Virtual Connect Switches
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::HPVC> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::N2270
 | ||
| 
 | ||
| Subclass for Nortel 2270 wireless switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::N2270> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::NAP222x
 | ||
| 
 | ||
| Subclass for Nortel 222x series wireless access points.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::NAP222x> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Netgear
 | ||
| 
 | ||
| Subclass for Netgear switches
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Netgear> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Nexans
 | ||
| 
 | ||
| Subclass for Nexans switches
 | ||
| 
 | ||
| See documetion in L<SNMP::Info::Layer2::Nexans> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::NWSS2300
 | ||
| 
 | ||
| SNMP Interface to Avaya (Trapeze) Wireless Controllers
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::NWSS2300> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Orinoco
 | ||
| 
 | ||
| Subclass for Orinoco/Proxim wireless access points.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Orinoco> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Trapeze
 | ||
| 
 | ||
| SNMP Interface to Juniper (Trapeze) Wireless Controllers
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Trapeze> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Sixnet
 | ||
| 
 | ||
| SNMP Interface to Sixnet industrial switches
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Sixnet> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::Ubiquiti
 | ||
| 
 | ||
| SNMP Interface to Ubiquiti Access Points and other devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::Ubiquiti> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer2::ZyXEL_DSLAM
 | ||
| 
 | ||
| Zyxel DSLAMs.  Need I say more?
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer2::ZyXEL_DSLAM> for details.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =item SNMP::Info::Layer3
 | ||
| 
 | ||
| Generic Layer3 and Layer2+3 Device subclass.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3> for details.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Aironet
 | ||
| 
 | ||
| Subclass for Cisco Aironet wireless access points (AP) not running IOS. These
 | ||
| are usually older devices.
 | ||
| 
 | ||
| MIBs for these devices now included in v2.tar.gz available from ftp.cisco.com.
 | ||
| 
 | ||
| Note Layer2::Aironet
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Aironet> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::AlcatelLucent
 | ||
| 
 | ||
| Alcatel-Lucent OmniSwitch Class.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::AlcatelLucent> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::AlteonAD
 | ||
| 
 | ||
| Subclass for Radware Alteon Series ADC switches and Nortel BladeCenter
 | ||
| Layer2-3 GbE Switch Modules.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::AlteonAD> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Altiga
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Altiga> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Arista
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Arista> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Aruba
 | ||
| 
 | ||
| Subclass for Aruba wireless switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Aruba> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::BayRS
 | ||
| 
 | ||
| Subclass for Avaya/Nortel/Bay Multiprotocol/BayRS routers.  This includes
 | ||
| BCN, BLN, ASN, ARN, AN, 2430, and 5430 routers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::BayRS> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::BlueCoatSG
 | ||
| 
 | ||
| Subclass for Blue Coat SG series proxy devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::BlueCoatSG> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::C3550
 | ||
| 
 | ||
| Subclass for Cisco Catalyst 3550,3540,3560 2/3 switches running IOS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::C3550> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::C4000
 | ||
| 
 | ||
| This class covers Catalyst 4000s and 4500s.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::C4000> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::C6500
 | ||
| 
 | ||
| This class covers Catalyst 6500s in native mode, hybrid mode.  Catalyst
 | ||
| 3750's, 2970's and probably others.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::C6500> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::CheckPoint
 | ||
| 
 | ||
| Subclass for CheckPoint devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::CheckPoint> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Cisco
 | ||
| 
 | ||
| This is a simple wrapper around layer 3 for IOS devices and the base layer 3
 | ||
| Cisco class for other device specific layer 3 Cisco classes.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Cisco> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::CiscoASA
 | ||
| 
 | ||
| Subclass for Cisco Adaptive Security Appliances.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::CiscoASA> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::CiscoFWSM
 | ||
| 
 | ||
| Subclass for Cisco Firewall Services Modules.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::CiscoFWSM> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::CiscoSwitch
 | ||
| 
 | ||
| Base class for L3 Cisco switches.  See documentation in
 | ||
| L<SNMP::Info::Layer3::CiscoSwitch> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Contivity
 | ||
| 
 | ||
| Subclass for Avaya/Nortel Contivity/VPN Routers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Contivity> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Cumulus
 | ||
| 
 | ||
| Subclass for Cumulus Networks Routers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Cumulus> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::DLink
 | ||
| 
 | ||
| Subclass for DLink devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::DLink> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Dell
 | ||
| 
 | ||
| Subclass for Dell PowerConnect switches. The IBM BladeCenter
 | ||
| Gigabit Ethernet Switch Module and some Linksys switches
 | ||
| also use this module based upon MIB support.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Dell> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Enterasys
 | ||
| 
 | ||
| Subclass for Enterasys devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Enterasys> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::ERX
 | ||
| 
 | ||
| Subclass for Juniper ERX switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::ERX> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Extreme
 | ||
| 
 | ||
| Subclass for Extreme Networks switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Extreme> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::F5
 | ||
| 
 | ||
| Subclass for F5 devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::F5> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Force10
 | ||
| 
 | ||
| Subclass for Force10 devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Force10> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Fortinet
 | ||
| 
 | ||
| Subclass for Fortinet devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Fortinet> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Foundry
 | ||
| 
 | ||
| Subclass for Brocade (Foundry) Network devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Foundry> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Genua
 | ||
| 
 | ||
| Subclass for Genua security devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Genua> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::H3C
 | ||
| 
 | ||
| SNMP Interface to Layer 3 Devices, H3C & HP A-series.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::H3C> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::HP9300
 | ||
| 
 | ||
| Subclass for HP network devices which Foundry Networks was the
 | ||
| Original Equipment Manufacturer (OEM) such as the HP ProCurve 9300 and 6300 series.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::HP9300> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Huawei
 | ||
| 
 | ||
| SNMP Interface to Huawei Layer 3 switches and routers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Huawei> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::IBMGbTor
 | ||
| 
 | ||
| SNMP Interface to IBM Rackswitch (formerly Blade Network Technologies)
 | ||
| network devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::IBMGbTor> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Juniper
 | ||
| 
 | ||
| Subclass for Juniper devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Juniper> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Lantronix
 | ||
| 
 | ||
| Subclass for Lantronix devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Lantronix> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Microsoft
 | ||
| 
 | ||
| Subclass for Generic Microsoft Routers running Microsoft Windows OS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Microsoft> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Mikrotik
 | ||
| 
 | ||
| Subclass for Mikrotik devices running RouterOS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Mikrotik> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::N1600
 | ||
| 
 | ||
| Subclass for Avaya/Nortel Ethernet Routing Switch 1600 series.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::N1600> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::NetSNMP
 | ||
| 
 | ||
| Subclass for host systems running Net-SNMP.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::NetSNMP> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Netscreen
 | ||
| 
 | ||
| Subclass for Juniper NetScreen.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Netscreen> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Nexus
 | ||
| 
 | ||
| Subclass for Cisco Nexus devices running NX-OS
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Nexus> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::OneAccess
 | ||
| 
 | ||
| Subclass for OneAccess Quidway switches
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::OneAccess> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::PacketFront
 | ||
| 
 | ||
| Subclass for PacketFront DRG series CPE.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::PacketFront> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::PaloAlto
 | ||
| 
 | ||
| Subclass for Palo Alto firewalls.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::PaloAlto> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Passport
 | ||
| 
 | ||
| Subclass for Avaya/Nortel Ethernet Routing Switch/Passport 8000 series,
 | ||
| Accelar, and VSP 9000 series switches.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Passport> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Pf
 | ||
| 
 | ||
| Subclass for FreeBSD-Based Firewalls using Pf /Pf Sense
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Pf> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Pica8
 | ||
| 
 | ||
| Subclass for Pica8 devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Pica8> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::SonicWALL
 | ||
| 
 | ||
| Subclass for generic SonicWALL devices. See documentation in
 | ||
| L<SNMP::Info::Layer3::SonicWALL> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Steelhead
 | ||
| 
 | ||
| Subclass for  Riverbed Steelhead WAN optimization appliances. See
 | ||
| documentation in L<SNMP::Info::Layer3::Steelhead> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Sun
 | ||
| 
 | ||
| Subclass for Generic Sun Routers running SunOS.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Sun> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Tasman
 | ||
| 
 | ||
| Subclass for Avaya Secure Routers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Tasman> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::Timetra
 | ||
| 
 | ||
| Alcatel-Lucent SR Class.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::Timetra> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::VyOS
 | ||
| 
 | ||
| Subclass for VyOS routers.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::VyOS> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer3::VMware
 | ||
| 
 | ||
| Subclass for VMware ESXi hosts.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer3::VMware> for details.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =over 4
 | ||
| 
 | ||
| =item SNMP::Info::Layer7
 | ||
| 
 | ||
| Generic Layer7 Devices.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7> for details.
 | ||
| 
 | ||
| =over 4
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::APC
 | ||
| 
 | ||
| Subclass for APC UPS devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::APC> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::Arbor
 | ||
| 
 | ||
| Subclass for Arbor appliances
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::Arbor> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::CiscoIPS
 | ||
| 
 | ||
| Subclass for Cisco IPS devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::CiscoIPS> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::Gigamon
 | ||
| 
 | ||
| Subclass for Gigamon devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::Gigamon> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::Liebert
 | ||
| 
 | ||
| Subclass for Liebert devices
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::Liebert> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::Netscaler
 | ||
| 
 | ||
| Subclass for Citrix Netscaler appliances
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::Netscaler> for details.
 | ||
| 
 | ||
| =item SNMP::Info::Layer7::Neoteris
 | ||
| 
 | ||
| Subclass for Juniper SSL VPN appliances
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::Layer7::Neoteris> for details.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head1 Thanks
 | ||
| 
 | ||
| Thanks for testing and coding help (in no particular order) to :
 | ||
| Alexander Barthel, Andy Ford, Alexander Hartmaier, Andrew Herrick, Alex
 | ||
| Kramarov, Bernhard Augenstein, Bradley Baetz, Brian Chow, Brian Wilson,
 | ||
| Carlos Vicente, Dana Watanabe, David Pinkoski, David Sieborger, Douglas
 | ||
| McKeown, Greg King, Ivan Auger, Jean-Philippe Luiggi, Jeroen van Ingen,
 | ||
| Justin Hunter, Kent Hamilton, Matthew Tuttle, Michael Robbert, Mike Hunter,
 | ||
| Nicolai Petri, Ralf Gross, Robert Kerr, Nick Nauwelaerts and people listed
 | ||
| on the Netdisco README!
 | ||
| 
 | ||
| =head1 USAGE
 | ||
| 
 | ||
| =head2 Constructor
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item new()
 | ||
| 
 | ||
| Creates a new object and connects via SNMP::Session.
 | ||
| 
 | ||
|  my $info = new SNMP::Info( 'Debug'             => 1,
 | ||
|                             'AutoSpecify'       => 1,
 | ||
|                             'BigInt'            => 1,
 | ||
|                             'BulkWalk'          => 1,
 | ||
|                             'BulkRepeaters'     => 20,
 | ||
|                             'IgnoreNetSNMPConf' => 1,
 | ||
|                             'LoopDetect'        => 1,
 | ||
|                             'DestHost'          => 'myrouter',
 | ||
|                             'Community'         => 'public',
 | ||
|                             'Version'           => 2,
 | ||
|                             'MibDirs'           => ['dir1','dir2','dir3'],
 | ||
|                           ) or die;
 | ||
| 
 | ||
| SNMP::Info Specific Arguments :
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item AutoSpecify
 | ||
| 
 | ||
| Returns an object of a more specific device class
 | ||
| 
 | ||
| (default 0, which means "off")
 | ||
| 
 | ||
| =item BigInt
 | ||
| 
 | ||
| Return Math::BigInt objects for 64 bit counters.  Sets on a global scope,
 | ||
| not object.
 | ||
| 
 | ||
| (default 0, which means "off")
 | ||
| 
 | ||
| =item BulkWalk
 | ||
| 
 | ||
| Set to C<0> to turn off BULKWALK commands for SNMPv2 connections.
 | ||
| 
 | ||
| Note that BULKWALK is turned off for Net-SNMP versions 5.1.x because of a bug.
 | ||
| 
 | ||
| (default 1, which means "on")
 | ||
| 
 | ||
| =item BulkRepeaters
 | ||
| 
 | ||
| Set number of MaxRepeaters for BULKWALK operation.  See
 | ||
| C<perldoc SNMP> -> bulkwalk() for more info.
 | ||
| 
 | ||
| (default 20)
 | ||
| 
 | ||
| =item LoopDetect
 | ||
| 
 | ||
| Detects looping during getnext table column walks by comparing IIDs for each
 | ||
| instance.  A loop is detected if the same IID is seen more than once and the
 | ||
| walk is aborted.  Note:  This will not detect loops during a bulkwalk
 | ||
| operation, Net-SNMP's internal bulkwalk function must detect the loop.
 | ||
| 
 | ||
| Set to C<0> to turn off loop detection.
 | ||
| 
 | ||
| (default 1, which means "on")
 | ||
| 
 | ||
| =item IgnoreNetSNMPConf
 | ||
| 
 | ||
| Net-SNMP version 5.0 and higher read configuration files, snmp.conf or
 | ||
| snmp.local.conf, from /etc/snmp, /usr/share/snmp, /usr/lib(64)/snmp, or
 | ||
| $HOME/.snmp and uses those settings to automatically parse MIB files, etc.
 | ||
| 
 | ||
| Set to C<1> "on" to ignore Net-SNMP configuration files by overriding the
 | ||
| C<SNMPCONFPATH> environmental variable during object initialization. Note:
 | ||
| MibDirs must be defined or Net-SNMP will not be able to load MIBs and
 | ||
| initialize the object.
 | ||
| 
 | ||
| (default 0, which means "off")
 | ||
| 
 | ||
| =item Debug
 | ||
| 
 | ||
| Prints Lots of debugging messages.
 | ||
| Pass 2 to print even more debugging messages.
 | ||
| 
 | ||
| (default 0, which means "off")
 | ||
| 
 | ||
| =item DebugSNMP
 | ||
| 
 | ||
| Set $SNMP::debugging level for Net-SNMP.
 | ||
| 
 | ||
| See F<SNMP> for more details.
 | ||
| 
 | ||
| =item MibDirs
 | ||
| 
 | ||
| Array ref to list of directories in which to look for MIBs.  Note this will
 | ||
| be in addition to the ones setup in snmp.conf at the system level.
 | ||
| 
 | ||
| (default use net-snmp settings only)
 | ||
| 
 | ||
| =item RetryNoSuch
 | ||
| 
 | ||
| When using SNMP Version 1, try reading values even if they come back as "no
 | ||
| such variable in this MIB".  Set to false if so desired.  This feature lets
 | ||
| you read SNMPv2 data from an SNMP version 1 connection, and should probably
 | ||
| be left on.
 | ||
| 
 | ||
| (default 1, which means "on")
 | ||
| 
 | ||
| =item Session
 | ||
| 
 | ||
| SNMP::Session object to use instead of connecting on own.
 | ||
| 
 | ||
| (default creates session automatically)
 | ||
| 
 | ||
| =item Offline
 | ||
| 
 | ||
| Causes SNMP::Info to avoid network activity and return data only from its
 | ||
| cache. If you ask for something not in the cache, an error is thrown.  See
 | ||
| also the C<cache()> and C<offline()> methods.
 | ||
| 
 | ||
| (default 0, which means "online")
 | ||
| 
 | ||
| =item Cache
 | ||
| 
 | ||
| Pass in a HashRef to prime the cache of retrieved data. Useful for creating an
 | ||
| instance in C<Offline> mode from a previously dumped cache. See also the
 | ||
| C<cache()> method to retrieve a cache after running actial queries.
 | ||
| 
 | ||
| =item OTHER
 | ||
| 
 | ||
| All other arguments are passed to SNMP::Session.
 | ||
| 
 | ||
| See SNMP::Session for a list of other possible arguments.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| A Note about the wrong Community string or wrong SNMP Version:
 | ||
| 
 | ||
| If a connection is using the wrong community string or the wrong SNMP version,
 | ||
| the creation of the object will not fail.  The device still answers the call
 | ||
| on the SNMP port, but will not return information.  Check the error() method
 | ||
| after you create the device object to see if there was a problem in
 | ||
| connecting.
 | ||
| 
 | ||
| A note about SNMP Versions :
 | ||
| 
 | ||
| Some older devices don't support SNMP version 2, and will not return anything
 | ||
| when a connection under Version 2 is attempted.
 | ||
| 
 | ||
| Some newer devices will support Version 1, but will not return all the data
 | ||
| they might have if you had connected under Version 1
 | ||
| 
 | ||
| When trying to get info from a new device, you may have to try version 2 and
 | ||
| then fallback to version 1.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub new {
 | ||
|     my $proto     = shift;
 | ||
|     my $class     = ref($proto) || $proto;
 | ||
|     my %args      = @_;
 | ||
|     my %sess_args = %args;
 | ||
|     my $new_obj   = {};
 | ||
|     bless $new_obj, $class;
 | ||
| 
 | ||
|     $new_obj->{class} = $class;
 | ||
| 
 | ||
|     # load references to all the subclass data structures
 | ||
|     {
 | ||
|         no strict 'refs';    ## no critic (ProhibitNoStrict ProhibitProlongedStrictureOverride)
 | ||
|         $new_obj->{init}    = \${ $class . '::INIT' };
 | ||
|         $new_obj->{mibs}    = \%{ $class . '::MIBS' };
 | ||
|         $new_obj->{globals} = \%{ $class . '::GLOBALS' };
 | ||
|         $new_obj->{funcs}   = \%{ $class . '::FUNCS' };
 | ||
|         $new_obj->{munge}   = \%{ $class . '::MUNGE' };
 | ||
|     }
 | ||
| 
 | ||
|     # SNMP::Info specific args :
 | ||
|     if ( defined $args{Debug} ) {
 | ||
|         $new_obj->debug( $args{Debug} );
 | ||
|         delete $sess_args{Debug};
 | ||
|     }
 | ||
|     else {
 | ||
|         $new_obj->debug( defined $DEBUG ? $DEBUG : 0 );
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{DebugSNMP} ) {
 | ||
|         $SNMP::debugging = $args{DebugSNMP};
 | ||
|         delete $sess_args{DebugSNMP};
 | ||
|     }
 | ||
| 
 | ||
|     my $auto_specific = 0;
 | ||
|     if ( defined $args{AutoSpecify} ) {
 | ||
|         $auto_specific = $args{AutoSpecify} || 0;
 | ||
|         delete $sess_args{AutoSpecify};
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{BulkRepeaters} ) {
 | ||
|         $new_obj->{BulkRepeaters} = $args{BulkRepeaters};
 | ||
|         delete $sess_args{BulkRepeaters};
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{BulkWalk} ) {
 | ||
|         $new_obj->{BulkWalk} = $args{BulkWalk};
 | ||
|         delete $sess_args{BulkWalk};
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{LoopDetect} ) {
 | ||
|         $new_obj->{LoopDetect} = $args{LoopDetect};
 | ||
|         delete $sess_args{LoopDetect};
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{IgnoreNetSNMPConf} ) {
 | ||
|         $new_obj->{IgnoreNetSNMPConf} = $args{IgnoreNetSNMPConf} || 0;
 | ||
|         delete $sess_args{IgnoreNetSNMPConf};
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{Offline} ) {
 | ||
|         $new_obj->{Offline} = $args{Offline} || 0;
 | ||
|         delete $sess_args{Offline};
 | ||
|     }
 | ||
| 
 | ||
|     if ( defined $args{Cache} and ref {} eq ref $args{Cache} ) {
 | ||
|         $new_obj->{$_} = $args{Cache}->{$_} for keys %{$args{Cache}};
 | ||
|         delete $sess_args{Cache};
 | ||
|     }
 | ||
| 
 | ||
|     my $sess = undef;
 | ||
|     if ( defined $args{Session} ) {
 | ||
|         $sess = $args{Session};
 | ||
|         delete $sess_args{Session};
 | ||
|     }
 | ||
|     if ( defined $args{BigInt} ) {
 | ||
|         $BIGINT = $args{BigInt};
 | ||
|         delete $sess_args{BigInt};
 | ||
|     }
 | ||
|     if ( defined $args{MibDirs} ) {
 | ||
|         $new_obj->{mibdirs} = $args{MibDirs};
 | ||
|         delete $sess_args{MibDirs};
 | ||
|     }
 | ||
|     
 | ||
|     # For IPv6 hosts set transport
 | ||
|     if ( defined $sess_args{DestHost} ) {
 | ||
|         $sess_args{DestHost} = resolve_desthost($sess_args{DestHost});
 | ||
|     }
 | ||
| 
 | ||
|     $new_obj->{nosuch} = $args{RetryNoSuch} || $NOSUCH;
 | ||
| 
 | ||
|     # Initialize mibs if not done
 | ||
|     my $init_ref = $new_obj->{init};
 | ||
|     unless ( defined $$init_ref and $$init_ref ) {
 | ||
|         $new_obj->init();
 | ||
|         $$init_ref = 1;
 | ||
|     }
 | ||
| 
 | ||
|     # Connects to device unless open session is provided.
 | ||
|     $sess = SNMP::Session->new(
 | ||
|         'UseEnums' => 1,
 | ||
|         %sess_args, 'RetryNoSuch' => $new_obj->{nosuch}
 | ||
|     ) unless defined $sess;
 | ||
| 
 | ||
|     # No session object created
 | ||
|     unless ( defined $sess ) {
 | ||
|         $new_obj->error_throw("SNMP::Info::new() Failed to Create Session. ");
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     # Session object created but SNMP connection failed.
 | ||
|     my $sess_err = $sess->{ErrorStr} || '';
 | ||
|     if ($sess_err) {
 | ||
|         $new_obj->error_throw(
 | ||
|             "SNMP::Info::new() Net-SNMP session creation failed. $sess_err");
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     # Save Args for later
 | ||
|     $new_obj->{store}     ||= {};
 | ||
|     $new_obj->{sess}      = $sess;
 | ||
|     $new_obj->{args}      = \%args;
 | ||
|     $new_obj->{snmp_ver}  = $sess->{Version}   || $args{Version}   || 2;
 | ||
|     $new_obj->{snmp_comm} = $sess->{Community} || $args{Community} || 'public';
 | ||
|     $new_obj->{snmp_user} = $sess->{SecName}   || $args{SecName}   || 'initial';
 | ||
| 
 | ||
|     return $auto_specific ? $new_obj->specify() : $new_obj;
 | ||
| }
 | ||
| 
 | ||
| =item update()
 | ||
| 
 | ||
| Replace the existing session with a new one with updated values,
 | ||
| without re-identifying the device.  The only supported changes are
 | ||
| to Community or Context.
 | ||
| 
 | ||
| Clears the object cache.
 | ||
| 
 | ||
| This is useful, e.g., when a device supports multiple contexts
 | ||
| (via changes to the Community string, or via the SNMPv3 Context
 | ||
| parameter), but a context that you want to access does not support
 | ||
| the objects (e.g., C<sysObjectID>, C<sysDescr>) that we use to identify
 | ||
| the device.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub update {
 | ||
|     my $obj         = shift;
 | ||
|     my %update_args = @_;
 | ||
|     my %sess_args   = ( %{ $obj->{args} }, %update_args );
 | ||
| 
 | ||
|     # silently only update "the right" args
 | ||
|     delete $sess_args{Debug};
 | ||
|     delete $sess_args{DebugSNMP};
 | ||
|     delete $sess_args{AutoSpecify};
 | ||
|     delete $sess_args{BulkRepeaters};
 | ||
|     delete $sess_args{BulkWalk};
 | ||
|     delete $sess_args{LoopDetect};
 | ||
|     delete $sess_args{IgnoreNetSNMPConf};
 | ||
|     delete $sess_args{BigInt};
 | ||
|     delete $sess_args{MibDirs};
 | ||
| 
 | ||
|     my $sess = SNMP::Session->new(
 | ||
|         'UseEnums' => 1,
 | ||
|         %sess_args, 'RetryNoSuch' => $obj->{nosuch}
 | ||
|     );
 | ||
|     unless ( defined $sess ) {
 | ||
|         $obj->error_throw(
 | ||
|             "SNMP::Info::update() Failed to Create new Session. ");
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     # Session object created but SNMP connection failed.
 | ||
|     my $sess_err = $sess->{ErrorStr} || '';
 | ||
|     if ($sess_err) {
 | ||
|         $obj->error_throw(
 | ||
|             "SNMP::Info::update() Net-SNMP session creation failed. $sess_err"
 | ||
|         );
 | ||
|         return;
 | ||
|     }
 | ||
|     $obj->clear_cache();
 | ||
|     return $obj->session($sess);
 | ||
| }
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Data is Cached
 | ||
| 
 | ||
| Methods and subroutines requesting data from a device will only load the data
 | ||
| once, and then return cached versions of that data.
 | ||
| 
 | ||
| Run $info->load_METHOD() where method is something like 'i_name' to reload
 | ||
| data from a method.
 | ||
| 
 | ||
| Run $info->clear_cache() to clear the cache to allow reload of both globals
 | ||
| and table methods.
 | ||
| 
 | ||
| The cache can be retrieved or set using the $info->cache() method. This works
 | ||
| together with the C<Offline> option.
 | ||
| 
 | ||
| =head2 Object Scalar Methods
 | ||
| 
 | ||
| These are for package related data, not directly supplied
 | ||
| from SNMP.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->clear_cache()
 | ||
| 
 | ||
| Clears the cached data.  This includes GLOBALS data and TABLE METHOD data.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub clear_cache {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     print "SNMP::Info::clear_cache() - Cache Cleared.\n" if $self->debug();
 | ||
| 
 | ||
|     # Clear cached global values and table method flag for being cached
 | ||
|     foreach my $key ( keys %$self ) {
 | ||
|         next unless defined $key;
 | ||
|         next unless $key =~ /^_/;
 | ||
|         delete $self->{$key};
 | ||
|     }
 | ||
| 
 | ||
|     # Clear store for tables
 | ||
|     return $self->store( {} );
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| =item $info->debug(1)
 | ||
| 
 | ||
| Returns current debug status, and optionally toggles debugging info for this
 | ||
| object.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub debug {
 | ||
|     my $self  = shift;
 | ||
|     my $debug = shift;
 | ||
| 
 | ||
|     if ( defined $debug ) {
 | ||
|         $self->{debug} = $debug;
 | ||
|     }
 | ||
| 
 | ||
|     return $self->{debug};
 | ||
| }
 | ||
| 
 | ||
| =item $info->offline([1|0])
 | ||
| 
 | ||
| Returns if offline mode is currently turned on for this object.
 | ||
| 
 | ||
| Optionally sets the Offline parameter.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub offline {
 | ||
|     my $self = shift;
 | ||
|     my $ol   = shift;
 | ||
| 
 | ||
|     if ( defined $ol ) {
 | ||
|         $self->{Offline} = $ol;
 | ||
|     }
 | ||
|     return $self->{Offline};
 | ||
| }
 | ||
| 
 | ||
| =item $info->cache([new_cache])
 | ||
| 
 | ||
| Returns a HashRef of all cached data in this object. There will be a C<store>
 | ||
| key for table data and then one key for each leaf.
 | ||
| 
 | ||
| Optionally sets the cache parameters if passed a HashRef.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub cache {
 | ||
|     my $self = shift;
 | ||
|     my $data = shift;
 | ||
| 
 | ||
|     if ( defined $data and ref {} eq ref $data ) {
 | ||
|         $self->{$_} = $data->{$_} for keys %$data;
 | ||
|     }
 | ||
| 
 | ||
|     my $cache = { store => $self->{store} };
 | ||
|     foreach my $key ( keys %$self ) {
 | ||
|         next unless defined $key;
 | ||
|         next unless $key =~ /^_/;
 | ||
|         $cache->{$key} = $self->{$key};
 | ||
|     }
 | ||
|     return $cache;
 | ||
| }
 | ||
| 
 | ||
| =item $info->bulkwalk([1|0])
 | ||
| 
 | ||
| Returns if bulkwalk is currently turned on for this object.
 | ||
| 
 | ||
| Optionally sets the bulkwalk parameter.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub bulkwalk {
 | ||
|     my $self = shift;
 | ||
|     my $bw   = shift;
 | ||
| 
 | ||
|     if ( defined $bw ) {
 | ||
|         $self->{BulkWalk} = $bw;
 | ||
|     }
 | ||
|     return $self->{BulkWalk};
 | ||
| }
 | ||
| 
 | ||
| =item $info->loopdetect([1|0])
 | ||
| 
 | ||
| Returns if loopdetect is currently turned on for this object.
 | ||
| 
 | ||
| Optionally sets the loopdetect parameter.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub loopdetect {
 | ||
|     my $self = shift;
 | ||
|     my $ld   = shift;
 | ||
| 
 | ||
|     if ( defined $ld ) {
 | ||
|         $self->{LoopDetect} = $ld;
 | ||
|     }
 | ||
|     return $self->{LoopDetect};
 | ||
| }
 | ||
| 
 | ||
| =item $info->device_type()
 | ||
| 
 | ||
| Returns the Subclass name for this device.  C<SNMP::Info> is returned if no
 | ||
| more specific class is available.
 | ||
| 
 | ||
| First the device is checked for Layer 3 support and a specific subclass,
 | ||
| then Layer 2 support and subclasses are checked.
 | ||
| 
 | ||
| This means that Layer 2 / 3  switches and routers will fall under the
 | ||
| SNMP::Info::Layer3 subclasses.
 | ||
| 
 | ||
| If the device still can be connected to via SNMP::Info, then
 | ||
| SNMP::Info is returned.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub device_type {
 | ||
|     my $info = shift;
 | ||
| 
 | ||
|     my $objtype = "SNMP::Info";
 | ||
| 
 | ||
|     my $layers = $info->layers() || '00000000';
 | ||
| 
 | ||
|     my $desc = $info->description() || 'undef';
 | ||
|     $desc =~ s/[\r\n\l]+/ /g;
 | ||
| 
 | ||
|     # Some devices don't implement sysServices, but do return a description.
 | ||
|     # In that case, log a warning and continue.
 | ||
|     if ( $layers eq '00000000' ) {
 | ||
|         if ($desc ne 'undef') {
 | ||
|             carp("Device doesn't implement sysServices but did return sysDescr. Might give unexpected results.\n") if $info->debug();
 | ||
|         } else {
 | ||
|             # No sysServices, no sysDescr
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     my $id = $info->id() || 'undef';
 | ||
|     my $soid = $id;
 | ||
| 
 | ||
|     # Hash for generic fallback to a device class if unable to determine using
 | ||
|     # the sysDescr regex.
 | ||
|     my %l3sysoidmap = (
 | ||
|         9    => 'SNMP::Info::Layer3::Cisco',
 | ||
|         11   => 'SNMP::Info::Layer2::HP',
 | ||
|         18   => 'SNMP::Info::Layer3::BayRS',
 | ||
|         42   => 'SNMP::Info::Layer3::Sun',
 | ||
|         43   => 'SNMP::Info::Layer2::3Com',
 | ||
|         45   => 'SNMP::Info::Layer2::Baystack',
 | ||
|         171  => 'SNMP::Info::Layer3::DLink',
 | ||
|         244  => 'SNMP::Info::Layer3::Lantronix',
 | ||
|         311  => 'SNMP::Info::Layer3::Microsoft',
 | ||
|         664   => 'SNMP::Info::Layer2::Adtran',
 | ||
|         674  => 'SNMP::Info::Layer3::Dell',
 | ||
|         1588 => 'SNMP::Info::Layer3::Foundry',
 | ||
|         1872 => 'SNMP::Info::Layer3::AlteonAD',
 | ||
|         1916 => 'SNMP::Info::Layer3::Extreme',
 | ||
|         1991 => 'SNMP::Info::Layer3::Foundry',
 | ||
|         2011 => 'SNMP::Info::Layer3::Huawei',
 | ||
|         2021 => 'SNMP::Info::Layer3::NetSNMP',
 | ||
|         2272 => 'SNMP::Info::Layer3::Passport',
 | ||
|         2620 => 'SNMP::Info::Layer3::CheckPoint',
 | ||
|         2636 => 'SNMP::Info::Layer3::Juniper',
 | ||
|         2925 => 'SNMP::Info::Layer1::Cyclades',
 | ||
|         3076 => 'SNMP::Info::Layer3::Altiga',
 | ||
|         3224 => 'SNMP::Info::Layer3::Netscreen',
 | ||
|         3375 => 'SNMP::Info::Layer3::F5',
 | ||
|         3417 => 'SNMP::Info::Layer3::BlueCoatSG',
 | ||
|         3717 => 'SNMP::Info::Layer3::Genua',
 | ||
|         4526 => 'SNMP::Info::Layer2::Netgear',
 | ||
|         4874 => 'SNMP::Info::Layer3::ERX',
 | ||
|         5624 => 'SNMP::Info::Layer3::Enterasys',
 | ||
|         6027 => 'SNMP::Info::Layer3::Force10',
 | ||
|         6486 => 'SNMP::Info::Layer3::AlcatelLucent',
 | ||
|         6527 => 'SNMP::Info::Layer3::Timetra',
 | ||
|         6876 => 'SNMP::Info::Layer3::VMware',
 | ||
|         8072 => 'SNMP::Info::Layer3::NetSNMP',
 | ||
|         9303 => 'SNMP::Info::Layer3::PacketFront',
 | ||
|         10002 => 'SNMP::Info::Layer2::Ubiquiti',
 | ||
|         10418 => 'SNMP::Info::Layer1::Cyclades',
 | ||
|         12325 => 'SNMP::Info::Layer3::Pf',
 | ||
|         12356 => 'SNMP::Info::Layer3::Fortinet',
 | ||
|         13191 => 'SNMP::Info::Layer3::OneAccess',
 | ||
|         14179 => 'SNMP::Info::Layer2::Airespace',
 | ||
|         14525 => 'SNMP::Info::Layer2::Trapeze',
 | ||
|         14823 => 'SNMP::Info::Layer3::Aruba',
 | ||
|         14988 => 'SNMP::Info::Layer3::Mikrotik',
 | ||
|         17163 => 'SNMP::Info::Layer3::Steelhead',
 | ||
|         21091 => 'SNMP::Info::Layer2::Exinda',
 | ||
|         25506 => 'SNMP::Info::Layer3::H3C',
 | ||
|         25461 => 'SNMP::Info::Layer3::PaloAlto',
 | ||
|         26543 => 'SNMP::Info::Layer3::IBMGbTor',
 | ||
|         30065 => 'SNMP::Info::Layer3::Arista',
 | ||
|         35098 => 'SNMP::Info::Layer3::Pica8',
 | ||
|         41112 => 'SNMP::Info::Layer2::Ubiquiti',
 | ||
|         4413 => 'SNMP::Info::Layer2::Ubiquiti',
 | ||
|         26928 => 'SNMP::Info::Layer2::Aerohive',
 | ||
|         30803 => 'SNMP::Info::Layer3::VyOS',
 | ||
|         40310 => 'SNMP::Info::Layer3::Cumulus',
 | ||
|     );
 | ||
| 
 | ||
|     my %l2sysoidmap = (
 | ||
|         9     => 'SNMP::Info::Layer2::Cisco',
 | ||
|         11    => 'SNMP::Info::Layer2::HP',
 | ||
|         43    => 'SNMP::Info::Layer2::3Com',
 | ||
|         45    => 'SNMP::Info::Layer2::Baystack',
 | ||
|         171   => 'SNMP::Info::Layer3::DLink',
 | ||
|         207   => 'SNMP::Info::Layer2::Allied',
 | ||
|         266   => 'SNMP::Info::Layer2::Nexans',
 | ||
|         664   => 'SNMP::Info::Layer2::Adtran',
 | ||
|         674   => 'SNMP::Info::Layer3::Dell',
 | ||
|         1872  => 'SNMP::Info::Layer3::AlteonAD',
 | ||
|         1916  => 'SNMP::Info::Layer3::Extreme',
 | ||
|         1991  => 'SNMP::Info::Layer3::Foundry',
 | ||
|         2011  => 'SNMP::Info::Layer3::Huawei',
 | ||
|         2272  => 'SNMP::Info::Layer3::Passport',
 | ||
|         2925  => 'SNMP::Info::Layer1::Cyclades',
 | ||
|         3224  => 'SNMP::Info::Layer3::Netscreen',
 | ||
|         3375  => 'SNMP::Info::Layer3::F5',
 | ||
|         4526  => 'SNMP::Info::Layer2::Netgear',
 | ||
|         5624  => 'SNMP::Info::Layer3::Enterasys',
 | ||
|         6486  => 'SNMP::Info::Layer3::AlcatelLucent',
 | ||
|         9303  => 'SNMP::Info::Layer3::PacketFront',
 | ||
|         10418 => 'SNMP::Info::Layer1::Cyclades',
 | ||
|         11898 => 'SNMP::Info::Layer2::Orinoco',
 | ||
|         13458 => 'SNMP::Info::Layer2::Atmedia',
 | ||
|         14179 => 'SNMP::Info::Layer2::Airespace',
 | ||
|         14525 => 'SNMP::Info::Layer2::Trapeze',
 | ||
|         14823 => 'SNMP::Info::Layer3::Aruba',
 | ||
|         17163 => 'SNMP::Info::Layer3::Steelhead',
 | ||
|         20540 => 'SNMP::Info::Layer2::Sixnet',
 | ||
|         21091 => 'SNMP::Info::Layer2::Exinda',
 | ||
|         26543 => 'SNMP::Info::Layer3::IBMGbTor',
 | ||
|         26928 => 'SNMP::Info::Layer2::Aerohive',
 | ||
|     );
 | ||
| 
 | ||
|     my %l1sysoidmap = (
 | ||
|         2925  => 'SNMP::Info::Layer1::Cyclades',
 | ||
|         10418 => 'SNMP::Info::Layer1::Cyclades',
 | ||
|     );
 | ||
| 
 | ||
|     my %l7sysoidmap = (
 | ||
|         318   => 'SNMP::Info::Layer7::APC',
 | ||
|         476   => 'SNMP::Info::Layer7::Liebert',
 | ||
|         5951  => 'SNMP::Info::Layer7::Netscaler',
 | ||
|         9694  => 'SNMP::Info::Layer7::Arbor',
 | ||
|         14525 => 'SNMP::Info::Layer2::Trapeze',
 | ||
|         12532 => 'SNMP::Info::Layer7::Neoteris',
 | ||
|         26866 => 'SNMP::Info::Layer7::Gigamon',
 | ||
|     );
 | ||
| 
 | ||
|     # Get just the enterprise number for generic mapping
 | ||
|     $id = $1 if ( defined($id) && $id =~ /^\.1\.3\.6\.1\.4\.1\.(\d+)/ );
 | ||
| 
 | ||
|     if ($info->debug()) {
 | ||
|         print "SNMP::Info $VERSION\n";
 | ||
|         print "SNMP::Info::device_type() layers:$layers id:$id sysDescr:\"$desc\"\n";
 | ||
|     }
 | ||
| 
 | ||
|     # Layer 3 Supported
 | ||
|     #   (usually has layer2 as well, so we check for 3 first)
 | ||
|     if ( $info->has_layer(3) ) {
 | ||
|         $objtype = 'SNMP::Info::Layer3';
 | ||
| 
 | ||
|         # Device Type Overrides
 | ||
| 
 | ||
|         return $objtype unless ( defined $desc and length($desc) );
 | ||
| 
 | ||
|         $objtype = 'SNMP::Info::Layer3::C3550' if $desc =~ /(C3550|C3560)/;
 | ||
|         $objtype = 'SNMP::Info::Layer3::C4000' if $desc =~ /Catalyst 4[05]00/;
 | ||
|         $objtype = 'SNMP::Info::Layer3::Foundry' if $desc =~ /foundry/i;
 | ||
|         $objtype = 'SNMP::Info::Layer3::ERX' if $desc =~ /erx/i;
 | ||
| 
 | ||
|         # Aironet - older non-IOS
 | ||
|         $objtype = 'SNMP::Info::Layer3::Aironet'
 | ||
|             if ($desc =~ /Cisco/
 | ||
|             and $desc =~ /\D(CAP340|AP340|CAP350|350|1200)\D/ );
 | ||
|         $objtype = 'SNMP::Info::Layer3::Aironet'
 | ||
|             if ( $desc =~ /Aironet/ and $desc =~ /\D(AP4800)\D/ );
 | ||
| 
 | ||
| 	# Override voice gateway device (VG350) showing up as Aironet
 | ||
|         $objtype = 'SNMP::Info::Layer3::Cisco' if $desc =~ /VG350/;
 | ||
| 
 | ||
|         # Cat6k with older SUPs (hybrid CatOS/IOS?)
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500' if $desc =~ /(c6sup2|c6sup1)/;
 | ||
| 
 | ||
|         # Cat6k with Sup720, Sup720 or Sup2T (and Sup2 running native IOS?)
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if $desc =~ /(s72033_rp|s3223_rp|s32p3_rp|s222_rp|s2t54)/;
 | ||
| 
 | ||
|         # Next one untested. Reported working by DA
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if ( $desc =~ /cisco/i and $desc =~ /3750/ );
 | ||
| 
 | ||
|         # IOS 15.x on Catalyst 3850
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if ( $desc =~ /cisco/i and $desc =~ /CAT3K/ );
 | ||
| 
 | ||
|         #   Cisco 2970
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if ( $desc =~ /(C2970|C2960)/ );
 | ||
| 
 | ||
|         #   Cisco 3400 w/ Layer3 capable image
 | ||
|         $objtype = 'SNMP::Info::Layer3::C3550'
 | ||
|             if ( $desc =~ /(ME340x)/ );
 | ||
| 
 | ||
|         # Various Cisco blade switches, CBS30x0 and CBS31x0 models
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if ( $desc =~ /cisco/i and $desc =~ /CBS3[0-9A-Za-z]{3}/ );
 | ||
| 
 | ||
|         # Cisco Nexus running NX-OS
 | ||
|         $objtype = 'SNMP::Info::Layer3::Nexus'
 | ||
|             if ( $desc =~ /^Cisco\s+NX-OS/ );
 | ||
| 
 | ||
|         # HP, older ProCurve models (1600, 2400, 2424m, 4000, 8000)
 | ||
|         $objtype = 'SNMP::Info::Layer2::HP4000'
 | ||
|             if $desc =~ /\b(J4093A|J4110A|J4120A|J4121A|J4122A|J4122B)\b/;
 | ||
| 
 | ||
|         # HP, Foundry OEM
 | ||
|         $objtype = 'SNMP::Info::Layer3::HP9300'
 | ||
|             if $desc =~ /\b(J4874A|J4138A|J4139A|J4840A|J4841A)\b/;
 | ||
| 
 | ||
|         # Nortel ERS (Passport) 1600 Series < version 2.1
 | ||
|         $objtype = 'SNMP::Info::Layer3::N1600'
 | ||
|             if $desc =~ /(Passport|Ethernet\s+Routing\s+Switch)-16/i;
 | ||
| 
 | ||
|         #  ERS - BayStack Numbered
 | ||
|         $objtype = 'SNMP::Info::Layer2::Baystack'
 | ||
|             if ( $desc
 | ||
|             =~ /^(BayStack|Ethernet\s+Routing\s+Switch)\s[2345](\d){2,3}/i );
 | ||
| 
 | ||
|         # Nortel Contivity
 | ||
|         $objtype = 'SNMP::Info::Layer3::Contivity'
 | ||
|           if $desc =~ /(\bCES\b|\bNVR\sV\d)/
 | ||
|               and (!defined $id or !defined $l3sysoidmap{$id});
 | ||
| 
 | ||
|         # SonicWALL
 | ||
|         $objtype = 'SNMP::Info::Layer3::SonicWALL' if $desc =~ /SonicWALL/i;
 | ||
| 
 | ||
|         # Allied Telesis Layer2 managed switches. They report they have L3 support
 | ||
|         $objtype = 'SNMP::Info::Layer2::Allied'
 | ||
|             if ( $desc =~ /Allied.*AT-80\d{2}\S*/i );
 | ||
| 
 | ||
|         # Cisco ASA, newer versions which report layer 3 functionality
 | ||
|         # version >= 8.2 are known to do this
 | ||
|         $objtype = 'SNMP::Info::Layer3::CiscoASA'
 | ||
|             if ( $desc =~ /Cisco Adaptive Security Appliance/i );
 | ||
| 
 | ||
|         # Cisco FTD includes an ASA running as lina process
 | ||
|         $objtype = 'SNMP::Info::Layer3::CiscoASA'
 | ||
|             if ( $desc =~ /Cisco Firepower Threat Defense/i );
 | ||
| 
 | ||
|         # Cisco FWSM
 | ||
|         $objtype = 'SNMP::Info::Layer3::CiscoFWSM'
 | ||
|             if ( $desc =~ /Cisco Firewall Services Module/i );
 | ||
| 
 | ||
|         #   Cisco Small Business (300 500) series override
 | ||
|         #   This is for enterprises(1).cisco(9).otherEnterprises(6).ciscosb(1)
 | ||
|         $objtype = 'SNMP::Info::Layer2::CiscoSB'
 | ||
|             if ( $soid =~ /^\.?1\.3\.6\.1\.4\.1\.9\.6\.1/ );
 | ||
| 
 | ||
|         # Avaya Secure Router
 | ||
|         $objtype = 'SNMP::Info::Layer3::Tasman'
 | ||
|             if ( $desc =~ /^(avaya|nortel)\s+(SR|secure\srouter)\s+\d{4}/i );
 | ||
| 
 | ||
|         # HP Virtual Connect blade switches
 | ||
|         $objtype = 'SNMP::Info::Layer2::HPVC'
 | ||
|             if ( $desc =~ /HP\sVC\s/ );
 | ||
| 
 | ||
|         # Aironet - IOS
 | ||
|         # Starting with IOS 15, Aironet reports sysServices 6, even though
 | ||
|         # it still is the same layer2 access point.
 | ||
|         $objtype = 'SNMP::Info::Layer2::Aironet'
 | ||
|             if ($desc =~ /\b(C1100|C1130|C1140|AP1200|C350|C1200|C1240|C1250|C2700|C3700)\b/
 | ||
|             and $desc =~ /\bIOS\b/ );
 | ||
| 
 | ||
|         # Airespace (WLC) Module
 | ||
|         $objtype = 'SNMP::Info::Layer2::Airespace'
 | ||
|             if ( $desc =~ /^Cisco Controller$/ );
 | ||
| 
 | ||
|         #Nortel 2270
 | ||
|         $objtype = 'SNMP::Info::Layer2::N2270'
 | ||
|             if (
 | ||
|             $desc =~ /Nortel\s+(Networks\s+)??WLAN\s+-\s+Security\s+Switch/ );
 | ||
| 
 | ||
|         # Nortel (Trapeze) WSS 2300 Series
 | ||
|         $objtype = 'SNMP::Info::Layer2::NWSS2300'
 | ||
|             if (
 | ||
|             $desc =~ /^(Nortel\s)??Wireless\sSecurity\sSwitch\s23[568][012]\b/);
 | ||
| 
 | ||
|         # Generic device classification based upon sysObjectID
 | ||
|         if (    ( $objtype eq 'SNMP::Info::Layer3' )
 | ||
|             and ( defined($id) )
 | ||
|             and ( exists( $l3sysoidmap{$id} ) ) )
 | ||
|         {
 | ||
|             $objtype = $l3sysoidmap{$id};
 | ||
|         }
 | ||
| 
 | ||
|         # Layer 2 Supported
 | ||
|     }
 | ||
|     elsif ( $info->has_layer(2) ) {
 | ||
|         $objtype = 'SNMP::Info::Layer2';
 | ||
| 
 | ||
|         return $objtype unless ( defined $desc and $desc !~ /^\s*$/ );
 | ||
| 
 | ||
|         # Device Type Overrides
 | ||
| 
 | ||
|         #  Bay Hub (Needed here for layers override)
 | ||
|         $objtype = 'SNMP::Info::Layer1::Bayhub'
 | ||
|             if ( $desc =~ /\bNMM.*Agent/ );
 | ||
|         $objtype = 'SNMP::Info::Layer1::Bayhub'
 | ||
|             if ( $desc =~ /\bBay\s*Stack.*Hub/i );
 | ||
| 
 | ||
|         #  Synoptics Hub (Needed here for layers override)
 | ||
|         #  This will override Bay Hub only for specific devices supported
 | ||
|         #  by this class
 | ||
|         $objtype = 'SNMP::Info::Layer1::S3000'
 | ||
|             if ( $desc =~ /\bNMM\s+(281|3000|3030)/i );
 | ||
| 
 | ||
|         #   Catalyst 1900 series override
 | ||
|         $objtype = 'SNMP::Info::Layer2::C1900'
 | ||
|             if ( $desc =~ /catalyst/i and $desc =~ /\D19\d{2}/ );
 | ||
| 
 | ||
|         #   Catalyst 2900 and 3500XL (IOS) series override
 | ||
|         $objtype = 'SNMP::Info::Layer2::C2900'
 | ||
|             if ( $desc =~ /(C2900XL|C2950|C3500XL|C2940|CGESM|CIGESM)/i );
 | ||
| 
 | ||
|         #   Catalyst WS-C series override 2926,4k,5k,6k in Hybrid
 | ||
|         $objtype = 'SNMP::Info::Layer2::Catalyst' if ( $desc =~ /WS-C\d{4}/ );
 | ||
| 
 | ||
|         #   Catalyst 3550 / 3548 Layer2 only switches
 | ||
|         #   Cisco 3400 w/ MetroBase Image
 | ||
|         $objtype = 'SNMP::Info::Layer3::C3550'
 | ||
|             if ( $desc =~ /(C3550|ME340x)/ );
 | ||
| 
 | ||
|         # Cisco blade switches, CBS30x0 and CBS31x0 models with L2 only
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if ( $desc =~ /cisco/i and $desc =~ /CBS3[0-9A-Za-z]{3}/ );
 | ||
| 
 | ||
|         #   Cisco 2970
 | ||
|         $objtype = 'SNMP::Info::Layer3::C6500'
 | ||
|             if ( $desc =~ /(C2970|C2960)/ );
 | ||
| 
 | ||
|         #   Cisco Small Business (300 500) series override
 | ||
|         #   This is for enterprises(1).cisco(9).otherEnterprises(6).ciscosb(1)
 | ||
|         $objtype = 'SNMP::Info::Layer2::CiscoSB'
 | ||
|             if ( $soid =~ /^\.1\.3\.6\.1\.4\.1\.9\.6\.1/ );
 | ||
| 
 | ||
|         # HP, older ProCurve models (1600, 2400, 2424m, 4000, 8000)
 | ||
|         $objtype = 'SNMP::Info::Layer2::HP4000'
 | ||
|             if $desc =~ /\b(J4093A|J4110A|J4120A|J4121A|J4122A|J4122B)\b/;
 | ||
| 
 | ||
|         # HP, Foundry OEM
 | ||
|         $objtype = 'SNMP::Info::Layer3::HP9300'
 | ||
|             if $desc =~ /\b(J4874A|J4138A|J4139A|J4840A|J4841A)\b/;
 | ||
| 
 | ||
|         # IBM BladeCenter 4-Port GB Ethernet Switch Module
 | ||
|         $objtype = 'SNMP::Info::Layer3::Dell'
 | ||
|             if ( $desc =~ /^IBM Gigabit Ethernet Switch Module$/ );
 | ||
| 
 | ||
|         # Linksys 2024/2048
 | ||
|         $objtype = 'SNMP::Info::Layer3::Dell'
 | ||
|             if (
 | ||
|             $desc =~ /^(24|48)-Port 10\/100\/1000 Gigabit Switch (with |w\/)WebView$/ );
 | ||
| 
 | ||
|         #  Centillion ATM
 | ||
|         $objtype = 'SNMP::Info::Layer2::Centillion' if ( $desc =~ /MCP/ );
 | ||
| 
 | ||
|         #  BPS
 | ||
|         $objtype = 'SNMP::Info::Layer2::Baystack'
 | ||
|             if ( $desc =~ /Business\sPolicy\sSwitch/i );
 | ||
| 
 | ||
|         #  BayStack Numbered
 | ||
|         $objtype = 'SNMP::Info::Layer2::Baystack'
 | ||
|             if ( $desc
 | ||
|             =~ /^(BayStack|Ethernet\s+(Routing\s+)??Switch)\s[2345](\d){2,3}/i
 | ||
|             );
 | ||
| 
 | ||
|         # Kentrox DataSMART DSU/CSU
 | ||
|         $objtype = 'SNMP::Info::Layer2::Kentrox'
 | ||
|             if ( $desc =~ /^DataSMART/i );
 | ||
| 
 | ||
|         #  Nortel Business Ethernet Switch
 | ||
|         $objtype = 'SNMP::Info::Layer2::Baystack'
 | ||
|             if ( $desc =~ /^Business Ethernet Switch\s[12]\d\d/i );
 | ||
| 
 | ||
|         #  Nortel AP 222X
 | ||
|         $objtype = 'SNMP::Info::Layer2::NAP222x'
 | ||
|             if ( $desc =~ /Access\s+Point\s+222/ );
 | ||
| 
 | ||
|         #  Orinoco
 | ||
|         $objtype = 'SNMP::Info::Layer2::Orinoco'
 | ||
|             if ( $desc =~ /(AP-\d{3}|WavePOINT)/ );
 | ||
| 
 | ||
|         #  Aironet - IOS
 | ||
|         $objtype = 'SNMP::Info::Layer2::Aironet'
 | ||
|             if ($desc =~ /\b(C1100|C1130|C1140|AP1200|C350|C1200|C1240|C1250)\b/
 | ||
|             and $desc =~ /\bIOS\b/ );
 | ||
| 
 | ||
|         # Aironet - non IOS
 | ||
|         $objtype = 'SNMP::Info::Layer3::Aironet'
 | ||
|             if ( $desc =~ /Cisco/ and $desc =~ /\D(BR500)\D/ );
 | ||
| 
 | ||
|         # Airespace (WLC) Module
 | ||
|         $objtype = 'SNMP::Info::Layer2::Airespace'
 | ||
|             if ( $desc =~ /^Cisco Controller$/ );
 | ||
| 
 | ||
|         #Nortel 2270
 | ||
|         $objtype = 'SNMP::Info::Layer2::N2270'
 | ||
|             if (
 | ||
|             $desc =~ /Nortel\s+(Networks\s+)??WLAN\s+-\s+Security\s+Switch/ );
 | ||
| 
 | ||
|         # HP Virtual Connect blade switches
 | ||
|         $objtype = 'SNMP::Info::Layer2::HPVC'
 | ||
|             if ( $desc =~ /HP\sVC\s/ );
 | ||
| 
 | ||
|         $objtype = 'SNMP::Info::Layer2::ZyXEL_DSLAM'
 | ||
|             if ( $desc =~ /8-port .DSL Module\(Annex .\)/i );
 | ||
| 
 | ||
|         # Generic device classification based upon sysObjectID
 | ||
|         if (    ( $objtype eq 'SNMP::Info::Layer2' )
 | ||
|             and ( defined($id) )
 | ||
|             and ( exists( $l2sysoidmap{$id} ) ) )
 | ||
|         {
 | ||
|             $objtype = $l2sysoidmap{$id};
 | ||
|         }
 | ||
| 
 | ||
|     }
 | ||
|     elsif ( $info->has_layer(1) ) {
 | ||
|         $objtype = 'SNMP::Info::Layer1';
 | ||
| 
 | ||
|         #  Allied crap-o-hub
 | ||
|         $objtype = 'SNMP::Info::Layer1::Allied' if ( $desc =~ /allied/i );
 | ||
|         $objtype = 'SNMP::Info::Layer1::Asante' if ( $desc =~ /asante/i );
 | ||
| 
 | ||
|         #  Bay Hub
 | ||
|         $objtype = 'SNMP::Info::Layer1::Bayhub'
 | ||
|             if ( $desc =~ /\bNMM.*Agent/ );
 | ||
|         $objtype = 'SNMP::Info::Layer1::Bayhub'
 | ||
|             if ( $desc =~ /\bBay\s*Stack.*Hub/i );
 | ||
| 
 | ||
|         #  Synoptics Hub
 | ||
|         #  This will override Bay Hub only for specific devices supported
 | ||
|         #  by this class
 | ||
|         $objtype = 'SNMP::Info::Layer1::S3000'
 | ||
|             if ( $desc =~ /\bNMM\s+(281|3000|3030)/i );
 | ||
| 
 | ||
|         # Generic device classification based upon sysObjectID
 | ||
|         if (    ( $objtype eq 'SNMP::Info::Layer1' )
 | ||
|             and ( defined($id) )
 | ||
|             and ( exists( $l1sysoidmap{$id} ) ) )
 | ||
|         {
 | ||
|             $objtype = $l1sysoidmap{$id};
 | ||
|         }
 | ||
|     }
 | ||
|     # These devices don't claim to have Layer1-3 but we like em anyways.
 | ||
|     else {
 | ||
|         $objtype = 'SNMP::Info::Layer2::ZyXEL_DSLAM'
 | ||
|             if ( $desc =~ /8-port .DSL Module\(Annex .\)/i );
 | ||
| 
 | ||
|         # Aruba wireless switches
 | ||
|         $objtype = 'SNMP::Info::Layer3::Aruba'
 | ||
|             if ( $desc =~ /(ArubaOS|AirOS)/ );
 | ||
| 
 | ||
|         # Alcatel-Lucent branded Aruba
 | ||
|         $objtype = 'SNMP::Info::Layer3::Aruba'
 | ||
|             if ( $desc =~ /^AOS-W/ );
 | ||
| 
 | ||
|         # Cisco PIX
 | ||
|         $objtype = 'SNMP::Info::Layer3::Cisco'
 | ||
|             if ( $desc =~ /Cisco PIX Security Appliance/i );
 | ||
| 
 | ||
|         # Cisco ASA, older version which doesn't report layer 3 functionality
 | ||
|         $objtype = 'SNMP::Info::Layer3::CiscoASA'
 | ||
|             if ( $desc =~ /Cisco Adaptive Security Appliance/i );
 | ||
| 
 | ||
|         # HP Virtual Connect blade switches
 | ||
|         $objtype = 'SNMP::Info::Layer2::HPVC'
 | ||
|             if ( $desc =~ /HP\sVC\s/ );
 | ||
| 
 | ||
|         # Nortel (Trapeze) WSS 2300 Series
 | ||
|         $objtype = 'SNMP::Info::Layer2::NWSS2300'
 | ||
|             if (
 | ||
|             $desc =~ /^(Nortel\s)??Wireless\sSecurity\sSwitch\s23[568][012]\b/);
 | ||
| 
 | ||
|         # Cisco IPS, older version which doesn't report layer 3 functionality
 | ||
|         $objtype = 'SNMP::Info::Layer7::CiscoIPS'
 | ||
|             if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.9\.1\.1545/i );
 | ||
| 
 | ||
|         # Generic device classification based upon sysObjectID
 | ||
|         if ( defined($id) and $objtype eq 'SNMP::Info') {
 | ||
|             if ( defined $l3sysoidmap{$id} ) {
 | ||
|                 $objtype = $l3sysoidmap{$id};
 | ||
|             } elsif ( defined $l2sysoidmap{$id}) {
 | ||
|                 $objtype = $l2sysoidmap{$id};
 | ||
|             } elsif ( defined $l7sysoidmap{$id}) {
 | ||
|                 $objtype = $l7sysoidmap{$id};
 | ||
|             } elsif ($info->has_layer(7)) {
 | ||
|                 $objtype = 'SNMP::Info::Layer7'
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     return $objtype;
 | ||
| }
 | ||
| 
 | ||
| =item $info->error(no_clear)
 | ||
| 
 | ||
| Returns Error message if there is an error, or undef if there is not.
 | ||
| 
 | ||
| Reading the error will clear the error unless you set the no_clear flag.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub error {
 | ||
|     my $self     = shift;
 | ||
|     my $no_clear = shift;
 | ||
|     my $err      = $self->{error};
 | ||
| 
 | ||
|     $self->{error} = undef unless defined $no_clear and $no_clear;
 | ||
|     return $err;
 | ||
| }
 | ||
| 
 | ||
| =item $info->has_layer(3)
 | ||
| 
 | ||
| Returns non-zero if the device has the supplied layer in the OSI Model
 | ||
| 
 | ||
| Returns if the device doesn't support the layers() call.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub has_layer {
 | ||
|     my $self      = shift;
 | ||
|     my $check_for = shift;
 | ||
| 
 | ||
|     my $layers = $self->layers();
 | ||
|     return unless defined $layers;
 | ||
|     return unless length($layers);
 | ||
|     return substr( $layers, 8 - $check_for, 1 );
 | ||
| }
 | ||
| 
 | ||
| =item $info->snmp_comm()
 | ||
| 
 | ||
| Returns SNMP Community string used in connection.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub snmp_comm {
 | ||
|     my $self = shift;
 | ||
|     if ( $self->{snmp_ver} == 3 ) {
 | ||
|         return $self->{snmp_user};
 | ||
|     }
 | ||
|     else {
 | ||
|         return $self->{snmp_comm};
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->snmp_ver()
 | ||
| 
 | ||
| Returns SNMP Version used for this connection
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub snmp_ver {
 | ||
|     my $self = shift;
 | ||
|     return $self->{snmp_ver};
 | ||
| }
 | ||
| 
 | ||
| =item $info->specify()
 | ||
| 
 | ||
| Returns an object of a more-specific subclass.
 | ||
| 
 | ||
|  my $info = new SNMP::Info(...);
 | ||
|  # Returns more specific object type
 | ||
|  $info = $info->specific();
 | ||
| 
 | ||
| Usually this method is called internally from new(AutoSpecify => 1)
 | ||
| 
 | ||
| See device_type() entry for how a subclass is chosen.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub specify {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     my $device_type = $self->device_type();
 | ||
|     unless ( defined $device_type ) {
 | ||
|         $self->error_throw(
 | ||
|             "SNMP::Info::specify() - Could not get info from device");
 | ||
|         return;
 | ||
|     }
 | ||
|     return $self if $device_type eq 'SNMP::Info';
 | ||
| 
 | ||
|     # Load Subclass
 | ||
|     # By evaling a string the contents of device_type now becomes a bareword.
 | ||
|     eval "require $device_type;";    ## no critic
 | ||
|     if ($@) {
 | ||
|         croak "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,
 | ||
|         'AutoSpecify' => 0
 | ||
|     );
 | ||
| 
 | ||
|     unless ( defined $sub_obj ) {
 | ||
|         $self->error_throw(
 | ||
|             "SNMP::Info::specify() - Could not connect with new class ($device_type)"
 | ||
|         );
 | ||
|         return $self;
 | ||
|     }
 | ||
| 
 | ||
|     $self->debug()
 | ||
|         and print "SNMP::Info::specify() - Changed Class to $device_type.\n";
 | ||
|     return $sub_obj;
 | ||
| }
 | ||
| 
 | ||
| =item $info->cisco_comm_indexing()
 | ||
| 
 | ||
| Returns 0.  Is an overridable method used for vlan indexing for
 | ||
| snmp calls on certain Cisco devices.
 | ||
| 
 | ||
| See L<ftp://ftp.cisco.com/pub/mibs/supportlists/wsc5000/wsc5000-communityIndexing.html>
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub cisco_comm_indexing {
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Globals (Scalar Methods)
 | ||
| 
 | ||
| These are methods to return scalar data from RFC1213.
 | ||
| 
 | ||
| Some subset of these is probably available for any network device that speaks
 | ||
| SNMP.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->uptime()
 | ||
| 
 | ||
| Uptime in hundredths of seconds since device became available.
 | ||
| 
 | ||
| (C<sysUpTime>)
 | ||
| 
 | ||
| =item $info->contact()
 | ||
| 
 | ||
| (C<sysContact>)
 | ||
| 
 | ||
| =item $info->name()
 | ||
| 
 | ||
| (C<sysName>)
 | ||
| 
 | ||
| =item $info->location()
 | ||
| 
 | ||
| (C<sysLocation>)
 | ||
| 
 | ||
| =item $info->layers()
 | ||
| 
 | ||
| This returns a binary encoded string where each
 | ||
| digit represents a layer of the OSI model served
 | ||
| by the device.
 | ||
| 
 | ||
|     eg: 01000010  means layers 2 (physical) and 7 (Application)
 | ||
|                   are served.
 | ||
| 
 | ||
| Note:  This string is 8 digits long.
 | ||
| 
 | ||
| See $info->has_layer()
 | ||
| 
 | ||
| (C<sysServices>)
 | ||
| 
 | ||
| =item $info->ports()
 | ||
| 
 | ||
| Number of interfaces available on this device.
 | ||
| 
 | ||
| Not too useful as the number of SNMP interfaces usually does not
 | ||
| correspond with the number of physical ports
 | ||
| 
 | ||
| (C<ifNumber>)
 | ||
| 
 | ||
| =item $info->ipforwarding()
 | ||
| 
 | ||
| The indication of whether the entity is acting as an IP gateway
 | ||
| 
 | ||
| Returns either forwarding or not-forwarding
 | ||
| 
 | ||
| (C<ipForwarding>)
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Table Methods
 | ||
| 
 | ||
| Each of these methods returns a hash_reference to a hash keyed on the
 | ||
| interface index in SNMP.
 | ||
| 
 | ||
| Example : $info->interfaces() might return
 | ||
| 
 | ||
|     { '1.12' => 'FastEthernet/0',
 | ||
|       '2.15' => 'FastEthernet/1',
 | ||
|       '9.99' => 'FastEthernet/2'
 | ||
|     }
 | ||
| 
 | ||
| The key is what you would see if you were to do an snmpwalk, and in some cases
 | ||
| changes between reboots of the network device.
 | ||
| 
 | ||
| =head2 Partial Table Fetches
 | ||
| 
 | ||
| If you want to get only a part of an SNMP table or a single instance from the
 | ||
| table and you know the IID for the part of the table that you want, you can
 | ||
| specify it in the call:
 | ||
| 
 | ||
|     $local_routes = $info->ipr_route('192.168.0');
 | ||
| 
 | ||
| This will only fetch entries in the table that start with C<192.168.0>, which
 | ||
| in this case are routes on the local network.
 | ||
| 
 | ||
| Remember that you must supply the partial IID (a numeric OID).
 | ||
| 
 | ||
| Partial table results are not cached.
 | ||
| 
 | ||
| =head2 Interface Information
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->interfaces()
 | ||
| 
 | ||
| This methods is overridden in each subclass to provide a
 | ||
| mapping between the Interface Table Index (iid) and the physical port name.
 | ||
| 
 | ||
| =item $info->if_ignore()
 | ||
| 
 | ||
| Returns a reference to a hash where key values that exist are
 | ||
| interfaces to ignore.
 | ||
| 
 | ||
| Ignored interfaces are ones that are usually not physical ports or Virtual
 | ||
| Lans (VLANs) such as the Loopback interface, or the CPU interface.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub if_ignore {
 | ||
|     my %nothing;
 | ||
|     return \%nothing;
 | ||
| }
 | ||
| 
 | ||
| =item $info->bulkwalk_no()
 | ||
| 
 | ||
| Returns 0.  Is an overridable method used for turn off bulkwalk for the
 | ||
| device class.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub bulkwalk_no {
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| =item $info->i_index()
 | ||
| 
 | ||
| Default SNMP IID to Interface index.
 | ||
| 
 | ||
| (C<ifIndex>)
 | ||
| 
 | ||
| =item $info->i_description()
 | ||
| 
 | ||
| Description of the interface. Usually a little longer single word name that is
 | ||
| both human and machine friendly.  Not always.
 | ||
| 
 | ||
| (C<ifDescr>)
 | ||
| 
 | ||
| =item $info->i_type()
 | ||
| 
 | ||
| Interface type, such as Vlan, Ethernet, Serial
 | ||
| 
 | ||
| (C<ifType>)
 | ||
| 
 | ||
| =item $info->i_mtu()
 | ||
| 
 | ||
| INTEGER. Interface MTU value.
 | ||
| 
 | ||
| (C<ifMtu>)
 | ||
| 
 | ||
| =item $info->i_speed()
 | ||
| 
 | ||
| Speed of the link, human format.  See munge_speed() later in document for
 | ||
| details.
 | ||
| 
 | ||
| (C<ifSpeed>, C<ifHighSpeed> if necessary)
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub i_speed {
 | ||
|     my $info    = shift;
 | ||
|     my $partial = shift;
 | ||
| 
 | ||
|     my $i_speed = $info->orig_i_speed($partial);
 | ||
| 
 | ||
|     my $i_speed_high = undef;
 | ||
|     foreach my $i ( keys %$i_speed ) {
 | ||
|         if ( $i_speed->{$i} eq "4294967295" ) {
 | ||
|             $i_speed_high = $info->i_speed_high($partial)
 | ||
|                 unless defined($i_speed_high);
 | ||
|             $i_speed->{$i} = $i_speed_high->{$i} if ( $i_speed_high->{$i} );
 | ||
|         }
 | ||
|     }
 | ||
|     return $i_speed;
 | ||
| }
 | ||
| 
 | ||
| =item $info->i_speed_raw()
 | ||
| 
 | ||
| Speed of the link in bits per second without munging.
 | ||
| If i_speed_high is available it will be used and multiplied by 1_000_000.
 | ||
| 
 | ||
| (C<ifSpeed>, C<ifHighSpeed> if necessary)
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub i_speed_raw {
 | ||
|     my $info    = shift;
 | ||
|     my $partial = shift;
 | ||
| 
 | ||
|     # remove the speed formating
 | ||
|     my $munge_i_speed = delete $info->{munge}{i_speed};
 | ||
|     # also for highspeed interfaces e.g. TenGigabitEthernet
 | ||
|     my $munge_i_speed_high = delete $info->{munge}{i_speed_high};
 | ||
| 
 | ||
|     my $i_speed_raw = $info->orig_i_speed($partial);
 | ||
| 
 | ||
|     my $i_speed_high = undef;
 | ||
|     foreach my $i ( keys %$i_speed_raw ) {
 | ||
|         if ( $i_speed_raw->{$i} eq "4294967295" ) {
 | ||
|             $i_speed_high = $info->i_speed_high($partial)
 | ||
|                 unless defined($i_speed_high);
 | ||
|             $i_speed_raw->{$i} = ( $i_speed_high->{$i} * 1_000_000 )
 | ||
|                 if ( $i_speed_high->{$i} );
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     # restore the speed formating
 | ||
|     $info->{munge}{i_speed} = $munge_i_speed;
 | ||
|     $info->{munge}{i_speed_high} = $munge_i_speed_high;
 | ||
| 
 | ||
|     return $i_speed_raw;
 | ||
| }
 | ||
| 
 | ||
| =item $info->i_speed_high()
 | ||
| 
 | ||
| Speed of a high-speed link, human format.  See munge_highspeed() later in
 | ||
| document for details.  You should not need to call this directly, as
 | ||
| i_speed() will call it if it needs to.
 | ||
| 
 | ||
| (C<ifHighSpeed>)
 | ||
| 
 | ||
| =item $info->i_mac()
 | ||
| 
 | ||
| MAC address of the interface.  Note this is just the MAC of the port, not
 | ||
| anything connected to it.
 | ||
| 
 | ||
| (C<ifPhysAddress>)
 | ||
| 
 | ||
| =item $info->i_up()
 | ||
| 
 | ||
| Link Status of the interface.  Typical values are 'up' and 'down'.
 | ||
| 
 | ||
| (C<ifOperStatus>)
 | ||
| 
 | ||
| =item $info->i_up_admin()
 | ||
| 
 | ||
| Administrative status of the port.  Typical values are 'enabled' and 'disabled'.
 | ||
| 
 | ||
| (C<ifAdminStatus>)
 | ||
| 
 | ||
| =item $info->i_lastchange()
 | ||
| 
 | ||
| The value of C<sysUpTime> when this port last changed states (up,down).
 | ||
| 
 | ||
| (C<ifLastChange>)
 | ||
| 
 | ||
| =item $info->i_name()
 | ||
| 
 | ||
| Interface Name field.  Supported by a smaller subset of devices, this fields
 | ||
| is often human set.
 | ||
| 
 | ||
| (C<ifName>)
 | ||
| 
 | ||
| =item $info->i_alias()
 | ||
| 
 | ||
| Interface Name field.  For certain devices this is a more human friendly form
 | ||
| of i_description().  For others it is a human set field like i_name().
 | ||
| 
 | ||
| (C<ifAlias>)
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 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.
 | ||
| 
 | ||
| 
 | ||
| (C<ifInOctets>) (C<ifOutOctets>)
 | ||
| (C<ifHCInOctets>) (C<ifHCOutOctets>)
 | ||
| 
 | ||
| =item $info->i_errors_in(), $info->i_errors_out()
 | ||
| 
 | ||
| Number of packets that contained an error preventing delivery.  See C<IF-MIB>
 | ||
| for more info.
 | ||
| 
 | ||
| (C<ifInErrors>) (C<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.
 | ||
| 
 | ||
| (C<ifInUcastPkts>) (C<ifOutUcastPkts>)
 | ||
| (C<ifHCInUcastPkts>) (C<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 deprecated by i_pkts_multi_in() and i_pkts_bcast_in()
 | ||
| according to C<IF-MIB>.  Actual device usage may vary.
 | ||
| 
 | ||
| (C<ifInNUcastPkts>) (C<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.
 | ||
| 
 | ||
| (C<ifInMulticastPkts>) (C<ifOutMulticastPkts>)
 | ||
| (C<ifHCInMulticastPkts>) (C<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.
 | ||
| 
 | ||
| (C<ifInBroadcastPkts>) (C<ifOutBroadcastPkts>)
 | ||
| (C<ifHCInBroadcastPkts>) (C<ifHCOutBroadcastPkts>)
 | ||
| 
 | ||
| =item $info->i_discards_in() $info->i_discards_out()
 | ||
| 
 | ||
| "The number of inbound packets which were chosen to be discarded even though
 | ||
| no errors had been detected to prevent their being deliverable to a
 | ||
| higher-layer protocol.  One possible reason for discarding such a packet could
 | ||
| be to free up buffer space."  (C<IF-MIB>)
 | ||
| 
 | ||
| (C<ifInDiscards>) (C<ifOutDiscards>)
 | ||
| 
 | ||
| =item $info->i_bad_proto_in()
 | ||
| 
 | ||
| "For packet-oriented interfaces, the number of packets received via the
 | ||
| interface which were discarded because of an unknown or unsupported protocol.
 | ||
| For character-oriented or fixed-length interfaces that support protocol
 | ||
| multiplexing the number of transmission units received via the interface which
 | ||
| were discarded because of an unknown or unsupported protocol.  For any
 | ||
| interface that does not support protocol multiplexing, this counter will always
 | ||
| be 0."
 | ||
| 
 | ||
| (C<ifInUnknownProtos>)
 | ||
| 
 | ||
| =item $info->i_qlen_out()
 | ||
| 
 | ||
| "The length of the output packet queue (in packets)."
 | ||
| 
 | ||
| (C<ifOutQLen>)
 | ||
| 
 | ||
| =item $info->i_specific()
 | ||
| 
 | ||
| See C<IF-MIB> for full description
 | ||
| 
 | ||
| (C<ifSpecific>)
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 IPv4 Address Table
 | ||
| 
 | ||
| Each entry in this table is an IPv4 address in use on this device.  Usually
 | ||
| this is implemented in Layer3 Devices. These methods try the deprecated IPv4
 | ||
| address table C<IP-MIB::ipAddrTable> first due to its prevalence and will try
 | ||
| the current C<IP-MIB::ipAddressTable> if it doesn't return any results.
 | ||
| C<IP-MIB::ipAddressTable> results are filtered to only return IPv4 unicast
 | ||
| addresses and modified to match the return format of the older table for
 | ||
| backwards compatibility.
 | ||
| 
 | ||
| See documentation in L<SNMP::Info::IPv6> for IPv6 Address Table.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->ip_index()
 | ||
| 
 | ||
| Maps the IPv4 addresses to the interface index
 | ||
| 
 | ||
| (C<ipAdEntIfIndex>) or filtered and index modified (C<ipAddressIfIndex>) 
 | ||
| 
 | ||
| =item $info->ip_table()
 | ||
| 
 | ||
| Maps the Table to the IPv4 address
 | ||
| 
 | ||
| (C<ipAdEntAddr>) or address extracted from (C<ipAddressIfIndex>) 
 | ||
| 
 | ||
| =item $info->ip_netmask()
 | ||
| 
 | ||
| Gives netmask setting for IPv4 table entry.
 | ||
| 
 | ||
| (C<ipAdEntNetMask>) or netmask calculated from (C<ipAddressPrefix>)
 | ||
| 
 | ||
| =item $info->ip_broadcast()
 | ||
| 
 | ||
| Gives the value of the least-significant bit in the IPv4 broadcast address
 | ||
| either 1 or 0.
 | ||
| 
 | ||
| (C<ipAdEntBcastAddr>), there is no equivalent from the
 | ||
| C<IP-MIB::ipAddressTable>
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 IP Routing Table
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->ipr_route()
 | ||
| 
 | ||
| The route in question.  A value of 0.0.0.0 is the default gateway route.
 | ||
| 
 | ||
| (C<ipRouteDest>)
 | ||
| 
 | ||
| =item $info->ipr_if()
 | ||
| 
 | ||
| The interface (IID) that the route is on.  Use interfaces() to map.
 | ||
| 
 | ||
| (C<ipRouteIfIndex>)
 | ||
| 
 | ||
| =item $info->ipr_1()
 | ||
| 
 | ||
| Primary routing metric for this route.
 | ||
| 
 | ||
| (C<ipRouteMetric1>)
 | ||
| 
 | ||
| =item $info->ipr_2()
 | ||
| 
 | ||
| If metrics are not used, they should be set to -1
 | ||
| 
 | ||
| (C<ipRouteMetric2>)
 | ||
| 
 | ||
| =item $info->ipr_3()
 | ||
| 
 | ||
| (C<ipRouteMetric3>)
 | ||
| 
 | ||
| =item $info->ipr_4()
 | ||
| 
 | ||
| (C<ipRouteMetric4>)
 | ||
| 
 | ||
| =item $info->ipr_5()
 | ||
| 
 | ||
| (C<ipRouteMetric5>)
 | ||
| 
 | ||
| =item $info->ipr_dest()
 | ||
| 
 | ||
| From RFC1213:
 | ||
| 
 | ||
|   "The IP address of the next hop of this route.
 | ||
|   (In the case of a route bound to an interface
 | ||
|   which is realized via a broadcast media, the value
 | ||
|   of this field is the agent's IP address on that
 | ||
|   interface.)"
 | ||
| 
 | ||
| (C<ipRouteNextHop>)
 | ||
| 
 | ||
| =item $info->ipr_type()
 | ||
| 
 | ||
| From RFC1213:
 | ||
| 
 | ||
|     other(1),        -- none of the following
 | ||
|     invalid(2),      -- an invalidated route
 | ||
|                      -- route to directly
 | ||
|     direct(3),       -- connected (sub-)network
 | ||
|                      -- route to a non-local
 | ||
|     indirect(4)      -- host/network/sub-network
 | ||
| 
 | ||
| 
 | ||
|       "The type of route.  Note that the values
 | ||
|       direct(3) and indirect(4) refer to the notion of
 | ||
|       direct and indirect routing in the IP
 | ||
|       architecture.
 | ||
| 
 | ||
|       Setting this object to the value invalid(2) has
 | ||
|       the effect of invalidating the corresponding entry
 | ||
|       in the ipRouteTable object.  That is, it
 | ||
|       effectively disassociates the destination
 | ||
|       identified with said entry from the route
 | ||
|       identified with said entry.  It is an
 | ||
|       implementation-specific matter as to whether the
 | ||
|       agent removes an invalidated entry from the table.
 | ||
|       Accordingly, management stations must be prepared
 | ||
|       to receive tabular information from agents that
 | ||
|       corresponds to entries not currently in use.
 | ||
|       Proper interpretation of such entries requires
 | ||
|       examination of the relevant ipRouteType object."
 | ||
| 
 | ||
| (C<ipRouteType>)
 | ||
| 
 | ||
| =item $info->ipr_proto()
 | ||
| 
 | ||
| From RFC1213:
 | ||
| 
 | ||
|     other(1),       -- none of the following
 | ||
|                     -- non-protocol information,
 | ||
|                     -- e.g., manually configured
 | ||
|     local(2),       -- entries
 | ||
|                     -- set via a network
 | ||
|     netmgmt(3),     -- management protocol
 | ||
|                     -- obtained via ICMP,
 | ||
|     icmp(4),        -- e.g., Redirect
 | ||
|                     -- the remaining values are
 | ||
|                     -- all gateway routing
 | ||
|                     -- protocols
 | ||
|     egp(5),
 | ||
|     ggp(6),
 | ||
|     hello(7),
 | ||
|     rip(8),
 | ||
|     is-is(9),
 | ||
|     es-is(10),
 | ||
|     ciscoIgrp(11),
 | ||
|     bbnSpfIgp(12),
 | ||
|     ospf(13),
 | ||
|     bgp(14)
 | ||
| 
 | ||
| (C<ipRouteProto>)
 | ||
| 
 | ||
| =item $info->ipr_age()
 | ||
| 
 | ||
| Seconds since route was last updated or validated.
 | ||
| 
 | ||
| (C<ipRouteAge>)
 | ||
| 
 | ||
| =item $info->ipr_mask()
 | ||
| 
 | ||
| Subnet Mask of route. 0.0.0.0 for default gateway.
 | ||
| 
 | ||
| (C<ipRouteMask>)
 | ||
| 
 | ||
| =item $info->ipr_info()
 | ||
| 
 | ||
| Reference to MIB definition specific to routing protocol.
 | ||
| 
 | ||
| (C<ipRouteInfo>)
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Topology Information
 | ||
| 
 | ||
| Based upon the manufacturer and software version devices may support some
 | ||
| combination of Layer 2 topology protocol information.  SNMP::Info
 | ||
| supports querying Link Layer Discovery Protocol (LLDP), Cisco Discovery
 | ||
| Protocol (CDP), SynOptics/Bay/Nortel/Avaya Network Management Protocol
 | ||
| (SONMP), Foundry/Brocade Discovery Protocol (FDP), Extreme Discovery
 | ||
| Protocol (EDP), and Alcatel Mapping Adjacency Protocol (AMAP).
 | ||
| 
 | ||
| For protocol specific information and implementation:
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item LLDP: See L<SNMP::Info::LLDP> for details.
 | ||
| 
 | ||
| =item CDP: See L<SNMP::Info::CDP> for details.
 | ||
| 
 | ||
| =item SONMP: See L<SNMP::Info::SONMP> for details.
 | ||
| 
 | ||
| =item FDP: See L<SNMP::Info::FDP> for details.
 | ||
| 
 | ||
| =item EDP: See L<SNMP::Info::EDP> for details.
 | ||
| 
 | ||
| =item AMAP: See L<SNMP::Info::AMAP> for details.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head3 Topology Capabilities
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->has_topo()
 | ||
| 
 | ||
| Reports Layer 2 topology protocols which are supported and running on
 | ||
| a device.
 | ||
| 
 | ||
| Returns either a reference to an array of protocols, possible values
 | ||
| being: C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>, C<amap> or C<undef> if
 | ||
| no protocols are supported or running.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub ip_index {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     my $o_ip_idx = $self->old_ip_index();
 | ||
|     return $o_ip_idx
 | ||
|         if ( ref {} eq ref $o_ip_idx and scalar keys %$o_ip_idx );
 | ||
| 
 | ||
|     # Since callers may be using the old iid to get the IP, strip protocol
 | ||
|     # and length from the index
 | ||
|     my $n_ip_idx  = $self->new_ip_index() || {};
 | ||
|     my $n_ip_type = $self->new_ip_type()  || {};
 | ||
| 
 | ||
|     my %ip_index;
 | ||
|     foreach my $iid ( keys %$n_ip_idx ) {
 | ||
|         next unless $n_ip_type->{$iid} and $n_ip_type->{$iid} eq 'unicast';
 | ||
|         my @parts = split( /\./, $iid );
 | ||
|         my $type  = shift(@parts);
 | ||
|         my $len   = shift(@parts);
 | ||
|         next unless ( ( $type == 1 ) and ( $len == 4 ) );
 | ||
| 
 | ||
|         my $new_iid = join( ".", @parts );
 | ||
|         $ip_index{$new_iid} = $n_ip_idx->{$iid};
 | ||
|     }
 | ||
|     return \%ip_index;
 | ||
| }
 | ||
| 
 | ||
| sub ip_table {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     my $o_ip_table = $self->old_ip_table();
 | ||
|     return $o_ip_table
 | ||
|         if ( ref {} eq ref $o_ip_table and scalar keys %$o_ip_table );
 | ||
| 
 | ||
|     my $n_ip_idx  = $self->new_ip_index() || {};
 | ||
|     my $n_ip_type = $self->new_ip_type()  || {};
 | ||
| 
 | ||
|     my %ip_table;
 | ||
|     foreach my $iid ( keys %$n_ip_idx ) {
 | ||
|         next unless $n_ip_type->{$iid} and $n_ip_type->{$iid} eq 'unicast';
 | ||
|         my @parts = split( /\./, $iid );
 | ||
|         my $type  = shift(@parts);
 | ||
|         my $len   = shift(@parts);
 | ||
|         next unless ( ( $type == 1 ) and ( $len == 4 ) );
 | ||
| 
 | ||
|         my $new_iid = join( ".", @parts );
 | ||
|         $ip_table{$new_iid} = $new_iid;
 | ||
|     }
 | ||
|     return \%ip_table;
 | ||
| }
 | ||
| 
 | ||
| sub ip_netmask {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     my $o_ip_mask = $self->old_ip_netmask();
 | ||
|     return $o_ip_mask
 | ||
|         if ( ref {} eq ref $o_ip_mask and scalar keys %$o_ip_mask );
 | ||
| 
 | ||
|     my $n_ip_pfx  = $self->new_ip_prefix() || {};
 | ||
|     my $n_ip_type = $self->new_ip_type()   || {};
 | ||
| 
 | ||
|     my %ip_netmask;
 | ||
|     foreach my $iid ( keys %$n_ip_pfx ) {
 | ||
|         next unless $n_ip_type->{$iid} and $n_ip_type->{$iid} eq 'unicast';
 | ||
|         my @parts = split( /\./, $iid );
 | ||
|         my $type  = shift(@parts);
 | ||
|         my $len   = shift(@parts);
 | ||
|         next unless ( ( $type == 1 ) and ( $len == 4 ) );
 | ||
| 
 | ||
|         my $prefix = $n_ip_pfx->{$iid};
 | ||
|         next if ( !$prefix || $prefix =~ /0\.0$/ );
 | ||
|         if ( $prefix =~ /\.(\d+)$/ ) {
 | ||
|             $prefix = $1;
 | ||
|         }
 | ||
|         my $new_iid = join( ".", @parts );
 | ||
|         my $mask = NetAddr::IP::Lite->new( $new_iid . '/' . $prefix )->mask()
 | ||
|             || undef;
 | ||
| 
 | ||
|         $ip_netmask{$new_iid} = $mask;
 | ||
|     }
 | ||
|     return \%ip_netmask;
 | ||
| }
 | ||
| 
 | ||
| sub has_topo {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     my @topo_cap;
 | ||
|     push( @topo_cap, 'lldp' )
 | ||
|         if ( $self->can('hasLLDP') && $self->hasLLDP() );
 | ||
|     push( @topo_cap, 'cdp' ) if $self->can('hasCDP') && $self->hasCDP();
 | ||
|     push( @topo_cap, 'sonmp' )
 | ||
|         if $self->can('hasSONMP') && $self->hasSONMP();
 | ||
|     push( @topo_cap, 'fdp' ) if $self->can('hasFDP') && $self->hasFDP();
 | ||
|     push( @topo_cap, 'edp' ) if $self->can('hasEDP') && $self->hasEDP();
 | ||
|     push( @topo_cap, 'amap' ) if $self->can('hasAMAP') && $self->hasAMAP();
 | ||
| 
 | ||
|     if (@topo_cap) {
 | ||
|         return \@topo_cap;
 | ||
|     }
 | ||
|     else {
 | ||
|         return;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| sub _get_topo_data {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
|     my $method   = shift || '';
 | ||
| 
 | ||
|     return unless $method =~ /(ip|if|port|id|platform|cap)/;
 | ||
| 
 | ||
|     my %t_data;
 | ||
|     foreach my $proto (@$topo_cap) {
 | ||
|         next unless $proto =~ /(lldp|cdp|sonmp|fdp|edp|amap)/;
 | ||
|         my $method_name = "$proto" . "_$method";
 | ||
|         my $cdp = $self->$method_name($partial) || {};
 | ||
| 
 | ||
|         foreach my $iid ( keys %$cdp ) {
 | ||
|             my $ip = $cdp->{$iid};
 | ||
|             next unless defined $ip;
 | ||
| 
 | ||
|             $t_data{$iid} = $ip;
 | ||
|         }
 | ||
|     }
 | ||
|     return \%t_data;
 | ||
| }
 | ||
| 
 | ||
| =head3 Common Topology Table Information
 | ||
| 
 | ||
| The common topology table methods below will query the
 | ||
| device for information from the specified topology protocols and return a
 | ||
| single hash combining all information. As a result, there may be identical
 | ||
| topology information returned from the two protocols causing duplicate
 | ||
| entries.  It is the calling program's responsibility to identify any
 | ||
| duplicate entries and remove duplicates if necessary.  If it is necessary
 | ||
| to understand which protocol provided the information, utilize the protocol
 | ||
| specific methods directly rather than the generic methods.
 | ||
| 
 | ||
| The methods support partial table fetches by providing a partial as the
 | ||
| first argument.
 | ||
| 
 | ||
| If a reference to an array is provided as the second argument, those
 | ||
| protocols will be queried for information.  The supported array values are:
 | ||
| C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>, C<amap>.
 | ||
| 
 | ||
| If nothing is passed in as the second argument, the methods will call
 | ||
| has_topo() to determine supported and running topology protocols on the
 | ||
| device.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->c_ip(partial, topology_protocol_arrayref)
 | ||
| 
 | ||
| Returns reference to hash.  Key: iid, Value: remote IPv4 address
 | ||
| 
 | ||
| If multiple entries exist with the same local port, c_if(), with the
 | ||
| same IPv4 address, c_ip(), it may be a duplicate entry.
 | ||
| 
 | ||
| If multiple entries exist with the same local port, c_if(), with different
 | ||
| IPv4 addresses, c_ip(), there is either a device in between two or
 | ||
| more devices utilizing a different topology protocol or multiple devices
 | ||
| which are not directly connected.
 | ||
| 
 | ||
| Use the protocol specific methods to dig deeper.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub c_ip {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
| 
 | ||
|     # Default to old behavior if not called with topo_cap
 | ||
|     if ( !$topo_cap ) {
 | ||
|         my $topo_test = $self->has_topo();
 | ||
|         if ($topo_test) {
 | ||
|             $topo_cap = $topo_test;
 | ||
|         }
 | ||
|         else {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
|     return _get_topo_data ($self, $partial, $topo_cap, 'ip');
 | ||
| }
 | ||
| 
 | ||
| =item $info->c_if(partial, topology_protocol_arrayref)
 | ||
| 
 | ||
| Returns reference to hash.  Key: iid, Value: local device port (interfaces)
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub c_if {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
| 
 | ||
|     # Default to old behavior if not called with topo_cap
 | ||
|     if ( !$topo_cap ) {
 | ||
|         my $topo_test = $self->has_topo();
 | ||
|         if ($topo_test) {
 | ||
|             $topo_cap = $topo_test;
 | ||
|         }
 | ||
|         else {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
|     return _get_topo_data ($self, $partial, $topo_cap, 'if');
 | ||
| }
 | ||
| 
 | ||
| =item $info->c_port(partial, topology_protocol_arrayref)
 | ||
| 
 | ||
| Returns reference to hash. Key: iid, Value: remote port (interfaces)
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub c_port {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
| 
 | ||
|     # Default to old behavior if not called with topo_cap
 | ||
|     if ( !$topo_cap ) {
 | ||
|         my $topo_test = $self->has_topo();
 | ||
|         if ($topo_test) {
 | ||
|             $topo_cap = $topo_test;
 | ||
|         }
 | ||
|         else {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
|     return _get_topo_data ($self, $partial, $topo_cap, 'port');
 | ||
| }
 | ||
| 
 | ||
| =item $info->c_id(partial, topology_protocol_arrayref)
 | ||
| 
 | ||
| Returns reference to hash. Key: iid, Value: string value used to identify the
 | ||
| chassis component associated with the remote system.
 | ||
| 
 | ||
| Note: SONMP does not return this information.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub c_id {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
| 
 | ||
|     # Default to old behavior if not called with topo_cap
 | ||
|     if ( !$topo_cap ) {
 | ||
|         my $topo_test = $self->has_topo();
 | ||
|         if ($topo_test) {
 | ||
|             $topo_cap = $topo_test;
 | ||
|         }
 | ||
|         else {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
|     return _get_topo_data ($self, $partial, $topo_cap, 'id');
 | ||
| }
 | ||
| 
 | ||
| =item $info->c_platform(partial, topology_protocol_arrayref)
 | ||
| 
 | ||
| Returns reference to hash.  Key: iid, Value: Remote Device Type
 | ||
| 
 | ||
| Note:  EDP does not provide this information.  LLDP uses (C<lldpRemSysDesc>)
 | ||
| or C<lldp_rem_sysname> as the closest match.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub c_platform {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
| 
 | ||
|     # Default to old behavior if not called with topo_cap
 | ||
|     if ( !$topo_cap ) {
 | ||
|         my $topo_test = $self->has_topo();
 | ||
|         if ($topo_test) {
 | ||
|             $topo_cap = $topo_test;
 | ||
|         }
 | ||
|         else {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
|     return _get_topo_data ($self, $partial, $topo_cap, 'platform');
 | ||
| }
 | ||
| 
 | ||
| =item $info->c_cap(partial, topology_protocol_arrayref)
 | ||
| 
 | ||
| Returns reference to hash of arrays.  Key: iid, Value: Array of capabilities
 | ||
| supported by the device.  See the specific protocol class for string values
 | ||
| which could be elements within the array.
 | ||
| 
 | ||
| Note:  Only CDP and LLDP support this method.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub c_cap {
 | ||
|     my $self     = shift;
 | ||
|     my $partial  = shift;
 | ||
|     my $topo_cap = shift;
 | ||
| 
 | ||
|     # Default to old behavior if not called with topo_cap
 | ||
|     if ( !$topo_cap ) {
 | ||
|         my $topo_test = $self->has_topo();
 | ||
|         if ($topo_test) {
 | ||
|             $topo_cap = $topo_test;
 | ||
|         }
 | ||
|         else {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
|     return _get_topo_data ($self, $partial, $topo_cap, 'cap');
 | ||
| }
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head1 SETTING DATA VIA SNMP
 | ||
| 
 | ||
| This section explains how to use SNMP::Info to do SNMP Set operations.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $info->set_METHOD($value)
 | ||
| 
 | ||
| Sets the global METHOD to value.  Assumes that iid is .0
 | ||
| 
 | ||
| Returns if failed, or the return value from SNMP::Session::set() (snmp_errno)
 | ||
| 
 | ||
|  $info->set_location("Here!");
 | ||
| 
 | ||
| =item $info->set_METHOD($value,$iid)
 | ||
| 
 | ||
| Table Methods. Set iid of method to value.
 | ||
| 
 | ||
| Returns if failed, or the return value from SNMP::Session::set() (snmp_errno)
 | ||
| 
 | ||
|  # Disable a port administratively
 | ||
|  my %if_map = reverse %{$info->interfaces()}
 | ||
|  $info->set_i_up_admin('down', $if_map{'FastEthernet0/0'})
 | ||
|     or die "Couldn't disable the port. ",$info->error(1);
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| NOTE: You must be connected to your device with a C<ReadWrite> community
 | ||
| string in order for set operations to work.
 | ||
| 
 | ||
| NOTE: This will only set data listed in %FUNCS and %GLOBALS.  For data
 | ||
| acquired from overridden methods (subroutines) specific set_METHOD()
 | ||
| subroutines will need to be added if they haven't been already.
 | ||
| 
 | ||
| =head1 Quiet Mode
 | ||
| 
 | ||
| SNMP::Info will not chirp anything to STDOUT unless there is a serious error
 | ||
| (in which case it will probably die).
 | ||
| 
 | ||
| To get lots of debug info, set the Debug flag when calling new() or
 | ||
| call $info->debug(1);
 | ||
| 
 | ||
| When calling a method check the return value.  If the return value is undef
 | ||
| then check $info->error()
 | ||
| 
 | ||
| Beware, calling $info->error() clears the error.
 | ||
| 
 | ||
|  my $name = $info->name() or die "Couldn't get sysName!" . $name->error();
 | ||
| 
 | ||
| =head1 EXTENDING SNMP::INFO
 | ||
| 
 | ||
| To support a new class (vendor or platform) of device, add a Perl package with
 | ||
| the data structures and methods listed below.
 | ||
| 
 | ||
| If this seems a little scary, then the SNMP::Info developers are usually happy
 | ||
| to accept the SNMP data from your device and make an attempt at the class
 | ||
| themselves. Usually a "beta" release will go to CPAN for you to verify the
 | ||
| implementation.
 | ||
| 
 | ||
| =head2 Gathering MIB data for SNMP::Info Developers
 | ||
| 
 | ||
| The preference is to open a pull request in the github project. This
 | ||
| allows all developers to have visibility into the request.  Please include
 | ||
| pointers to the applicable platform MIBs.  For development we will need an
 | ||
| C<snmpwalk> of the device.  There is a tool now included in the SNMP::Info
 | ||
| distribution to help with this task, although you'll most likely need to
 | ||
| download the distribution from CPAN as it's included in the "C<contrib/util>"
 | ||
| directory.
 | ||
| 
 | ||
| The utility is named C<make_snmpdata.pl>. Run it with a command line like:
 | ||
| 
 | ||
|  ./make_snmpdata.pl -c community -i -d device_ip \
 | ||
|   -m /home/netdisco-mibs/rfc:/home/netdisco-mibs/net-snmp:/home/netdisco-mibs/dir3 \
 | ||
|   SNMPv2-MIB IF-MIB EtherLike-MIB BRIDGE-MIB Q-BRIDGE-MIB ENTITY-MIB \
 | ||
|   POWER-ETHERNET-MIB IPV6-MIB LLDP-MIB DEVICE-SPECIFIC-MIB-NAME(s) > output.txt
 | ||
| 
 | ||
| This will print to the file every MIB entry with data in a format that the
 | ||
| developers can use to emulate read operations without needing access to the
 | ||
| device.  Preference would be to mask any sensitive data in the output, zip
 | ||
| the file, and attach it to the github pull request. However, if you do not
 | ||
| feel comfortable uploading the output to the tracker you could e-mail it
 | ||
| to the developer that has claimed the ticket.
 | ||
| 
 | ||
| =head2 Data Structures required in new Subclass
 | ||
| 
 | ||
| A class inheriting this class must implement these data structures :
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item  $INIT
 | ||
| 
 | ||
| Used to flag if the MIBs have been loaded yet.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| $INIT = 0;
 | ||
| 
 | ||
| =item %GLOBALS
 | ||
| 
 | ||
| Contains a hash in the form ( method_name => SNMP MIB leaf name )
 | ||
| These are scalar values such as name, uptime, etc.
 | ||
| 
 | ||
| To resolve MIB leaf name conflicts between private MIBs, you may prefix the
 | ||
| leaf name with the MIB replacing each - (dash) and : (colon) with
 | ||
| an _ (underscore).  For example, ALTEON_TIGON_SWITCH_MIB__agSoftwareVersion
 | ||
| would be used as the hash value instead of the net-snmp notation
 | ||
| ALTEON-TIGON-SWITCH-MIB::agSoftwareVersion.
 | ||
| 
 | ||
| When choosing the name for the methods, be aware that other new
 | ||
| Sub Modules might inherit this one to get it's features.  Try to
 | ||
| choose a prefix for methods that will give it's own name space inside
 | ||
| the SNMP::Info methods.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| %GLOBALS = (
 | ||
| 
 | ||
|     # from SNMPv2-MIB
 | ||
|     'id'           => 'sysObjectID',
 | ||
|     'description'  => 'sysDescr',
 | ||
|     'uptime'       => 'sysUpTime',
 | ||
|     'contact'      => 'sysContact',
 | ||
|     'name'         => 'sysName',
 | ||
|     'location'     => 'sysLocation',
 | ||
|     'layers'       => 'sysServices',
 | ||
|     # IF-MIB
 | ||
|     'ports'        => 'ifNumber',
 | ||
|     # IP-MIB
 | ||
|     'ipforwarding' => 'ipForwarding',
 | ||
| );
 | ||
| 
 | ||
| =item %FUNCS
 | ||
| 
 | ||
| Contains a hash in the form ( method_name => SNMP MIB leaf name)
 | ||
| These are table entries, such as the C<ifIndex>
 | ||
| 
 | ||
| To resolve MIB leaf name conflicts between private MIBs, you may prefix the
 | ||
| leaf name with the MIB replacing each - (dash) and : (colon) with
 | ||
| an _ (underscore).  For example, ALTEON_TS_PHYSICAL_MIB__agPortCurCfgPortName
 | ||
| would be used as the hash value instead of the net-snmp notation
 | ||
| ALTEON-TS-PHYSICAL-MIB::agPortCurCfgPortName.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| %FUNCS = (
 | ||
|     # IF-MIB::IfEntry
 | ||
|     'interfaces' => 'ifIndex',
 | ||
|     # IF-MIB::IfXEntry
 | ||
|     'i_name'     => 'ifName',
 | ||
| 
 | ||
|     # IF-MIB::IfEntry
 | ||
|     'i_index'           => 'ifIndex',
 | ||
|     'i_description'     => 'ifDescr',
 | ||
|     'i_type'            => 'ifType',
 | ||
|     'i_mtu'             => 'ifMtu',
 | ||
|     'i_speed'           => 'ifSpeed',
 | ||
|     'i_mac'             => 'ifPhysAddress',
 | ||
|     'i_up_admin'        => 'ifAdminStatus',
 | ||
|     'i_up'              => 'ifOperStatus',
 | ||
|     'i_lastchange'      => 'ifLastChange',
 | ||
|     'i_octet_in'        => 'ifInOctets',
 | ||
|     'i_pkts_ucast_in'   => 'ifInUcastPkts',
 | ||
|     'i_pkts_nucast_in'  => 'ifInNUcastPkts',
 | ||
|     'i_discards_in'     => 'ifInDiscards',
 | ||
|     'i_errors_in'       => 'ifInErrors',
 | ||
|     'i_bad_proto_in'    => 'ifInUnknownProtos',
 | ||
|     'i_octet_out'       => 'ifOutOctets',
 | ||
|     'i_pkts_ucast_out'  => 'ifOutUcastPkts',
 | ||
|     'i_pkts_nucast_out' => 'ifOutNUcastPkts',
 | ||
|     'i_discards_out'    => 'ifOutDiscards',
 | ||
|     'i_errors_out'      => 'ifOutErrors',
 | ||
|     'i_qlen_out'        => 'ifOutQLen',
 | ||
|     'i_specific'        => 'ifSpecific',
 | ||
| 
 | ||
|     # IF-MIB::IfStackTable
 | ||
|     'i_stack_status'    => 'ifStackStatus',
 | ||
| 
 | ||
|     # IP-MIB::ipAddrTable (deprecated IPv4 address table)
 | ||
|     'old_ip_index'     => 'ipAdEntIfIndex',
 | ||
|     'old_ip_table'     => 'ipAdEntAddr',
 | ||
|     'old_ip_netmask'   => 'ipAdEntNetMask',
 | ||
|     'ip_broadcast'     => 'ipAdEntBcastAddr',
 | ||
| 
 | ||
|     # IP-MIB::ipAddressTable
 | ||
|     'new_ip_index'     => 'ipAddressIfIndex',
 | ||
|     'new_ip_prefix'    => 'ipAddressPrefix',
 | ||
|     'new_ip_type'      => 'ipAddressType',
 | ||
| 
 | ||
|     # IF-MIB::ifXTable - Extension Table
 | ||
|     'i_speed_high'       => 'ifHighSpeed',
 | ||
|     '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',
 | ||
| 
 | ||
|     # RFC-1213::ipRoute (deprecated Table IP Routing Table)
 | ||
|     'ipr_route' => 'ipRouteDest',
 | ||
|     'ipr_if'    => 'ipRouteIfIndex',
 | ||
|     'ipr_1'     => 'ipRouteMetric1',
 | ||
|     'ipr_2'     => 'ipRouteMetric2',
 | ||
|     'ipr_3'     => 'ipRouteMetric3',
 | ||
|     'ipr_4'     => 'ipRouteMetric4',
 | ||
|     'ipr_5'     => 'ipRouteMetric5',
 | ||
|     'ipr_dest'  => 'ipRouteNextHop',
 | ||
|     'ipr_type'  => 'ipRouteType',
 | ||
|     'ipr_proto' => 'ipRouteProto',
 | ||
|     'ipr_age'   => 'ipRouteAge',
 | ||
|     'ipr_mask'  => 'ipRouteMask',
 | ||
|     'ipr_info'  => 'ipRouteInfo',
 | ||
| );
 | ||
| 
 | ||
| =item %MIBS
 | ||
| 
 | ||
| A list of each mib needed.
 | ||
| 
 | ||
|     ('MIB-NAME' => 'itemToTestForPresence')
 | ||
| 
 | ||
| The value for each entry should be a MIB object to check for to make sure
 | ||
| that the MIB is present and has loaded correctly.
 | ||
| 
 | ||
| $info->init() will throw an exception if a MIB does not load.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| %MIBS = (
 | ||
| 
 | ||
|     # Include these here for cases where the Net-SNMP default MIB list has
 | ||
|     # been overridden during the compliation of the local Net-SNMP library.
 | ||
|     # These cover the globals and funcs defined in this file.
 | ||
|     'SNMPv2-MIB'  => 'sysObjectID',
 | ||
|     'RFC1213-MIB' => 'ipRouteIfIndex',
 | ||
|     'IP-MIB'      => 'ipAdEntAddr',
 | ||
|     'IF-MIB'      => 'ifIndex',
 | ||
| );
 | ||
| 
 | ||
| =item %MUNGE
 | ||
| 
 | ||
| A map between method calls (from %FUNCS or %GLOBALS) and subroutine methods.
 | ||
| The subroutine called will be passed the data as it gets it from SNMP and
 | ||
| it should return that same data in a more human friendly format.
 | ||
| 
 | ||
| Sample %MUNGE:
 | ||
| 
 | ||
|  (my_ip     => \&munge_ip,
 | ||
|   my_mac    => \&munge_mac,
 | ||
|   my_layers => \&munge_dec2bin
 | ||
|  )
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| %MUNGE = (
 | ||
|     'ip'                 => \&munge_ip,
 | ||
|     'mac'                => \&munge_mac,
 | ||
|     'i_mac'              => \&munge_mac,
 | ||
|     'layers'             => \&munge_dec2bin,
 | ||
|     'i_speed'            => \&munge_speed,
 | ||
|     'i_speed_high'       => \&munge_highspeed,
 | ||
|     '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,
 | ||
|     'i_up'               => \&munge_i_up,
 | ||
| );
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Sample Subclass
 | ||
| 
 | ||
| Let's make a sample Layer 2 Device subclass.  This class
 | ||
| will inherit the Cisco Vlan module as an example.
 | ||
| 
 | ||
| ----------------------- snip --------------------------------
 | ||
| 
 | ||
|  # SNMP::Info::Layer2::Sample
 | ||
| 
 | ||
|  package SNMP::Info::Layer2::Sample;
 | ||
| 
 | ||
|  $VERSION = 0.1;
 | ||
| 
 | ||
|  use strict;
 | ||
| 
 | ||
|  use Exporter;
 | ||
|  use SNMP::Info::Layer2;
 | ||
|  use SNMP::Info::CiscoVTP;
 | ||
| 
 | ||
|  @SNMP::Info::Layer2::Sample::ISA = qw/SNMP::Info::Layer2
 | ||
|                                        SNMP::Info::CiscoVTP Exporter/;
 | ||
|  @SNMP::Info::Layer2::Sample::EXPORT_OK = qw//;
 | ||
| 
 | ||
|  use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE $AUTOLOAD $INIT $DEBUG/;
 | ||
| 
 | ||
|  %MIBS    = (%SNMP::Info::Layer2::MIBS,
 | ||
|              %SNMP::Info::CiscoVTP::MIBS,
 | ||
|              'SUPER-DOOPER-MIB'  => 'supermibobject'
 | ||
|             );
 | ||
| 
 | ||
|  %GLOBALS = (%SNMP::Info::Layer2::GLOBALS,
 | ||
|              %SNMP::Info::CiscoVTP::GLOBALS,
 | ||
|              'name'              => 'supermib_supername',
 | ||
|              'favorite_color'    => 'supermib_fav_color_object',
 | ||
|              'favorite_movie'    => 'supermib_fav_movie_val'
 | ||
|              );
 | ||
| 
 | ||
|  %FUNCS   = (%SNMP::Info::Layer2::FUNCS,
 | ||
|              %SNMP::Info::CiscoVTP::FUNCS,
 | ||
|              # Super Dooper MIB - Super Hero Table
 | ||
|              'super_hero_index'  => 'SuperHeroIfIndex',
 | ||
|              'super_hero_name'   => 'SuperHeroIfName',
 | ||
|              'super_hero_powers' => 'SuperHeroIfPowers'
 | ||
|             );
 | ||
| 
 | ||
| 
 | ||
|  %MUNGE   = (%SNMP::Info::Layer2::MUNGE,
 | ||
|              %SNMP::Info::CiscoVTP::MUNGE,
 | ||
|              'super_hero_powers' => \&munge_powers
 | ||
|             );
 | ||
| 
 | ||
|  # OverRide uptime() method from %SNMP::Info::GLOBALS
 | ||
|  sub uptime {
 | ||
|      my $sample = shift;
 | ||
| 
 | ||
|      my $name   = $sample->name();
 | ||
| 
 | ||
|      # this is silly but you get the idea
 | ||
|      return '600' if defined $name ;
 | ||
|  }
 | ||
| 
 | ||
|  # Create our own munge function
 | ||
|  sub munge_powers {
 | ||
|      my $power = shift;
 | ||
| 
 | ||
|      # Take the returned obscure value and return something useful.
 | ||
|      return 'Fire' if $power =~ /reallyhot/i;
 | ||
|      return 'Ice'  if $power =~ /reallycold/i;
 | ||
| 
 | ||
|      # Else
 | ||
|      return $power;
 | ||
|  }
 | ||
| 
 | ||
|  # Copious Documentation here!!!
 | ||
|  =head1 NAME
 | ||
|  =head1 AUTHOR
 | ||
|  =head1 SYNOPSIS
 | ||
|  =head1 DESCRIPTION
 | ||
|  =head2 Inherited Classes
 | ||
|  =head2 Required MIBs
 | ||
|  =head1 GLOBALS
 | ||
|  =head2 Overrides
 | ||
|  =head1 TABLE METHODS
 | ||
|  =head2 Overrides
 | ||
|  =cut
 | ||
| 
 | ||
|  1; # don't forget this line
 | ||
| ----------------------- snip --------------------------------
 | ||
| 
 | ||
| 
 | ||
| =head1 SNMP::INFO INTERNALS
 | ||
| 
 | ||
| =head2 Object Namespace
 | ||
| 
 | ||
| Internal data is stored with bareword keys. For example $info->{debug}
 | ||
| 
 | ||
| SNMP Data is stored or marked cached with keys starting with an underscore.
 | ||
| For example $info->{_name} is the cache for $info->name().
 | ||
| 
 | ||
| Cached Table data is stored in $info->store() and marked cached per above.
 | ||
| 
 | ||
| =head2 Package Globals
 | ||
| 
 | ||
| These set the default value for an object upon creation.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item $DEBUG
 | ||
| 
 | ||
| Default 0.  Sends copious debug info to stdout.  This global sets the object's
 | ||
| debug status in new() unless 'Debug' argument passed in new().  Change
 | ||
| objects' debug status with $info->debug().
 | ||
| 
 | ||
| =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;
 | ||
| 
 | ||
| =item $NOSUCH
 | ||
| 
 | ||
| Default 1.  Set to false to disable RetryNoSuch option for SNMP::Session.  Or
 | ||
| see method in new() to do it on an object scope.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| $NOSUCH = 1;
 | ||
| 
 | ||
| =item $REPEATERS
 | ||
| 
 | ||
| Default 20.  MaxRepeaters for BULKWALK operations.  See C<perldoc SNMP> for
 | ||
| more info.  Can change by passing L<BulkRepeaters> option in new()
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| $REPEATERS = 20;
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Data Munging Callback Subroutines
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item munge_speed()
 | ||
| 
 | ||
| Makes human friendly speed ratings using C<%SPEED_MAP>.
 | ||
| 
 | ||
|  %SPEED_MAP = (
 | ||
|                 '56000'      => '56 kbps',
 | ||
|                 '64000'      => '64 kbps',
 | ||
|                 '115000'     => '115 kpbs',
 | ||
|                 '1500000'    => '1.5 Mbps',
 | ||
|                 '1536000'    => 'T1',
 | ||
|                 '1544000'    => 'T1',
 | ||
|                 '2000000'    => '2.0 Mbps',
 | ||
|                 '2048000'    => '2.048 Mbps',
 | ||
|                 '3072000'    => 'Dual T1',
 | ||
|                 '3088000'    => 'Dual T1',
 | ||
|                 '4000000'    => '4.0 Mbps',
 | ||
|                 '10000000'   => '10 Mbps',
 | ||
|                 '11000000'   => '11 Mbps',
 | ||
|                 '20000000'   => '20 Mbps',
 | ||
|                 '16000000'   => '16 Mbps',
 | ||
|                 '16777216'   => '16 Mbps',
 | ||
|                 '44210000'   => 'T3',
 | ||
|                 '44736000'   => 'T3',
 | ||
|                 '45000000'   => '45 Mbps',
 | ||
|                 '45045000'   => 'DS3',
 | ||
|                 '46359642'   => 'DS3',
 | ||
|                 '51850000'   => 'OC-1',
 | ||
|                 '54000000'   => '54 Mbps',
 | ||
|                 '64000000'   => '64 Mbps',
 | ||
|                 '100000000'  => '100 Mbps',
 | ||
|                 '200000000'  => '200 Mbps',
 | ||
|                 '149760000'  => 'ATM on OC-3',
 | ||
|                 '155000000'  => 'OC-3',
 | ||
|                 '155519000'  => 'OC-3',
 | ||
|                 '155520000'  => 'OC-3',
 | ||
|                 '400000000'  => '400 Mbps',
 | ||
|                 '599040000'  => 'ATM on OC-12',
 | ||
|                 '622000000'  => 'OC-12',
 | ||
|                 '622080000'  => 'OC-12',
 | ||
|                 '1000000000' => '1.0 Gbps',
 | ||
|                 '2000000000' => '2.0 Gbps',
 | ||
|                 '2488000000' => 'OC-48',
 | ||
|              )
 | ||
| 
 | ||
| Note: high speed interfaces (usually 1 Gbps or faster) have their link
 | ||
| speed in C<ifHighSpeed>. i_speed() automatically determines whether to use
 | ||
| C<ifSpeed> or C<ifHighSpeed>; if the latter is used, the value is munged by
 | ||
| munge_highspeed(). SNMP::Info can return speeds up to terabit levels this way.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| %SPEED_MAP = (
 | ||
|     '56000'      => '56 kbps',
 | ||
|     '64000'      => '64 kbps',
 | ||
|     '115000'     => '115 kpbs',
 | ||
|     '1500000'    => '1.5 Mbps',
 | ||
|     '1536000'    => 'T1',
 | ||
|     '1544000'    => 'T1',
 | ||
|     '2000000'    => '2.0 Mbps',
 | ||
|     '2048000'    => '2.048 Mbps',
 | ||
|     '3072000'    => 'Dual T1',
 | ||
|     '3088000'    => 'Dual T1',
 | ||
|     '4000000'    => '4.0 Mbps',
 | ||
|     '10000000'   => '10 Mbps',
 | ||
|     '11000000'   => '11 Mbps',
 | ||
|     '20000000'   => '20 Mbps',
 | ||
|     '16000000'   => '16 Mbps',
 | ||
|     '16777216'   => '16 Mbps',
 | ||
|     '44210000'   => 'T3',
 | ||
|     '44736000'   => 'T3',
 | ||
|     '45000000'   => '45 Mbps',
 | ||
|     '45045000'   => 'DS3',
 | ||
|     '46359642'   => 'DS3',
 | ||
|     '51850000'   => 'OC-1',
 | ||
|     '54000000'   => '54 Mbps',
 | ||
|     '64000000'   => '64 Mbps',
 | ||
|     '100000000'  => '100 Mbps',
 | ||
|     '200000000'  => '200 Mbps',
 | ||
|     '149760000'  => 'ATM on OC-3',
 | ||
|     '155000000'  => 'OC-3',
 | ||
|     '155519000'  => 'OC-3',
 | ||
|     '155520000'  => 'OC-3',
 | ||
|     '400000000'  => '400 Mbps',
 | ||
|     '599040000'  => 'ATM on OC-12',
 | ||
|     '622000000'  => 'OC-12',
 | ||
|     '622080000'  => 'OC-12',
 | ||
|     '1000000000' => '1.0 Gbps',
 | ||
|     '2000000000' => '2.0 Gbps',
 | ||
|     '2488000000' => 'OC-48',
 | ||
| );
 | ||
| 
 | ||
| sub munge_speed {
 | ||
|     my $speed = shift;
 | ||
|     my $map   = $SPEED_MAP{$speed};
 | ||
| 
 | ||
|     #print "  $speed -> $map  " if (defined $map);
 | ||
|     return $map || $speed;
 | ||
| }
 | ||
| 
 | ||
| =item munge_highspeed()
 | ||
| 
 | ||
| Makes human friendly speed ratings for C<ifHighSpeed>.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_highspeed {
 | ||
|     my $speed = shift;
 | ||
|     my $fmt   = "%d Mbps";
 | ||
| 
 | ||
|     if ( $speed > 9999999 ) {
 | ||
|         $fmt = "%d Tbps";
 | ||
|         $speed /= 1000000;
 | ||
|     }
 | ||
|     elsif ( $speed > 999999 ) {
 | ||
|         $fmt = "%.1f Tbps";
 | ||
|         $speed /= 1000000.0;
 | ||
|     }
 | ||
|     elsif ( $speed > 9999 ) {
 | ||
|         $fmt = "%d Gbps";
 | ||
|         $speed /= 1000;
 | ||
|     }
 | ||
|     elsif ( $speed > 999 ) {
 | ||
|         $fmt = "%.1f Gbps";
 | ||
|         $speed /= 1000.0;
 | ||
|     }
 | ||
|     return sprintf( $fmt, $speed );
 | ||
| }
 | ||
| 
 | ||
| =item munge_ip()
 | ||
| 
 | ||
| Takes a binary IP and makes it dotted ASCII.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_ip {
 | ||
|     my $ip = shift;
 | ||
|     return join( '.', unpack( 'C4', $ip ) );
 | ||
| }
 | ||
| 
 | ||
| =item munge_mac()
 | ||
| 
 | ||
| Takes an octet stream (HEX-STRING) and returns a colon separated ASCII hex
 | ||
| string.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_mac {
 | ||
|     my $mac = shift;
 | ||
|     return unless defined $mac;
 | ||
|     return unless length $mac;
 | ||
|     $mac = join( ':', map { sprintf "%02x", $_ } unpack( 'C*', $mac ) );
 | ||
|     return $mac if $mac =~ /^([0-9A-F][0-9A-F]:){5}[0-9A-F][0-9A-F]$/i;
 | ||
|     return;
 | ||
| }
 | ||
| 
 | ||
| =item munge_prio_mac()
 | ||
| 
 | ||
| Takes an 8-byte octet stream (HEX-STRING) and returns a colon separated ASCII
 | ||
| hex string.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_prio_mac {
 | ||
|     my $mac = shift;
 | ||
|     return unless defined $mac;
 | ||
|     return unless length $mac;
 | ||
|     $mac = join( ':', map { sprintf "%02x", $_ } unpack( 'C*', $mac ) );
 | ||
|     return $mac if $mac =~ /^([0-9A-F][0-9A-F]:){7}[0-9A-F][0-9A-F]$/i;
 | ||
|     return;
 | ||
| }
 | ||
| 
 | ||
| =item munge_prio_port()
 | ||
| 
 | ||
| Takes an 2-byte octet stream (HEX-STRING) and returns a colon separated ASCII
 | ||
| hex string.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_prio_port {
 | ||
|     my $priop = shift;
 | ||
|     return unless defined $priop;
 | ||
|     return unless length $priop;
 | ||
|     $priop = join( ':', map { sprintf "%02x", $_ } unpack( 'C*', $priop ) );
 | ||
|     return $priop if $priop =~ /^([0-9A-F][0-9A-F]:){1}[0-9A-F][0-9A-F]$/i;
 | ||
|     return;
 | ||
| }
 | ||
| 
 | ||
| =item munge_octet2hex()
 | ||
| 
 | ||
| Takes a binary octet stream and returns an ASCII hex string.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_octet2hex {
 | ||
|     my $oct = shift;
 | ||
|     return join( '', map { sprintf "%x", $_ } unpack( 'C*', $oct ) );
 | ||
| }
 | ||
| 
 | ||
| =item munge_dec2bin()
 | ||
| 
 | ||
| Takes a binary char and returns its ASCII binary representation.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_dec2bin {
 | ||
|     my $num = shift;
 | ||
|     return unless defined $num;
 | ||
| 
 | ||
|     #return unless length($num);
 | ||
|     $num = unpack( "B32", pack( "N", $num ) );
 | ||
| 
 | ||
|     # return last 8 characters only
 | ||
|     $num =~ s/.*(.{8})$/$1/;
 | ||
|     return $num;
 | ||
| }
 | ||
| 
 | ||
| =item munge_bits()
 | ||
| 
 | ||
| Takes a SNMP2 'BITS' field and returns the ASCII bit string.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_bits {
 | ||
|     my $bits = shift;
 | ||
|     return unless defined $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;
 | ||
| }
 | ||
| 
 | ||
| =item munge_i_up()
 | ||
| 
 | ||
| Net-SNMP tends to load C<RFC1213-MIB> first, and so ignores the
 | ||
| updated enumeration for C<ifOperStatus> in C<IF-MIB>.  This munge
 | ||
| handles the "newer" definitions for the enumeration in IF-MIB.
 | ||
| 
 | ||
| TODO: Get the precedence of MIBs and overriding of MIB data in Net-SNMP
 | ||
| figured out.  Heirarchy/precendence of MIBS in SNMP::Info.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_i_up {
 | ||
|     my $i_up = shift;
 | ||
|     return unless defined $i_up;
 | ||
| 
 | ||
|     my %ifOperStatusMap = ( '4' => 'unknown',
 | ||
|                             '5' => 'dormant',
 | ||
|                             '6' => 'notPresent',
 | ||
|                             '7' => 'lowerLayerDown' );
 | ||
|     return $ifOperStatusMap{$i_up} || $i_up;
 | ||
| }
 | ||
| 
 | ||
| =item munge_port_list()
 | ||
| 
 | ||
| Takes an octet string representing a set of ports and returns a reference
 | ||
| to an array of binary values each array element representing a port.
 | ||
| 
 | ||
| If the element has a value of '1', then that port is included in the set of
 | ||
| ports; the port is not included if it has a value of '0'.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_port_list {
 | ||
|     my $oct = shift;
 | ||
|     return unless defined $oct;
 | ||
| 
 | ||
|     my $list = [ split( //, unpack( "B*", $oct ) ) ];
 | ||
| 
 | ||
|     return $list;
 | ||
| }
 | ||
| 
 | ||
| =item munge_null()
 | ||
| 
 | ||
| Removes control characters from a string.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| # munge_null() - removes nulls (\0) and other control characters
 | ||
| sub munge_null {
 | ||
|     my $text = shift || return;
 | ||
| 
 | ||
|     $text =~ s/[[:cntrl:]]//g;
 | ||
|     return $text;
 | ||
| }
 | ||
| 
 | ||
| =item munge_e_type()
 | ||
| 
 | ||
| Takes an OID and return the object name if the right MIB is loaded.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge_e_type {
 | ||
|     my $oid = shift;
 | ||
| 
 | ||
|     my $name = &SNMP::translateObj($oid);
 | ||
|     return $name if defined($name);
 | ||
|     return $oid;
 | ||
| }
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 Internally Used Functions
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item resolve_desthost()
 | ||
| 
 | ||
| Takes the SNMP::Session C<DestHost> argument and determines if it is an
 | ||
| 'IPv4' or 'IPv6' host. 'IPv6' hosts are prefixed with the C<udp6:>
 | ||
| C<transport-specifier> as required by the undelying C<Net-SNMP> library.
 | ||
| If unable to determine the type of address or resolve a DNS name, dies with
 | ||
| C<croak>.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub resolve_desthost {
 | ||
|     my $desthost = shift;
 | ||
| 
 | ||
|     # If we have an IPv6 transport-specifier strip it
 | ||
|     $desthost =~ s/^(?:udp6:|udpv6:|udpipv6:)//x;
 | ||
| 
 | ||
|     my $ip = NetAddr::IP::Lite->new($desthost);
 | ||
|     
 | ||
|     if ($ip and $ip->bits == 32) {
 | ||
|         return $ip->addr;
 | ||
|     }
 | ||
|     elsif ($ip and $ip->bits == 128) {
 | ||
|         return 'udp6:' . $ip->addr;        
 | ||
|     }
 | ||
|     else {
 | ||
|        croak "Unable to resolve DestHost: $desthost to an IP\n";
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->init()
 | ||
| 
 | ||
| Used internally.  Loads all entries in %MIBS.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub init {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     # Get MibDirs if provided
 | ||
|     my $mibdirs = $self->{mibdirs} || [];
 | ||
| 
 | ||
|     # SNMP::initMib and SNMP::addMibDirs both look for some initial MIBs
 | ||
|     # so if we are not using Net-SNMP configuration files we need to
 | ||
|     # specify where the MIBs are before those calls.
 | ||
| 
 | ||
|     # Ignore snmp.conf and snmp.local.conf files if IgnoreNetSNMPConf
 | ||
|     # specified
 | ||
|     local $ENV{'SNMPCONFPATH'} = '' if $self->{IgnoreNetSNMPConf};
 | ||
|     # We need to provide MIBDIRS if we are not getting them from a
 | ||
|     # configuration file
 | ||
|     my $mibdir = join (':', @$mibdirs);
 | ||
|     local $ENV{'MIBDIRS'} = "$mibdir" if $self->{IgnoreNetSNMPConf};
 | ||
| 
 | ||
|     SNMP::initMib;
 | ||
| 
 | ||
|     my $version = $SNMP::VERSION;
 | ||
|     my ( $major, $minor, $rev ) = split( '\.', $version );
 | ||
| 
 | ||
|     if ( $major < 5 ) {
 | ||
| 
 | ||
|         # Seems to work under 4.2.0
 | ||
|     }
 | ||
|     elsif ( $major == 5 and $minor == 0 and $rev < 2 ) {
 | ||
|         carp("Net-SNMP 5.0.1 seems to be rather buggy. Upgrade.\n");
 | ||
| 
 | ||
|         # This is a bug in net-snmp 5.0.1 perl module
 | ||
|         # see http://groups.google.com/groups?th=47aed6bf7be6a0f5
 | ||
|         SNMP::init_snmp("perl");
 | ||
|     }
 | ||
| 
 | ||
|     foreach my $d (@$mibdirs) {
 | ||
|         next unless -d $d;
 | ||
|         print "SNMP::Info::init() - Adding new mibdir:$d\n"
 | ||
|           if $self->debug() > 1;
 | ||
|         SNMP::addMibDirs($d);
 | ||
|     }
 | ||
| 
 | ||
|     my $mibs = $self->mibs();
 | ||
| 
 | ||
|     foreach my $mib ( keys %$mibs ) {
 | ||
| 
 | ||
|         #print "SNMP::Info::init() - Loading mib:$mib\n" if $self->debug();
 | ||
|         SNMP::loadModules("$mib");
 | ||
| 
 | ||
|         unless ( defined $SNMP::MIB{ $mibs->{$mib} } ) {
 | ||
|             croak "The $mib did not load. See README for $self->{class}\n";
 | ||
|         }
 | ||
|     }
 | ||
|     return;
 | ||
| }
 | ||
| 
 | ||
| =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.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub class {
 | ||
|     my $self = shift;
 | ||
|     return $self->{class};
 | ||
| }
 | ||
| 
 | ||
| =item $info->error_throw(error message)
 | ||
| 
 | ||
| Stores the error message for use by $info->error()
 | ||
| 
 | ||
| If $info->debug() is true, then the error message is carped too.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub error_throw {
 | ||
|     my $self  = shift;
 | ||
|     my $error = shift;
 | ||
| 
 | ||
|     return unless defined $error;
 | ||
|     $self->{error} = $error;
 | ||
| 
 | ||
|     if ( $self->debug() ) {
 | ||
|         $error =~ s/\n+$//;
 | ||
|         carp($error);
 | ||
|     }
 | ||
|     return;
 | ||
| }
 | ||
| 
 | ||
| =item $info->funcs()
 | ||
| 
 | ||
| Returns a reference to the %FUNCS hash.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub funcs {
 | ||
|     my $self = shift;
 | ||
|     return $self->{funcs};
 | ||
| }
 | ||
| 
 | ||
| =item $info->globals()
 | ||
| 
 | ||
| Returns a reference to the %GLOBALS hash.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub globals {
 | ||
|     my $self = shift;
 | ||
|     return $self->{globals};
 | ||
| }
 | ||
| 
 | ||
| =item $info->mibs()
 | ||
| 
 | ||
| Returns a reference to the %MIBS hash.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub mibs {
 | ||
|     my $self = shift;
 | ||
|     return $self->{mibs};
 | ||
| }
 | ||
| 
 | ||
| =item $info->munge()
 | ||
| 
 | ||
| Returns a reference of the %MUNGE hash.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub munge {
 | ||
|     my $self = shift;
 | ||
|     return $self->{munge};
 | ||
| }
 | ||
| 
 | ||
| =item $info->nosuch()
 | ||
| 
 | ||
| Returns NoSuch value set or not in new()
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub nosuch {
 | ||
|     my $self = shift;
 | ||
|     return $self->{nosuch};
 | ||
| }
 | ||
| 
 | ||
| =item $info->session()
 | ||
| 
 | ||
| Gets or Sets the SNMP::Session object.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub session {
 | ||
|     my $self = shift;
 | ||
|     $self->{sess} = $_[0] if @_;
 | ||
|     return $self->{sess};
 | ||
| }
 | ||
| 
 | ||
| =item $info->store(new_store)
 | ||
| 
 | ||
| Returns or sets hash store for Table functions.
 | ||
| 
 | ||
| Store is a hash reference in this format :
 | ||
| 
 | ||
| $info->store = { attribute => { iid => value , iid2 => value2, ... } };
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub store {
 | ||
|     my $self = shift;
 | ||
|     $self->{store} = $_[0] if @_;
 | ||
|     return $self->{store};
 | ||
| }
 | ||
| 
 | ||
| =item $info->_global()
 | ||
| 
 | ||
| Used internally by AUTOLOAD to create dynamic methods from %GLOBALS or a
 | ||
| single instance MIB Leaf node name from a loaded MIB.
 | ||
| 
 | ||
| Example: $info->name() on the first call dispatches to AUTOLOAD() which
 | ||
| calls $info->_global('name') creating the method name().
 | ||
| 
 | ||
| These methods return data as a scalar.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _global {
 | ||
|     my $method = shift;
 | ||
|     my $oid    = shift;
 | ||
| 
 | ||
|     return sub {
 | ||
|         my $self = shift;
 | ||
| 
 | ||
|         my $sess = $self->session();
 | ||
|         return unless defined $sess;
 | ||
| 
 | ||
|         my $load = $method =~ /^load/;
 | ||
|         my $raw  = $method =~ /raw$/;
 | ||
| 
 | ||
|         my $attr = $method;
 | ||
|         $attr =~ s/^(load|orig)_//;
 | ||
|         $attr =~ s/_raw$//;
 | ||
| 
 | ||
|         # Return cached data unless loading
 | ||
|         # We now store in raw format so munge before returning
 | ||
|         # unless expecting raw data
 | ||
|         if ( exists $self->{"_$attr"} && !$load ) {
 | ||
|             my $val = $self->{"_$attr"};
 | ||
| 
 | ||
|             if ( !$raw ) {
 | ||
|                 return $self->_munge($attr, $val);
 | ||
|             } else{
 | ||
|                 return $val;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         if ( $self->{Offline} ) {
 | ||
|             $self->error_throw(
 | ||
|                 "SNMP::Info::_global: Offline but $attr is not in cache\n" );
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         if ( $self->debug() ) {
 | ||
|             # Let's get the MIB Module and leaf name along with the OID
 | ||
|             my $qual_leaf = SNMP::translateObj($oid,0,1) || '';
 | ||
|             print "SNMP::Info::_global $method : $qual_leaf : $oid\n";
 | ||
|         }
 | ||
|         my $val = $sess->get($oid);
 | ||
| 
 | ||
|         # Mark as gotten. Even if it fails below, we don't want to keep failing.
 | ||
|         $self->{"_$attr"} = undef;
 | ||
| 
 | ||
|         if ( $sess->{ErrorStr} ) {
 | ||
|             $self->error_throw(
 | ||
|                 "SNMP::Info::_global($method) $sess->{ErrorStr}");
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         if ( defined $val and $val eq 'NOSUCHOBJECT' ) {
 | ||
|             $self->error_throw("SNMP::Info::_global($method) NOSUCHOBJECT");
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         if ( defined $val and $val eq 'NOSUCHINSTANCE' ) {
 | ||
|             $self->error_throw("SNMP::Info::_global($method) NOSUCHINSTANCE");
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         # Save Cached Value
 | ||
|         $self->_cache($attr, $val);
 | ||
| 
 | ||
|         # Data Munging
 | ||
|         if ( !$raw ) {
 | ||
|             $val = $self->_munge($attr, $val);
 | ||
|         }
 | ||
| 
 | ||
|         return $val;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->_set(attr,val,iid,type)
 | ||
| 
 | ||
| Used internally by set_multi() to run an SNMP set command.  When run
 | ||
| clears attr cache.
 | ||
| 
 | ||
| Attr can be passed as either a scalar or a reference to an array or array
 | ||
| of arrays when used with set_multi().
 | ||
| 
 | ||
| Example:  $info->set_name('dog',3) uses autoload to resolve to
 | ||
| $info->_set('name','dog',3);
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _set {
 | ||
|     my ( $self, $attr, $val, $iid, $type ) = @_;
 | ||
|     my $varbind_list_ref;
 | ||
| 
 | ||
|     if ( !ref($attr) ) {
 | ||
|         $varbind_list_ref = [ [ $attr, $iid, $val, $type ] ];
 | ||
|     }
 | ||
|     elsif ( ref($attr) =~ /ARRAY/ ) {
 | ||
|         $varbind_list_ref = [$attr];
 | ||
|         $varbind_list_ref = $attr if ref( $$attr[0] ) =~ /ARRAY/;
 | ||
|     }
 | ||
|     else {
 | ||
|         $self->error_throw(
 | ||
|             "SNMP::Info::_set - Failed. Invalid arguments"
 | ||
|         );
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     my $sess = $self->session();
 | ||
|     return unless defined $sess;
 | ||
| 
 | ||
|     my $funcs   = $self->funcs();
 | ||
|     my $globals = $self->globals();
 | ||
| 
 | ||
|     foreach my $var_list (@$varbind_list_ref) {
 | ||
|         my $list_attr = $var_list->[0];
 | ||
|         my $list_iid  = $var_list->[1];
 | ||
|         my $list_val  = $var_list->[2];
 | ||
| 
 | ||
|         # Get rid of non-printable chars in $list_val for debug statements
 | ||
|         $list_val =~ s/\W//;
 | ||
| 
 | ||
|         # Instance is 0 for scalars without a supplied instance
 | ||
|         $var_list->[1] = $list_iid = defined $list_iid ? $list_iid : '0';
 | ||
| 
 | ||
|         # Lookup oid
 | ||
|         my $oid = undef;
 | ||
|         $oid = $list_attr             if SNMP::translateObj($list_attr);
 | ||
|         $oid = $globals->{$list_attr} if defined $globals->{$list_attr};
 | ||
|         $oid = $funcs->{$list_attr}   if defined $funcs->{$list_attr};
 | ||
| 
 | ||
|         unless ( defined $oid ) {
 | ||
|             $self->error_throw(
 | ||
|                 "SNMP::Info::_set($list_attr,$list_val) - Failed to find $list_attr in \%GLOBALS or \%FUNCS or loaded MIB."
 | ||
|             );
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         # Check for fully qualified attr
 | ||
|         if ( $oid =~ /__/ ) {
 | ||
|             $oid =~ s/__/::/;
 | ||
|             $oid =~ s/_/-/g;
 | ||
|         }
 | ||
| 
 | ||
|         $var_list->[0] = $oid;
 | ||
| 
 | ||
|         $self->debug()
 | ||
|             and print
 | ||
|             "SNMP::Info::_set $list_attr.$list_iid ($oid.$list_iid) = $list_val\n";
 | ||
|         delete $self->{"_$list_attr"};
 | ||
|     }
 | ||
| 
 | ||
|     my $rv = $sess->set($varbind_list_ref);
 | ||
| 
 | ||
|     if ( $sess->{ErrorStr} ) {
 | ||
|         $self->error_throw("SNMP::Info::_set $sess->{ErrorStr}");
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     return $rv;
 | ||
| }
 | ||
| 
 | ||
| =item $info->_make_setter(val,iid)
 | ||
| 
 | ||
| Used internally by AUTOLOAD to create dynamic methods from either %GLOBALS,
 | ||
| %FUNCS, or a valid mib leaf from a loaded MIB which runs an SNMP set command.
 | ||
| When run clears the attribute cache.
 | ||
| 
 | ||
| Example:  $info->set_name('dog',3) dispatches to autoload to resolve to
 | ||
| $info->_set('name','dog',3) and _make_setter creates the set_name() method.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _make_setter {
 | ||
|     my $method = shift;
 | ||
|     my $oid    = shift;
 | ||
| 
 | ||
|     return sub {
 | ||
|         my $self = shift;
 | ||
|         my $val  = shift;
 | ||
|         my $iid  = shift;
 | ||
| 
 | ||
|         my $set_oid = $oid;
 | ||
|         my $globals = $self->globals();
 | ||
|         my $attr = $method;
 | ||
|         $attr =~ s/^set_//;
 | ||
| 
 | ||
|         # The only thing which may give us the iid in $oid should be
 | ||
|         # a %GLOBALS entry appended with a number.  In that case strip it
 | ||
|         # from the OID and use it as $iid
 | ||
|         if ( defined $globals->{$attr} && $globals->{$attr} =~ /(\.\d+$)/ ) {
 | ||
|             $iid = $1;
 | ||
|             $set_oid =~ s/$iid//;
 | ||
|         }
 | ||
| 
 | ||
|         # If we don't have $iid now we should be a %GLOBALS entry or single
 | ||
|         # instance MIB leaf so default to zero
 | ||
|         $iid = defined $iid ? $iid : '.0';
 | ||
| 
 | ||
|         # prepend dot if necessary to $iid
 | ||
|         $iid = ".$iid" unless $iid =~ /^\./;
 | ||
| 
 | ||
|         my $sess = $self->session();
 | ||
|         return unless defined $sess;
 | ||
| 
 | ||
|         $set_oid .= "$iid";
 | ||
| 
 | ||
|         $self->debug()
 | ||
|             and print "SNMP::Info::_set $method$iid ($set_oid) = $val\n";
 | ||
|         delete $self->{"_$attr"};
 | ||
| 
 | ||
|         my $rv = $sess->set( $set_oid, $val );
 | ||
| 
 | ||
|         if ( $sess->{ErrorStr} ) {
 | ||
|             $self->error_throw("SNMP::Info::_set $sess->{ErrorStr}");
 | ||
|             return;
 | ||
|         }
 | ||
|         return $rv;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->set_multi(arrayref)
 | ||
| 
 | ||
| Used to run an SNMP set command on several new values in the one request.
 | ||
| Returns the result of $info->_set(method).
 | ||
| 
 | ||
| Pass either a reference to a 4 element array [<obj>, <iid>, <val>, <type>] or
 | ||
| a reference to an array of 4 element arrays to specify multiple values.
 | ||
| 
 | ||
|     <obj> - One of the following forms:
 | ||
|         1) leaf identifier (e.g., C<'sysContact'>)
 | ||
|         2) An entry in either %FUNCS, %GLOBALS (e.g., 'contact')
 | ||
|     <iid> - The dotted-decimal, instance identifier. For scalar MIB objects
 | ||
|              use '0'
 | ||
|     <val>  - The SNMP data value being set (e.g., 'netdisco')
 | ||
|     <type> - Optional as the MIB should be loaded.
 | ||
| 
 | ||
| If one of the set assignments is invalid, then the request will be rejected
 | ||
| without applying any of the new values - regardless of the order they appear
 | ||
| in the list.
 | ||
| 
 | ||
| Example:
 | ||
|     my $vlan_set = [
 | ||
|         ['qb_v_untagged',"$old_vlan_id","$old_untagged_portlist"],
 | ||
|         ['qb_v_egress',"$new_vlan_id","$new_egress_portlist"],
 | ||
|         ['qb_v_egress',"$old_vlan_id","$old_egress_portlist"],
 | ||
|         ['qb_v_untagged',"$new_vlan_id","$new_untagged_portlist"],
 | ||
|         ['qb_i_vlan',"$port","$new_vlan_id"],
 | ||
|     ];
 | ||
| 
 | ||
|     $info->set_multi($vlan_set);
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub set_multi {
 | ||
|     my $self = shift;
 | ||
| 
 | ||
|     return $self->_set(@_);
 | ||
| }
 | ||
| 
 | ||
| =item $info->load_all()
 | ||
| 
 | ||
| Debugging routine.  This does not include any overridden method or method
 | ||
| implemented by subroutine.
 | ||
| 
 | ||
| Runs $info->load_METHOD() for each entry in $info->funcs();
 | ||
| 
 | ||
| Returns $info->store() -- See store() entry.
 | ||
| 
 | ||
| Note return value has changed since version 0.3
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub load_all {
 | ||
|     my $self = shift;
 | ||
|     my $sess = $self->session();
 | ||
|     return unless defined $sess;
 | ||
| 
 | ||
|     my $funcs = $self->funcs();
 | ||
| 
 | ||
|     foreach my $attrib ( keys %$funcs ) {
 | ||
|         $attrib = "load_$attrib";
 | ||
|         $self->$attrib();
 | ||
|     }
 | ||
| 
 | ||
|     $self->{_all}++;
 | ||
| 
 | ||
|     return unless defined wantarray;
 | ||
| 
 | ||
|     return $self->store();
 | ||
| }
 | ||
| 
 | ||
| =item $info->all()
 | ||
| 
 | ||
| Runs $info->load_all() once then returns $info->store();
 | ||
| 
 | ||
| Use $info->load_all() to reload the data.
 | ||
| 
 | ||
| Note return value has changed since version 0.3
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub all {
 | ||
|     my $self = shift;
 | ||
|     my $sess = $self->session();
 | ||
|     return unless defined $sess;
 | ||
| 
 | ||
|     $self->load_all() unless defined $self->{_all};
 | ||
| 
 | ||
|     return $self->store();
 | ||
| }
 | ||
| 
 | ||
| =item $info->_load_attr()
 | ||
| 
 | ||
| Used internally by AUTOLOAD to create dynamic methods from %FUNCS
 | ||
| or a MIB Leaf node name contained within a table of a loaded MIB.
 | ||
| 
 | ||
| Supports partial table fetches and single instance table fetches.
 | ||
| See L<SNMP::Info/"Partial Table Fetches">.
 | ||
| 
 | ||
| These methods return data as a reference to a hash.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _load_attr {
 | ||
|     my $method = shift;
 | ||
|     my $oid    = shift;
 | ||
| 
 | ||
|     return sub {
 | ||
|         my $self    = shift;
 | ||
|         my $partial = shift;
 | ||
| 
 | ||
|         my $sess = $self->session();
 | ||
|         return unless defined $sess;
 | ||
| 
 | ||
|         my $ver    = $self->snmp_ver();
 | ||
| 
 | ||
|         my $load = $method =~ /^load/;
 | ||
|         my $raw  = $method =~ /raw$/;
 | ||
| 
 | ||
|         my $attr = $method;
 | ||
|         $attr =~ s/^(load|orig)_//;
 | ||
|         $attr =~ s/_raw$//;
 | ||
| 
 | ||
|         # Return cached data unless loading or partial
 | ||
|         # We now store in raw format so munge before returning
 | ||
|         # unless expecting raw data
 | ||
|         return $self->_show_attr($attr, $raw)
 | ||
|             if ( defined $self->{"_${attr}"}
 | ||
|             && !$load
 | ||
|             && !defined $partial );
 | ||
| 
 | ||
|         if ( $self->{Offline} ) {
 | ||
|             $self->error_throw(
 | ||
|                 "SNMP::Info::_load_attr: Offline but $attr is not in cache\n" );
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         # We want the qualified leaf name so that we can
 | ||
|         # specify the Module (MIB) in the case of private leaf naming
 | ||
|         # conflicts.  Example: ALTEON-TIGON-SWITCH-MIB::agSoftwareVersion
 | ||
|         # and ALTEON-CHEETAH-SWITCH-MIB::agSoftwareVersion
 | ||
|         # Third argument to translateObj specifies the Module prefix
 | ||
| 
 | ||
|         my $qual_leaf = SNMP::translateObj($oid,0,1) || '';
 | ||
| 
 | ||
|         # We still want just the leaf since a SNMP get in the case of a
 | ||
|         # partial fetch may strip the Module portion upon return.  We need
 | ||
|         # the match to make sure we didn't leave the table during getnext
 | ||
|         # requests
 | ||
| 
 | ||
|         my ($leaf) = $qual_leaf =~ /::(.+)$/;
 | ||
|         
 | ||
|         # If we weren't able to translate, we'll only have an OID
 | ||
|         $leaf = $oid unless defined $leaf;
 | ||
| 
 | ||
|         $self->debug()
 | ||
|             and print "SNMP::Info::_load_attr $method : $qual_leaf",
 | ||
|             defined $partial ? "($partial)" : '', " : $oid" ,
 | ||
|             defined $partial ? ".$partial" : '', "\n";
 | ||
| 
 | ||
|         my $var = SNMP::Varbind->new( [$qual_leaf, $partial] );
 | ||
| 
 | ||
|         # So devices speaking SNMP v.1 are not supposed to give out
 | ||
|         # data from SNMP2, but most do.  Net-SNMP, being very precise
 | ||
|         # will tell you that the SNMP OID doesn't exist for the device.
 | ||
|         # They have a flag RetryNoSuch that is used for get() operations,
 | ||
|         # but not for getnext().  We set this flag normally, and if we're
 | ||
|         # using V1, let's try and fetch the data even if we get one of those.
 | ||
| 
 | ||
|         my $localstore = undef;
 | ||
|         my $errornum   = 0;
 | ||
|         my %seen       = ();
 | ||
| 
 | ||
|         my $vars = [];
 | ||
|         my $bulkwalk_no
 | ||
|             = $self->can('bulkwalk_no') ? $self->bulkwalk_no() : 0;
 | ||
|         my $bulkwalk_on = defined $self->{BulkWalk} ? $self->{BulkWalk} : 1;
 | ||
|         my $can_bulkwalk = $bulkwalk_on && !$bulkwalk_no;
 | ||
|         my $repeaters = $self->{BulkRepeaters} || $REPEATERS;
 | ||
|         my $bulkwalk = $can_bulkwalk && $ver != 1;
 | ||
|         my $loopdetect
 | ||
|             = defined $self->{LoopDetect} ? $self->{LoopDetect} : 1;
 | ||
| 
 | ||
|         if ( defined $partial ) {
 | ||
| 
 | ||
|             # Try a GET, in case the partial is a leaf OID.
 | ||
|             # Would like to only do this if we know the OID is
 | ||
|             # long enough; implementing that would require a
 | ||
|             # lot of MIB mucking.
 | ||
|             my $try = $sess->get($var);
 | ||
|             $errornum = $sess->{ErrorNum};
 | ||
|             if ( defined($try) && $errornum == 0 && $try !~ /^NOSUCH/ ) {
 | ||
|                 $var->[2] = $try;
 | ||
|                 $vars     = [$var];
 | ||
|                 $bulkwalk = 1;        # fake a bulkwalk return
 | ||
|             }
 | ||
| 
 | ||
|             # We want to execute the while loop below for the getnext request.
 | ||
|             if (    $ver == 1
 | ||
|                 and $sess->{ErrorNum}
 | ||
|                 and $sess->{ErrorStr} =~ /nosuch/i )
 | ||
|             {
 | ||
|                 $errornum = 0;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         # Use BULKWALK if we can because its faster
 | ||
|         if ( $bulkwalk && @$vars == 0 ) {
 | ||
|             ($vars) = $sess->bulkwalk( 0, $repeaters, $var );
 | ||
|             if ( $sess->{ErrorNum} ) {
 | ||
|                 $self->error_throw(
 | ||
|                     "SNMP::Info::_load_attr: BULKWALK " . $sess->{ErrorStr},
 | ||
|                     "\n" );
 | ||
|                 return;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         while ( !$errornum ) {
 | ||
|             if ($bulkwalk) {
 | ||
|                 $var = shift @$vars or last;
 | ||
|             }
 | ||
|             else {
 | ||
| 
 | ||
|                 # GETNEXT instead of BULKWALK
 | ||
|                 $sess->getnext($var);
 | ||
|                 $errornum = $sess->{ErrorNum};
 | ||
|             }
 | ||
| 
 | ||
|             if ( $self->debug() > 1 ) {
 | ||
|                 use Data::Dumper;
 | ||
|                 print "SNMP::Info::_load_attr $method : leaf = $oid , var = ",
 | ||
|                     Dumper($var);
 | ||
|             }
 | ||
| 
 | ||
|             # Check if we've left the requested subtree
 | ||
|             last if $var->[0] !~ /$leaf$/;
 | ||
|             my $iid = $var->[1];
 | ||
|             my $val = $var->[2];
 | ||
| 
 | ||
|             unless ( defined $iid ) {
 | ||
|                 $self->error_throw(
 | ||
|                     "SNMP::Info::_load_attr: $method not here");
 | ||
|                 next;
 | ||
|             }
 | ||
| 
 | ||
|             # Check to make sure we are still in partial land
 | ||
|             if (    defined $partial
 | ||
|                 and $iid !~ /^$partial$/
 | ||
|                 and $iid !~ /^$partial\./ )
 | ||
|             {
 | ||
|                 $self->debug()
 | ||
|                     and print "$iid makes us leave partial land.\n";
 | ||
|                 last;
 | ||
|             }
 | ||
| 
 | ||
|            # Check if last element, V2 devices may report ENDOFMIBVIEW even if
 | ||
|            # instance or object doesn't exist.
 | ||
|             if ( $val eq 'ENDOFMIBVIEW' ) {
 | ||
|                 last;
 | ||
|             }
 | ||
| 
 | ||
|             # Similarly for SNMPv1 - noSuchName return results in both $iid
 | ||
|             # and $val being empty strings.
 | ||
|             if ( $val eq '' and $iid eq '' ) {
 | ||
|                 last;
 | ||
|             }
 | ||
| 
 | ||
|          # Another check for SNMPv1 - noSuchName return may results in an $iid
 | ||
|          # we've already seen and $val an empty string.  If we don't catch
 | ||
|          # this here we erronously report a loop below.
 | ||
|             if ( defined $seen{$iid} and $seen{$iid} and $val eq '' ) {
 | ||
|                 last;
 | ||
|             }
 | ||
| 
 | ||
|             if ($loopdetect) {
 | ||
| 
 | ||
|                 # Check to see if we've already seen this IID (looping)
 | ||
|                 if ( defined $seen{$iid} and $seen{$iid} ) {
 | ||
|                     $self->error_throw("Looping on: $method iid:$iid. ");
 | ||
|                     last;
 | ||
|                 }
 | ||
|                 else {
 | ||
|                     $seen{$iid}++;
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             if ( $val eq 'NOSUCHOBJECT' ) {
 | ||
|                 $self->error_throw(
 | ||
|                     "SNMP::Info::_load_attr: $method :  NOSUCHOBJECT");
 | ||
|                 next;
 | ||
|             }
 | ||
|             if ( $val eq 'NOSUCHINSTANCE' ) {
 | ||
|                 $self->error_throw(
 | ||
|                     "SNMP::Info::_load_attr: $method :  NOSUCHINSTANCE");
 | ||
|                 next;
 | ||
|             }
 | ||
| 
 | ||
|             $localstore->{$iid} = $val;
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         # Cache data if we are not getting partial data:
 | ||
|         if ( !defined $partial ) {
 | ||
|             $self->_cache($attr, $localstore);
 | ||
|         }
 | ||
| 
 | ||
|         # Data Munging
 | ||
|         if ( !$raw ) {
 | ||
|             $localstore = $self->_munge($attr, $localstore);
 | ||
|         }
 | ||
| 
 | ||
|         return $localstore;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->_show_attr()
 | ||
| 
 | ||
| Used internally by AUTOLOAD to return data called by methods listed in %FUNCS.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _show_attr {
 | ||
|     my $self = shift;
 | ||
|     my $attr = shift;
 | ||
|     my $raw  = shift;
 | ||
| 
 | ||
|     my $store = $self->store();
 | ||
| 
 | ||
|     if ( !$raw ) {
 | ||
|         my $localstore = $store->{$attr};
 | ||
|         return $self->_munge($attr, $localstore);
 | ||
|     }
 | ||
|     else {
 | ||
|         return $store->{$attr};
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->snmp_connect_ip(ip)
 | ||
| 
 | ||
| Returns true or false based upon snmp connectivity to an IP.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub snmp_connect_ip {
 | ||
|     my $self = shift;
 | ||
|     my $ip   = shift;
 | ||
|     my $ver  = $self->snmp_ver();
 | ||
|     my $comm = $self->snmp_comm();
 | ||
| 
 | ||
|     return if $self->{Offline};
 | ||
|     
 | ||
|     $ip = resolve_desthost($ip);
 | ||
|     return if ( $ip eq '0.0.0.0' ) or ( $ip =~ /^127\./ );
 | ||
| 
 | ||
|     # Create session object
 | ||
|     my $snmp_test = SNMP::Session->new(
 | ||
|         'DestHost'  => $ip,
 | ||
|         'Community' => $comm,
 | ||
|         'Version'   => $ver
 | ||
|     );
 | ||
| 
 | ||
|     # No session object created
 | ||
|     unless ( defined $snmp_test ) {
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     # Session object created but SNMP connection failed.
 | ||
|     my $sess_err = $snmp_test->{ErrorStr} || '';
 | ||
|     if ($sess_err) {
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     # Try to get some data from IP
 | ||
|     my $layers = $snmp_test->get('sysServices.0');
 | ||
| 
 | ||
|     $sess_err = $snmp_test->{ErrorStr} || '';
 | ||
|     if ($sess_err) {
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     return 1;
 | ||
| }
 | ||
| 
 | ||
| =item modify_port_list(portlist,offset,replacement)
 | ||
| 
 | ||
| Replaces the specified bit in a port_list array and
 | ||
| returns the packed bitmask
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub modify_port_list {
 | ||
|     my ( $self, $portlist, $offset, $replacement ) = @_;
 | ||
| 
 | ||
|     print "Original port list: @$portlist \n" if $self->debug();
 | ||
|     @$portlist[$offset] = $replacement;
 | ||
| 
 | ||
|     # Some devices do not populate the portlist with all possible ports.
 | ||
|     # If we have lengthened the list fill all undefined elements with zero.
 | ||
|     foreach my $item (@$portlist) {
 | ||
|         $item = '0' unless ( defined($item) );
 | ||
|     }
 | ||
|     print "Modified port list: @$portlist \n" if $self->debug();
 | ||
| 
 | ||
|     return pack( "B*", join( '', @$portlist ) );
 | ||
| }
 | ||
| 
 | ||
| =item $info->_cache(attr, data)
 | ||
| 
 | ||
| Cache retrieved data so that if it's asked for again, we use the cache instead
 | ||
| of going back to Net-SNMP. Data is cached inside the blessed hashref C<$self>.
 | ||
| 
 | ||
| Accepts the leaf and value (scalar, or hashref for a table). Does not return
 | ||
| anything useful.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _cache {
 | ||
|     my $self = shift;
 | ||
|     my ($attr, $data) = @_;
 | ||
|     my $store = $self->store();
 | ||
| 
 | ||
|     if (ref {} eq ref $data) {
 | ||
|         $self->{"_${attr}"}++;
 | ||
|         $store->{$attr} = $data;
 | ||
|     }
 | ||
|     else {
 | ||
|         $self->{"_$attr"} = $data;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item $info->_munge(attr, data)
 | ||
| 
 | ||
| Raw data returned from Net-SNMP might not be formatted correctly or might have
 | ||
| platform-specific bugs or mistakes. The MUNGE feature of SNMP::Info allows for
 | ||
| fixups to take place.
 | ||
| 
 | ||
| Accepts the leaf and value (scalar, or hashref for a table) and returns the raw
 | ||
| or the munged data, as appropriate. That is, you do not need to know whether
 | ||
| MUNGE is installed, and it's safe to call this method regardless.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _munge {
 | ||
|     my $self = shift;
 | ||
|     my ($attr, $data) = @_;
 | ||
|     my $munge = $self->munge();
 | ||
| 
 | ||
|     return $data unless defined $munge->{$attr};
 | ||
| 
 | ||
|     if (ref {} eq ref $data) {
 | ||
|         my $subref = $munge->{$attr};
 | ||
|         my %munged;
 | ||
|         foreach my $key ( keys %$data ) {
 | ||
|             my $value = $data->{$key};
 | ||
|             next unless defined $value;
 | ||
|             $munged{$key} = $subref->($value);
 | ||
|         }
 | ||
|         return \%munged;
 | ||
|     }
 | ||
|     else {
 | ||
|         return unless $data;
 | ||
|         my $subref = $munge->{$attr};
 | ||
|         return $subref->($data);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =item _validate_autoload_method(method)
 | ||
| 
 | ||
| Used internally by AUTOLOAD to validate that a dynamic method should be
 | ||
| created.  Returns the OID of the MIB leaf node the method will get or set.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item 1. Returns unless method is listed in %FUNCS, %GLOBALS, or is MIB Leaf
 | ||
| node name in a loaded MIB for given class.
 | ||
| 
 | ||
| =item 2. Translates the MIB Leaf node name to an OID.
 | ||
| 
 | ||
| =item 3. Checks to see if the method access type is allowed for the resolved
 | ||
| OID.  Write access for set_ methods, read access for others.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub _validate_autoload_method {
 | ||
|     my $self   = shift;
 | ||
|     my $method = shift;
 | ||
| 
 | ||
|     my $setter = $method =~ /^set/;
 | ||
|     my $attr = $method;
 | ||
|     $attr =~ s/^(load|set|orig)_//;
 | ||
|     $attr =~ s/_raw$//;
 | ||
| 
 | ||
|     my $globals = $self->globals();
 | ||
|     my $funcs   = $self->funcs();
 | ||
| 
 | ||
|     my $leaf_name = $globals->{$attr} || $funcs->{$attr} || $attr;
 | ||
| 
 | ||
|     # Check for fully qualified name
 | ||
|     if ( $leaf_name =~ /__/ ) {
 | ||
|         $leaf_name =~ s/__/::/;
 | ||
|         $leaf_name =~ s/_/-/g;
 | ||
|     }
 | ||
| 
 | ||
|     # skip if offline
 | ||
|     if ( $self->{Offline} ) {
 | ||
|         return [1,(exists $self->{store}->{$method} ? 1: 0)];
 | ||
|     }
 | ||
| 
 | ||
|     # Translate MIB leaf node name to OID
 | ||
|     my $oid = SNMP::translateObj($leaf_name);
 | ||
| 
 | ||
|     if ( $leaf_name =~ /^[.]?\d[\.\d]+$/ ) {
 | ||
|         $oid = $leaf_name;
 | ||
|     }
 | ||
| 
 | ||
|     unless ( defined $oid ) {
 | ||
|         print
 | ||
|             "SNMP::Info::_validate_autoload_method($leaf_name) Unable to resolve method.\n"
 | ||
|             if $self->debug();
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     # Validate that we have proper access for the operation
 | ||
|     my $access = '';
 | ||
|     
 | ||
|     # Prevent autovivification by checking that MIB leaf exists
 | ||
|     if (exists $SNMP::MIB{$oid}) {
 | ||
|         $access = $SNMP::MIB{$oid}{'access'} || '';
 | ||
|     }
 | ||
| 
 | ||
|     # If we were given a fully qualified OID because we don't have the MIB
 | ||
|     # file, it will translate above but we won't be able to check access so
 | ||
|     # skip the check and return
 | ||
|     if ($access && ($method =~ /^set/ && $access !~ /Write|Create/)
 | ||
|         || ($method !~ /^set/ && $access eq 'NoAccess')) {
 | ||
| 
 | ||
|             print
 | ||
|                 "SNMP::Info::_validate_autoload_method($attr : $oid) Not accessable for requested operation.\n"
 | ||
|                 if $self->debug();
 | ||
|             return;
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|      my $table_leaf = 0;
 | ||
|  
 | ||
|     # This is an expensive check so we assume anything in the funcs and globals
 | ||
|     # hashes are known. Only for actual MIB leafs should we have to check the
 | ||
|     # MIB. If the parent of the leaf has indexes it is contained within a table.   
 | ||
|     if ($funcs->{$attr}) {
 | ||
|       $table_leaf = 1;
 | ||
|      }
 | ||
|     elsif (!$globals->{$attr}) {
 | ||
| 
 | ||
|         # Prevent autovivification 
 | ||
|         if (exists $SNMP::MIB{$oid} &&
 | ||
|             exists $SNMP::MIB{$oid}{'parent'} &&
 | ||
|             exists $SNMP::MIB{$oid}{'parent'}{'indexes'} &&
 | ||
|             defined $SNMP::MIB{$oid}{'parent'}{'indexes'} &&
 | ||
|             scalar( @{$SNMP::MIB{$oid}{'parent'}{'indexes'}} ) > 0)
 | ||
|         {
 | ||
|             $table_leaf = 1;    
 | ||
|         }
 | ||
|      }
 | ||
| 
 | ||
|     # Tag on .0 for %GLOBALS and single instance MIB leafs unless
 | ||
|     # the leaf ends in a digit or we are going to use for a set operation
 | ||
|     if ( $table_leaf == 0 && ( $globals->{$attr} || $leaf_name ne $oid ) ) {
 | ||
| 
 | ||
|         unless ( $leaf_name =~ /\d$/ || $setter ) {
 | ||
|             $oid .= ".0";
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     my $return = [ $oid, $table_leaf ];
 | ||
|     return $return;
 | ||
| }
 | ||
| 
 | ||
| =item $info->can()
 | ||
| 
 | ||
| Overrides UNIVERSAL::can() so that objects will correctly report their
 | ||
| capabilities to include dynamic methods generated at run time via AUTOLOAD.
 | ||
| 
 | ||
| Calls parent can() first to see if method exists, if not validates that a
 | ||
| method should be created then dispatches to the appropriate internal method
 | ||
| for creation.  The newly created method is inserted into the symbol table
 | ||
| returning to AUTOLOAD only for the initial method call.
 | ||
| 
 | ||
| Returns undef if the method does not exist and can not be created.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| sub can {
 | ||
|     my $self   = shift;
 | ||
|     my $method = shift;
 | ||
| 
 | ||
|     # use results of parent can()
 | ||
|     return $self->SUPER::can($method) if $self->SUPER::can($method);
 | ||
| 
 | ||
|     return if $method eq 'CARP_TRACE';
 | ||
| 
 | ||
|     my $validated = $self->_validate_autoload_method($method);
 | ||
|     return unless $validated;
 | ||
| 
 | ||
|     my ($oid, $table) = @$validated;
 | ||
| 
 | ||
|     # _validate_autoload_method validates, so we need to check for
 | ||
|     # set_ , funcs, table leafs, and everything else goes to _global
 | ||
|     my $funcs = $self->funcs();
 | ||
| 
 | ||
|     # We need to resolve funcs with a prefix or suffix
 | ||
|     my $base_method = $method;
 | ||
|     $base_method =~ s/^(load|orig)_//;
 | ||
|     $base_method =~ s/_raw$//;
 | ||
| 
 | ||
|     no strict 'refs';    ## no critic (ProhibitNoStrict )
 | ||
| 
 | ||
|     # We could add load_/orig_/_raw alternatives to symbol table here on
 | ||
|     # first call of any type for a global or func since they all use the same
 | ||
|     # destination code, but they aren't used heavily in main code base so
 | ||
|     # we’ll just create if/when they are called rather than pollute the
 | ||
|     # symbol table with entries that never get called.
 | ||
| 
 | ||
|     # Check for set_ ing.
 | ||
|     if ( $method =~ /^set_/ ) {
 | ||
|         return *{$method} = _make_setter( $method, $oid, @_ );
 | ||
|     }
 | ||
|     elsif ( defined $funcs->{$base_method} || $table ) {
 | ||
|         return *{$method} = _load_attr( $method, $oid, @_ );
 | ||
|     }
 | ||
|     else {
 | ||
|         return *{$method} = _global( $method, $oid );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| =head2 AUTOLOAD
 | ||
| 
 | ||
| Each entry in either %FUNCS, %GLOBALS, or MIB Leaf node names present in
 | ||
| loaded MIBs are used by AUTOLOAD() to create dynamic methods.  Generated
 | ||
| methods are inserted into the symbol table so that subsequent calls can avoid
 | ||
| AUTOLOAD() and dispatch directly.
 | ||
| 
 | ||
| =over
 | ||
| 
 | ||
| =item 1. Returns unless method is listed in %FUNCS, %GLOBALS, or is a MIB
 | ||
| Leaf node name in a loaded MIB for given class.
 | ||
| 
 | ||
| =item 2. If the method exists in %GLOBALS or is a single instance MIB Leaf
 | ||
| node name from a loaded MIB, _global() generates the method.
 | ||
| 
 | ||
| =item 3. If a set_ prefix is present _make_setter() generates the method.
 | ||
| 
 | ||
| =item 4. If the method exists in %FUNCS or is a MIB Leaf node name contained
 | ||
| within a table from a loaded MIB, _load_attr() generates the method.
 | ||
| 
 | ||
| =item 5. A load_ prefix forces reloading of data and does not use cached data.
 | ||
| 
 | ||
| =item 6. A _raw suffix returns data ignoring any munge routines.
 | ||
| 
 | ||
| =back
 | ||
| 
 | ||
| Override any dynamic method listed in %GLOBALS, %FUNCS, or MIB Leaf node
 | ||
| name a by creating a subroutine with the same name.
 | ||
| 
 | ||
| For example to override $info->name() create `` sub name {...}'' in your
 | ||
| subclass.
 | ||
| 
 | ||
| =cut
 | ||
| 
 | ||
| our $AUTOLOAD;
 | ||
| 
 | ||
| sub AUTOLOAD {
 | ||
|     my $self = shift;
 | ||
|     my ($sub_name) = $AUTOLOAD =~ /::(\w+)$/;
 | ||
| 
 | ||
|    return if $sub_name eq 'CARP_TRACE';
 | ||
| 
 | ||
|     # Typos in function calls in SNMP::Info subclasses turn into
 | ||
|     # AUTOLOAD requests for non-methods.  While this is deprecated,
 | ||
|     # we'll still get called, so report a less confusing error.
 | ||
|     if ( ref($self) !~ /SNMP::Info/ ) {
 | ||
| 
 | ||
|         # croak reports one level too high.  die reports here.
 | ||
|         # I would really like to get the place that's likely to
 | ||
|         # have the typo, but perl doesn't want me to.
 | ||
|         croak(
 | ||
|             "SNMP::Info::AUTOLOAD($AUTOLOAD) called with no class (probably typo of function call to $sub_name)"
 | ||
|         );
 | ||
|     }
 | ||
| 
 | ||
|     # This enables us to use SUPER:: for AUTOLOAD methods as well
 | ||
|     # as the true OO methods.  Method needs to be renamed to prevent
 | ||
|     # namespace collision when we insert into the symbol table later.
 | ||
|     if ( $AUTOLOAD =~ /SUPER::$sub_name$/ ) {
 | ||
|         $AUTOLOAD =~ s/SUPER::$sub_name/orig_$sub_name/;
 | ||
|         $sub_name = "orig_$sub_name";
 | ||
|     }
 | ||
| 
 | ||
|     return unless my $meth_ref = $self->can($sub_name, @_);
 | ||
|     return $self->$meth_ref(@_);
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| # Skip AUTOLOAD()
 | ||
| sub DESTROY {}
 | ||
| 
 | ||
| 1;
 | ||
| 
 | ||
| =head1 COPYRIGHT AND LICENSE
 | ||
| 
 | ||
| Changes from SNMP::Info Version 0.7 and on are:
 | ||
| Copyright (c) 2003-2010 Max Baker and SNMP::Info Developers
 | ||
| All rights reserved.
 | ||
| 
 | ||
| Original Code is:
 | ||
| Copyright (c) 2002-2003, Regents of the University of California
 | ||
| All rights reserved.
 | ||
| 
 | ||
| Redistribution and use in source and binary forms, with or without
 | ||
| modification, are permitted provided that the following conditions are met:
 | ||
| 
 | ||
|     * Redistributions of source code must retain the above copyright notice,
 | ||
|       this list of conditions and the following disclaimer.
 | ||
|     * Redistributions in binary form must reproduce the above copyright
 | ||
|       notice, this list of conditions and the following disclaimer in the
 | ||
|       documentation and/or other materials provided with the distribution.
 | ||
|     * Neither the name of the University of California, Santa Cruz nor the
 | ||
|       names of its contributors may be used to endorse or promote products
 | ||
|       derived from this software without specific prior written permission.
 | ||
| 
 | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | ||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | ||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | ||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 | ||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | ||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | ||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | ||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | ||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||
| 
 | ||
| =cut
 |