diff --git a/ChangeLog b/ChangeLog index 64028905..170266c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,36 @@ SNMP::Info - Friendly OO-style interface to Network devices using SNMP. +version 3.00 + + [API Changes] + * AUTOLOAD no longer tries to determine if a MIB leaf is a single + instance or part of a table. As a result all MIB leafs provided as a + method call to be resolved by AUTOLOAD return data as a reference to + a hash with the instance id as the key and the data as the value. If + you would rather a scalar be returned you must define within %GLOBALS. + * The methods c_ip(), c_if(), c_port(), c_id(), and c_platform() now + represent common topology methods and will try to return a combined + hash of data from all L2 topology protocols either running on the + device or specified in the method call. The topology specific methods + have been been prefixed with the protocol name in lowercase so that + they can be called directly, sonmp_ip(), cdp_ip(), etc. + + [NEW FEATURES] + + * [3160037] - Support _raw suffix on methods to skip munging + * Support for Avaya VSP 9000 series in L3::Passport + * Support for Avaya VSP 7000 series in L2::Baystack + * Support Avaya (Trapeze) Wireless Controllers in new class L2::NWSS2300 + + [ENHANCEMENTS] + + * UNIVERSAL::can() now works with dynamic methods + * Dynamically generated methods to symbol table to avoid + AUTOLOAD on subsequent calls + + [BUG FIXES] + + version 2.09 (2012-11-28) [NEW FEATURES] diff --git a/Info.pm b/Info.pm index e6ed8503..bc5cd4a1 100644 --- a/Info.pm +++ b/Info.pm @@ -10,6 +10,7 @@ package SNMP::Info; +use warnings; use strict; use Exporter; use SNMP; @@ -492,10 +493,10 @@ Depreciated. Use BayStack. =item SNMP::Info::Layer2::Baystack -Subclass for Nortel/Bay Ethernet Switch/Baystack switches. This includes 303, -304, 350, 380, 410, 420, 425, 450, 460, 470 series, 2500 series, 4500 series, -5500 series, Business Ethernet Switch (BES), Business Policy Switch (BPS) -and probably others. +Subclass for Avaya/Nortel/Bay Ethernet Switch/Baystack switches. This +includes 303, 304, 350, 380, 410, 420, 425, 450, 460, 470 series, +2500 series, 4500 series, 5500 series, Business Ethernet Switch (BES), +Business Policy Switch (BPS), VSP 7000 series, and probably others. See documentation in L for details. @@ -580,6 +581,12 @@ Subclass for Netgear switches See documentation in L for details. +=item SNMP::Info::Layer2::NWSS2300 + +SNMP Interface to Avaya (Trapeze) Wireless Controllers + +See documentation in L for details. + =item SNMP::Info::Layer2::Orinoco Subclass for Orinoco/Proxim wireless access points. @@ -989,7 +996,7 @@ sub new { # load references to all the subclass data structures { - no strict 'refs'; ## no critic + no strict 'refs'; ## no critic (ProhibitNoStrict ProhibitProlongedStrictureOverride) $new_obj->{init} = \${ $class . '::INIT' }; $new_obj->{mibs} = \%{ $class . '::MIBS' }; $new_obj->{globals} = \%{ $class . '::GLOBALS' }; @@ -1288,6 +1295,7 @@ sub device_type { 11 => 'SNMP::Info::Layer2::HP', 18 => 'SNMP::Info::Layer3::BayRS', 42 => 'SNMP::Info::Layer3::Sun', + 45 => 'SNMP::Info::Layer2::Baystack', 171 => 'SNMP::Info::Layer3::Dell', 311 => 'SNMP::Info::Layer3::Microsoft', 674 => 'SNMP::Info::Layer3::Dell', @@ -1313,6 +1321,7 @@ sub device_type { my %l2sysoidmap = ( 9 => 'SNMP::Info::Layer2::Cisco', 11 => 'SNMP::Info::Layer2::HP', + 45 => 'SNMP::Info::Layer2::Baystack', 171 => 'SNMP::Info::Layer3::Dell', 207 => 'SNMP::Info::Layer2::Allied', 674 => 'SNMP::Info::Layer3::Dell', @@ -1596,6 +1605,10 @@ sub device_type { $objtype = 'SNMP::Info::Layer2::HPVC' if ( $desc =~ /HP\sVC\s/ ); + # Nortel (Trapeze) WSS 2300 Series + $objtype = 'SNMP::Info::Layer2::NWSS2300' + if ( $desc =~ /\bWireless\sSecurity\sSwitch\s23[568][012]\b/); + # Generic device classification based upon sysObjectID if ( defined($id) and $objtype eq 'SNMP::Info') { if ( defined $l3sysoidmap{$id} ) { @@ -1857,6 +1870,17 @@ sub if_ignore { 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. @@ -2263,6 +2287,249 @@ Reference to MIB definition specific to routing protocol. =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), and Extreme Discovery +Protocol (EDP). + +For protocol specific information and implementation: + +=over + +=item LLDP: See L for details. + +=item CDP: See L for details. + +=item SONMP: See L for details. + +=item FDP: See L for details. + +=item EDP: See L for details. + +=back + +=head3 Topology Capabilties + +$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: 'lldp', 'cdp, 'sonmp', 'fdp','edp' or 'undef' if no protocols are +supported or running. + +=cut + +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(); + + 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)/; + + my %t_data; + foreach my $proto (@$topo_cap) { + next unless $proto =~ /(lldp|cdp|sonmp|fdp|edp)/; + 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: +'lldp', 'cdp, 'sonmp', 'fdp','edp' + +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: LLDP and EDP do not provide this information. + +=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'); +} + +=back + =head1 SETTING DATA VIA SNMP This section explains how to use SNMP::Info to do SNMP Set operations. @@ -3139,96 +3406,88 @@ sub store { =item $info->_global() -Used internally by AUTOLOAD to load dynamic methods from %GLOBALS. +Used internally by AUTOLOAD to create dynamic methods from %GLOBALS. -Example: $info->name() calls autoload which calls $info->_global('name'). +Example: $info->name() on the first call dispatches to AUTOLOAD() which +calls $info->_global('name') creating the method name(). =cut sub _global { - my $self = shift; - my $attr = shift; - my $sess = $self->session(); - return unless defined $sess; + my $method = shift; + my $oid = shift; - my $globals = $self->globals(); + return sub { + my $self = shift; - my $oid; - if ( exists $globals->{$attr} ) { - $oid = $globals->{$attr}; - unless ( $oid =~ /\.\d+$/ ) { - $oid .= ".0"; + 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$//; + + # Get the callback hash for data munging + my $munge = $self->munge(); + + # Return cached data unless loading + # We now store in raw format so munge before returning + # unless expecting raw data + if ( defined $self->{"_$attr"} && !$load ) { + if ( defined $munge->{$attr} && !$raw ) { + my $val = $self->{"_$attr"}; + my $subref = $munge->{$attr}; + return &$subref($val); + } else{ + return $self->{"_$attr"}; + } } - # Check for fully qualified attr - if ( $oid =~ /__/ ) { - $oid =~ s/__/::/; - $oid =~ s/_/-/g; + print "SNMP::Info::_global $method : $oid\n" if $self->debug(); + my $val = $sess->get($oid); - # Need to translate fully qualified attr to full oid - $oid = &SNMP::translateObj($oid); - unless ( defined $oid ) { - $self->error_throw( - "SNMP::Info::_load_attr: Can't translate $globals->{$attr}. Missing MIB?\n" - ); - return; - } + # 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->{"_$attr"} = $val; + + # Data Munging + if ( defined $munge->{$attr} && !$raw ) { + my $subref = $munge->{$attr}; + $val = &$subref($val); + } + + return $val; } - else { - $oid = $attr; - } - - # Tag on .0 unless the leaf ends in .number - unless ( $oid =~ /\.\d+$/ ) { - $oid .= ".0"; - } - - print "SNMP::Info::_global $attr : $oid\n" if $self->debug(); - 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($attr) $sess->{ErrorStr}"); - return; - } - - if ( defined $val and $val eq 'NOSUCHOBJECT' ) { - $self->error_throw("SNMP::Info::_global($attr) NOSUCHOBJECT"); - return; - } - - if ( defined $val and $val eq 'NOSUCHINSTANCE' ) { - $self->error_throw("SNMP::Info::_global($attr) NOSUCHINSTANCE"); - return; - } - - # Get the callback hash for data munging - my $munge = $self->munge(); - - # Data Munging - if ( defined $munge->{$attr} ) { - my $subref = $munge->{$attr}; - $val = &$subref($val); - } - - # Save Cached Value - $self->{"_$attr"} = $val; - - return $val; } =item $info->_set(attr,val,iid,type) -Used internally by AUTOLOAD to run an SNMP set command for dynamic methods -listed in either %GLOBALS or %FUNCS or a valid mib leaf from a loaded MIB or -the set_multi() method to set multiple variable in one command. When run +Used internally by set_multi() to run an SNMP set command. When run clears attr cache. -Attr is passed as either a scalar for dynamic methods or a reference to an -array or array of arrays when used with set_multi(). +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); @@ -3316,6 +3575,50 @@ sub _set { 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; + + $iid = defined $iid ? $iid : '.0'; + + # prepend dot if necessary to $iid + $iid = ".$iid" unless $iid =~ /^\./; + + my $sess = $self->session(); + return unless defined $sess; + + $oid .= $iid; + + $self->debug() + and print "SNMP::Info::_set $method$iid ($oid) = $val\n"; + delete $self->{"_$method"}; + + my $rv = $sess->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. @@ -3409,212 +3712,215 @@ sub all { =item $info->_load_attr() -Used internally by AUTOLOAD to fetch data called from methods listed in %FUNCS -or a MIB Leaf node name. +Used internally by AUTOLOAD to create dynamic methods from %FUNCS +or a MIB Leaf node name which fetches data. Supports partial table fetches and single instance table fetches. See L. -Called from $info->load_METHOD(); - =cut sub _load_attr { - my $self = shift; - my ( $attr, $leaf, $partial ) = @_; + my $method = shift; + my $oid = shift; - my $ver = $self->snmp_ver(); - my $nosuch = $self->nosuch(); - my $sess = $self->session(); - my $store = $self->store(); - my $munge = $self->munge(); - return unless defined $sess; + return sub { + my $self = shift; + my $partial = shift; - my $varleaf = $leaf; + my $sess = $self->session(); + return unless defined $sess; - # Check for fully qualified attr - if ( $leaf =~ /__/ ) { - $leaf =~ s/__/::/; - $leaf =~ s/_/-/g; - $varleaf = $leaf; - } + my $ver = $self->snmp_ver(); + my $nosuch = $self->nosuch(); + my $store = $self->store(); + my $munge = $self->munge(); - # Deal with partial entries. - if ( defined $partial ) { + my $load = $method =~ /^load/; + my $raw = $method =~ /raw$/; - # If we aren't supplied an OID translate - if ( $leaf !~ /^[.\d]*$/ ) { + my $attr = $method; + $attr =~ s/^(load|orig)_//; + $attr =~ s/_raw$//; - # VarBind will not resolve mixed OID and leaf entries like - # "ipRouteMask.255.255". So we convert to full OID - my $oid = &SNMP::translateObj($leaf); - unless ( defined $oid ) { + # 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 ); + + my $leaf_name = SNMP::translateObj($oid) || ''; + my $varleaf = defined $partial ? "$oid.$partial" : "$oid"; + + $self->debug() + and print "SNMP::Info::_load_attr $method : $oid", + defined $partial ? "($partial)" : '', "\n"; + + my $var = new SNMP::Varbind( [$varleaf] ); + + # 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: Can't translate $leaf.$partial. Missing MIB?\n" - ); + "SNMP::Info::_load_atrr: BULKWALK " . $sess->{ErrorStr}, + "\n" ); return; } - $varleaf = "$oid.$partial"; - } - else { - $varleaf = "$leaf.$partial"; - } - } - - $self->debug() - and print "SNMP::Info::_load_attr $attr : $leaf", - defined $partial ? "($partial / $varleaf)" : '', "\n"; - - my $var = new SNMP::Varbind( [$varleaf] ); - - # 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_atrr: 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 $attr : leaf = $leaf , var = ", - Dumper($var); - } - - # Check if we've left the requested subtree - last if $var->[0] ne $leaf; - my $iid = $var->[1]; - my $val = $var->[2]; - - unless ( defined $iid ) { - $self->error_throw("SNMP::Info::_load_attr: $attr 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: $attr iid:$iid. "); - last; + while ( !$errornum ) { + if ($bulkwalk) { + $var = shift @$vars or last; } else { - $seen{$iid}++; + + # 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] ne $leaf_name; + 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; + } - if ( $val eq 'NOSUCHOBJECT' ) { - $self->error_throw( - "SNMP::Info::_load_attr: $attr : NOSUCHOBJECT"); - next; - } - if ( $val eq 'NOSUCHINSTANCE' ) { - $self->error_throw( - "SNMP::Info::_load_attr: $attr : NOSUCHINSTANCE"); - next; + # Cache data if we are not getting partial data: + if ( !defined $partial ) { + $self->{"_${attr}"}++; + $store->{$attr} = $localstore; } # Data Munging - # Checks for an entry in %munge and runs the subroutine - if ( defined $munge->{$attr} ) { + # Checks for an entry in %munge and munges values unless we expect + # raw data + if ( defined $munge->{$attr} && !$raw ) { my $subref = $munge->{$attr}; - $val = &$subref($val); + my %munged; + foreach my $key ( keys %$localstore ) { + my $value = $localstore->{$key}; + next unless $key; + my $munged_value = &$subref($value); + $munged{$key} = $munged_value; + } + return \%munged; } - - $localstore->{$iid} = $val; + return $localstore; } - - # Cache data if we are not getting partial data: - if ( !defined $partial ) { - $self->{"_${attr}"}++; - $store->{$attr} = $localstore; - } - - return $localstore; } =item $info->_show_attr() @@ -3631,10 +3937,28 @@ Every time after it will return cached data. sub _show_attr { my $self = shift; my $attr = shift; + my $raw = shift; my $store = $self->store(); - return $store->{$attr}; + # Get the callback hash for data munging + my $munge = $self->munge(); + + if ( defined $munge->{$attr} && !$raw ) { + my $localstore = $store->{$attr}; + my $subref = $munge->{$attr}; + my %munged; + foreach my $key ( keys %$localstore ) { + my $value = $localstore->{$key}; + next unless $key; + my $munged_value = &$subref($value); + $munged{$key} = $munged_value; + } + return \%munged; + } + else { + return $store->{$attr}; + } } =item $info->snmp_connect_ip(ip) @@ -3704,43 +4028,170 @@ sub modify_port_list { return pack( "B*", join( '', @$portlist ) ); } -=back +=item _validate_autoload_method(method) -=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. - -Note that this AUTOLOAD is going to be run for all the classes listed in the -@ISA array in a subclass, so will be called with a variety of package names. -We check the %FUNCS and %GLOBALS of the package that is doing the calling at -this given instant. +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. Checks for load_ prefix and if present runs $info->_global(method) -for methods which exist in %GLOBALS or are a single instance MIB Leaf node -name, otherwise runs $info->_load_attr(method) for methods which exist in -%FUNCS or are MIB Leaf node name contained within a table. This always -forces reloading and does not use cached data. +=item 2. Translates the MIB Leaf node name to an OID. -=item 3. Check for set_ prefix and if present runs $info->_set(method). - -=item 4. If the method exists in %GLOBALS or is a single instance MIB Leaf -node name it runs $info->_global(method) unless already cached. - -=item 5. If the method exists in %FUNCS or is MIB Leaf node name contained -within a table it runs $info->_load_attr(method) if not cached. - -=item 6. Otherwise return $info->_show_attr(method). +=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 -Override any dynamic method listed in one of these hashes by creating a -subroutine with the same name. +=cut + +sub _validate_autoload_method { + my $self = shift; + my $method = shift; + + 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; + } + + if ($leaf_name && $globals->{$attr}) { + # Tag on .0 unless the leaf ends in a digit + unless ( $leaf_name =~ /\d$/ ) { + $leaf_name .= ".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 = $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) { + if ( $method =~ /^set/ && $access =~ /Write|Create/ ) { + return $oid; + } + elsif ( $access =~ /Read|Create/ ) { + return $oid; + } + else { + print + "SNMP::Info::_validate_autoload_method($attr : $oid) Not accessable for requested operation.\n" + if $self->debug(); + return; + } + } + return $oid; +} + +=item $info->can() + +Overrides UNIVERSAL::can() so that objects will correctly report thier +capabilities to include dynamic methods generated at runtime 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 inital 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() + my $meth_ref = $self->SUPER::can($method); + + # Don't return if passed $super as it means we were called + # from AUTOLOAD for a method that hasn't been generated yet. + if ($meth_ref) { + return $meth_ref + unless ( defined $AUTOLOAD && $AUTOLOAD =~ /SUPER::$method$/ ); + } + + my $oid = $self->_validate_autoload_method($method); + return unless $oid; + + # _validate_autoload_method validates, so we need to check for + # set_ , globals, and everything else goes to _load_attr + my $globals = $self->globals(); + + # We need to resolve globals with a prefix or suffix + my $g_method = $method; + $g_method =~ s/^(load|orig)_//; + $g_method =~ s/_raw$//; + + no strict 'refs'; ## no critic (ProhibitNoStrict ) + + # Check for set_ ing. + if ( $method =~ /^set_/ ) { + return *{$method} = _make_setter( $method, $oid, @_ ); + } + elsif ( defined $globals->{$g_method} ) { + return *{$method} = _global( $method, $oid ); + } + else { + return *{$method} = _load_attr( $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 MIB Leaf +node name in a loaded MIB for given class. + +=item 2. If the method exists in %GLOBALS, _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 MIB Leaf node name in 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. @@ -3748,20 +4199,11 @@ subclass. =cut sub AUTOLOAD { - my $self = shift; - my $sub_name = $AUTOLOAD; + my $self = shift; + my ($sub_name) = $AUTOLOAD =~ /::(\w+)$/; return if $sub_name =~ /DESTROY$/; - # package is the first part - ( my $package = $sub_name ) =~ s/[^:]*$//; - - # Sub name is the last part - $sub_name =~ s/.*://; - - # Enable calls to SUPER class to find autoloaded methods - $package =~ s/SUPER::$//; - # 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. @@ -3775,97 +4217,9 @@ sub AUTOLOAD { ); } - my $attr = $sub_name; - $attr =~ s/^(load|set)_//; - $attr =~ s/^orig_//; + return unless my $meth_ref = $self->can($sub_name, @_); + return $self->$meth_ref(@_); - # Let's use the %GLOBALS and %FUNCS from the class that - # inherited us. - my ( %funcs, %globals ); - { - no strict 'refs'; ## no critic - %funcs = %{ $package . 'FUNCS' }; - %globals = %{ $package . 'GLOBALS' }; - } - - # Check if we were called with a MIB leaf node name - my $trans = SNMP::translateObj($attr); - - my $mib_leaf = 0; - my $table_leaf = 0; - if ( defined($trans) ) { - my $mib = $SNMP::MIB{$trans}; - - # We're not a leaf if we don't have access attribute - # Don't bother if not-accessable - my $access = $$mib{'access'}; - $mib_leaf = 1 if ( defined $access && $access !~ /NoAccess/ ); - if ( $self->debug() and !$mib_leaf ) { - print "SNMP::Info::AUTOLOAD($attr) Leaf not accessable.\n"; - } - - # If we're a leaf check to see if we are in a table - if ($mib_leaf) { - my $indexes = $$mib{'parent'}{'indexes'}; - $table_leaf = 1 - if ( defined $indexes && scalar( @{$indexes} ) > 0 ); - } - } - - unless ( defined $funcs{$attr} - or defined $globals{$attr} - or defined $mib_leaf ) - { - $self->error_throw( - "SNMP::Info::AUTOLOAD($attr) Attribute not found in this device class." - ); - return; - } - - # Check for load_ ing. - if ( $sub_name =~ /^load_/ ) { - if ( defined $globals{$attr} ) { - return $self->_global($attr); - } - if ( defined $funcs{$attr} ) { - return $self->_load_attr( $attr, $funcs{$attr}, @_ ); - } - if ( $mib_leaf and !$table_leaf ) { - return $self->_global($attr); - } - if ($table_leaf) { - return $self->_load_attr( $attr, $attr, @_ ); - } - } - - # Check for set_ ing. - if ( $sub_name =~ /^set_/ ) { - return $self->_set( $attr, @_ ); - } - - # Next check for entry in %GLOBALS - if ( defined $globals{$attr} or ( $mib_leaf and !$table_leaf ) ) { - - # Return Cached Value if exists - return $self->{"_${attr}"} if exists $self->{"_${attr}"}; - - # Fetch New Value - return $self->_global($attr); - } - - # Otherwise we must be listed in %FUNCS - - # Load data if it both not cached and we are not requesting partial info. - if ( defined $funcs{$attr} ) { - return $self->_load_attr( $attr, $funcs{$attr}, @_ ) - unless ( defined $self->{"_${attr}"} and !defined $_[0] ); - } - if ($table_leaf) { - return $self->_load_attr( $attr, $attr, @_ ) - unless ( defined $self->{"_${attr}"} and !defined $_[0] ); - } - - return $self->_show_attr($attr); } 1; diff --git a/Info/CDP.pm b/Info/CDP.pm index 7160acce..53cfdd34 100644 --- a/Info/CDP.pm +++ b/Info/CDP.pm @@ -53,37 +53,37 @@ $VERSION = '2.09'; 'cdp_run' => 'cdpGlobalRun', 'cdp_interval' => 'cdpGlobalMessageInterval', 'cdp_holdtime' => 'cdpGlobalHoldTime', - 'cdp_id' => 'cdpGlobalDeviceId', + 'cdp_gid' => 'cdpGlobalDeviceId', ); %FUNCS = ( - 'c_index' => 'cdpCacheIfIndex', - 'c_proto' => 'cdpCacheAddressType', - 'c_addr' => 'cdpCacheAddress', - 'c_ver' => 'cdpCacheVersion', - 'c_id' => 'cdpCacheDeviceId', - 'c_port' => 'cdpCacheDevicePort', - 'c_platform' => 'cdpCachePlatform', - 'c_capabilities' => 'cdpCacheCapabilities', - 'c_domain' => 'cdpCacheVTPMgmtDomain', - 'c_vlan' => 'cdpCacheNativeVLAN', - 'c_duplex' => 'cdpCacheDuplex', - 'c_power' => 'cdpCachePowerConsumption', - 'c_pri_mgmt_type'=> 'cdpCachePrimaryMgmtAddrType', - 'c_pri_mgmt_addr'=> 'cdpCachePrimaryMgmtAddr', - 'c_sec_mgmt_type'=> 'cdpCacheSecondaryMgmtAddrType', - 'c_sec_mgmt_addr'=> 'cdpCacheSecondaryMgmtAddr', + 'cdp_index' => 'cdpCacheIfIndex', + 'cdp_proto' => 'cdpCacheAddressType', + 'cdp_addr' => 'cdpCacheAddress', + 'cdp_ver' => 'cdpCacheVersion', + 'cdp_id' => 'cdpCacheDeviceId', + 'cdp_port' => 'cdpCacheDevicePort', + 'cdp_platform' => 'cdpCachePlatform', + 'cdp_capabilities' => 'cdpCacheCapabilities', + 'cdp_domain' => 'cdpCacheVTPMgmtDomain', + 'cdp_vlan' => 'cdpCacheNativeVLAN', + 'cdp_duplex' => 'cdpCacheDuplex', + 'cdp_power' => 'cdpCachePowerConsumption', + 'cdp_pri_mgmt_type'=> 'cdpCachePrimaryMgmtAddrType', + 'cdp_pri_mgmt_addr'=> 'cdpCachePrimaryMgmtAddr', + 'cdp_sec_mgmt_type'=> 'cdpCacheSecondaryMgmtAddrType', + 'cdp_sec_mgmt_addr'=> 'cdpCacheSecondaryMgmtAddr', ); %MUNGE = ( - 'c_capabilities' => \&SNMP::Info::munge_caps, - 'c_platform' => \&SNMP::Info::munge_null, - 'c_domain' => \&SNMP::Info::munge_null, - 'c_port' => \&SNMP::Info::munge_null, - 'c_id' => \&SNMP::Info::munge_null, - 'c_ver' => \&SNMP::Info::munge_null, - 'c_ip' => \&SNMP::Info::munge_ip, - 'c_power' => \&munge_power, + 'cdp_capabilities' => \&SNMP::Info::munge_caps, + 'cdp_platform' => \&SNMP::Info::munge_null, + 'cdp_domain' => \&SNMP::Info::munge_null, + 'cdp_port' => \&SNMP::Info::munge_null, + 'cdp_id' => \&SNMP::Info::munge_null, + 'cdp_ver' => \&SNMP::Info::munge_null, + 'cdp_ip' => \&SNMP::Info::munge_ip, + 'cdp_power' => \&munge_power, ); @@ -101,63 +101,63 @@ sub hasCDP { # SNMP v1 clients dont have the globals if ( defined $ver and $ver == 1 ) { - my $c_ip = $cdp->c_ip(); + my $cdp_ip = $cdp->cdp_ip(); # See if anything in cdp cache, if so we have cdp - return 1 if ( defined $c_ip and scalar( keys %$c_ip ) ); + return 1 if ( defined $cdp_ip and scalar( keys %$cdp_ip ) ); return; } return $cdp->cdp_run(); } -sub c_if { +sub cdp_if { my $cdp = shift; # See if by some miracle Cisco implemented the cdpCacheIfIndex entry - my $c_index = $cdp->c_index(); - return $c_index if defined $c_index; + my $cdp_index = $cdp->cdp_index(); + return $cdp_index if defined $cdp_index; # Nope, didn't think so. Now we fake it. - my $c_ip = $cdp->c_ip(); - unless ( defined $c_ip ) { + my $cdp_ip = $cdp->cdp_ip(); + unless ( defined $cdp_ip ) { $cdp->error_throw( - "SNMP::Info::CDP:c_if() - Device doesn't have cdp_ip() data. Can't fake cdp_index()" + "SNMP::Info::CDP:cdp_if() - Device doesn't have cdp_ip() data. Can't fake cdp_index()" ); return; } - my %c_if; - foreach my $key ( keys %$c_ip ) { + my %cdp_if; + foreach my $key ( keys %$cdp_ip ) { next unless defined $key; my $iid = $key; # Truncate .1 from cdp cache entry $iid =~ s/\.\d+$//; - $c_if{$key} = $iid; + $cdp_if{$key} = $iid; } - return \%c_if; + return \%cdp_if; } -sub c_ip { +sub cdp_ip { my $cdp = shift; my $partial = shift; - my $c_addr = $cdp->c_addr($partial) || {}; - my $c_proto = $cdp->c_proto($partial) || {}; + my $cdp_addr = $cdp->cdp_addr($partial) || {}; + my $cdp_proto = $cdp->cdp_proto($partial) || {}; - my %c_ip; - foreach my $key ( keys %$c_addr ) { - my $addr = $c_addr->{$key}; - my $proto = $c_proto->{$key}; + my %cdp_ip; + foreach my $key ( keys %$cdp_addr ) { + my $addr = $cdp_addr->{$key}; + my $proto = $cdp_proto->{$key}; next unless defined $addr; next if ( defined $proto and $proto ne 'ip' ); my $ip = join( '.', unpack( 'C4', $addr ) ); - $c_ip{$key} = $ip; + $cdp_ip{$key} = $ip; } - return \%c_ip; + return \%cdp_ip; } 1; @@ -188,15 +188,15 @@ Max Baker # Print out a map of device ports with CDP neighbors: my $interfaces = $cdp->interfaces(); - my $c_if = $cdp->c_if(); - my $c_ip = $cdp->c_ip(); - my $c_port = $cdp->c_port(); + my $cdp_if = $cdp->cdp_if(); + my $cdp_ip = $cdp->cdp_ip(); + my $cdp_port = $cdp->cdp_port(); - foreach my $cdp_key (keys %$c_ip){ - my $iid = $c_if->{$cdp_key}; + foreach my $cdp_key (keys %$cdp_ip){ + my $iid = $cdp_if->{$cdp_key}; my $port = $interfaces->{$iid}; - my $neighbor = $c_ip->{$cdp_key}; - my $neighbor_port = $c_port->{$cdp_key}; + my $neighbor = $cdp_ip->{$cdp_key}; + my $neighbor_port = $cdp_port->{$cdp_key}; print "Port : $port connected to $neighbor / $neighbor_port\n"; } @@ -260,7 +260,7 @@ Time in seconds that CDP messages are kept. (C) -=item $cdp->cdp_id() +=item $cdp->cdp_gid() Returns CDP device ID. @@ -280,7 +280,7 @@ to a hash. =over -=item $cdp->c_capabilities() +=item $cdp->cdp_capabilities() Returns Device Functional Capabilities. Results are munged into an ascii binary string, 7 digits long, MSB. Each digit represents a bit from the @@ -319,108 +319,108 @@ information. (C) -=item $cdp->c_domain() +=item $cdp->cdp_domain() Returns remote VTP Management Domain as defined in C (C) -=item $cdp->c_duplex() +=item $cdp->cdp_duplex() Returns the port duplex status from remote devices. (C) -=item $cdp->c_id() +=item $cdp->cdp_id() Returns remote device id string (C) -=item $cdp->c_if() +=item $cdp->cdp_if() Returns the mapping to the SNMP Interface Table. -Note that a lot devices don't implement $cdp->c_index(), So if it isn't +Note that a lot devices don't implement $cdp->cdp_index(), So if it isn't around, we fake it. In order to map the cdp table entry back to the interfaces() entry, we truncate the last number off of it : # it exists, yay. - my $c_index = $device->c_index(); - return $c_index if defined $c_index; + my $cdp_index = $device->cdp_index(); + return $cdp_index if defined $cdp_index; # if not, let's fake it - my $c_ip = $device->c_ip(); + my $cdp_ip = $device->cdp_ip(); - my %c_if - foreach my $key (keys %$c_ip){ + my %cdp_if + foreach my $key (keys %$cdp_ip){ $iid = $key; ## Truncate off .1 from cdp response $iid =~ s/\.\d+$//; - $c_if{$key} = $iid; + $cdp_if{$key} = $iid; } - return \%c_if; + return \%cdp_if; -=item $cdp->c_index() +=item $cdp->cdp_index() Returns the mapping to the SNMP2 Interface table for CDP Cache Entries. -Most devices don't implement this, so you probably want to use $cdp->c_if() +Most devices don't implement this, so you probably want to use $cdp->cdp_if() instead. -See c_if() entry. +See cdp_if() entry. (C) -=item $cdp->c_ip() +=item $cdp->cdp_ip() -If $cdp->c_proto() is supported, returns remote IPV4 address only. Otherwise +If $cdp->cdp_proto() is supported, returns remote IPV4 address only. Otherwise it will return all addresses. (C) -=item $cdp->c_addr() +=item $cdp->cdp_addr() Returns remote address (C) -=item $cdp->c_platform() +=item $cdp->cdp_platform() Returns remote platform id (C) -=item $cdp->c_port() +=item $cdp->cdp_port() Returns remote port ID (C) -=item $cdp->c_proto() +=item $cdp->cdp_proto() Returns remote address type received. Usually IP. (C) -=item $cdp->c_ver() +=item $cdp->cdp_ver() Returns remote hardware version (C) -=item $cdp->c_vlan() +=item $cdp->cdp_vlan() Returns the remote interface native VLAN. (C) -=item $cdp->c_power() +=item $cdp->cdp_power() Returns the amount of power consumed by remote device in milliwatts munged for decimal placement. diff --git a/Info/FDP.pm b/Info/FDP.pm index 81ac7e3f..9a1a270e 100644 --- a/Info/FDP.pm +++ b/Info/FDP.pm @@ -47,13 +47,6 @@ $VERSION = '2.09'; %MIBS = ( 'FOUNDRY-SN-SWITCH-GROUP-MIB' => 'snFdpGlobalRun' ); %GLOBALS = ( - - # CDP-Compatibility - 'cdp_interval' => 'snFdpGlobalMessageInterval', - 'cdp_holdtime' => 'snFdpGlobalHoldTime', - 'cdp_id' => 'snFdpGlobalDeviceId', - - # 'fdp_run' => 'snFdpGlobalRun', 'fdp_interval' => 'snFdpGlobalMessageInterval', 'fdp_holdtime' => 'snFdpGlobalHoldTime', @@ -61,27 +54,27 @@ $VERSION = '2.09'; ); %FUNCS = ( - 'c_index' => 'snFdpCacheIfIndex', - 'c_proto' => 'snFdpCacheAddressType', - 'c_ip' => 'snFdpCacheAddress', - 'c_ver' => 'snFdpCacheVersion', - 'c_id' => 'snFdpCacheDeviceId', - 'c_port' => 'snFdpCacheDevicePort', - 'c_platform' => 'snFdpCachePlatform', - 'c_capabilities' => 'snFdpCacheCapabilities', - 'c_domain' => 'snFdpCacheVTPMgmtDomain', - 'c_vlan' => 'snFdpCacheNativeVLAN', - 'c_duplex' => 'snFdpCacheDuplex', + 'fdp_index' => 'snFdpCacheIfIndex', + 'fdp_proto' => 'snFdpCacheAddressType', + 'fdp_ip' => 'snFdpCacheAddress', + 'fdp_ver' => 'snFdpCacheVersion', + 'fdp_id' => 'snFdpCacheDeviceId', + 'fdp_port' => 'snFdpCacheDevicePort', + 'fdp_platform' => 'snFdpCachePlatform', + 'fdp_capabilities' => 'snFdpCacheCapabilities', + 'fdp_domain' => 'snFdpCacheVTPMgmtDomain', + 'fdp_vlan' => 'snFdpCacheNativeVLAN', + 'fdp_duplex' => 'snFdpCacheDuplex', ); %MUNGE = ( - 'c_capabilities' => \&SNMP::Info::munge_caps, - 'c_ip' => \&SNMP::Info::munge_ip + 'fdp_capabilities' => \&SNMP::Info::munge_caps, + 'fdp_ip' => \&SNMP::Info::munge_ip ); -sub cdp_run { +sub fdp_run { my $fdp = shift; - my $fdp_run = $fdp->fdp_run(); + my $fdp_run = $fdp->orig_fdp_run(); # if fdp_run isn't implemented on device, assume FDP is on return $fdp_run if defined $fdp_run; @@ -107,7 +100,7 @@ sub hasFDP { return $fdp->fdp_run(); } -sub c_if { +sub fdp_if { my $fdp = shift; # See if by some miracle Cisco implemented the fdpCacheIfIndex entry @@ -115,7 +108,7 @@ sub c_if { return $fdp_index if defined $fdp_index; # Nope, didn't think so. Now we fake it. - my $fdp_ip = $fdp->c_ip(); + my $fdp_ip = $fdp->fdp_ip(); unless ( defined $fdp_ip ) { $fdp->error_throw( "SNMP::Info::FDP:fdp_if() - Device doesn't have fdp_ip() data. Can't fake fdp_index()" @@ -256,19 +249,19 @@ CDP compatibility =over -=item $fdp->c_interval() +=item $fdp->fdp_interval() Interval in seconds at which FDP messages are generated. (C) -=item $fdp->c_holdtime() +=item $fdp->fdp_holdtime() Time in seconds that FDP messages are kept. (C) -=item $fdp->c_id() +=item $fdp->fdp_id() Returns FDP device ID. @@ -277,7 +270,7 @@ retrieved from remote devices with $fdp->id(). (C) -=item $cdp->cdp_run() +=item $fdp->fdp_run() Is FDP enabled on this device? @@ -294,7 +287,7 @@ CDP compatibility =over -=item $fdp->c_capabilities() +=item $fdp->fdp_capabilities() Returns Device Functional Capabilities. Results are munged into an ascii binary string, 7 digits long, MSB. Each digit represents a bit from the @@ -333,26 +326,26 @@ this information. (C) -=item $fdp->c_domain() +=item $fdp->fdp_domain() The CDP version of this returns remote VTP Management Domain as defined in C (C) -=item $fdp->c_duplex() +=item $fdp->fdp_duplex() Returns the port duplex status from remote devices. (C) -=item $fdp->c_id() +=item $fdp->fdp_id() Returns remote device id string (C) -=item $fdp->c_if() +=item $fdp->fdp_if() Returns the mapping to the SNMP Interface Table. @@ -380,7 +373,7 @@ truncate the last number off of it : return \%fdp_if; -=item $fdp->c_index() +=item $fdp->fdp_index() Returns the mapping to the SNMP2 Interface table for FDP Cache Entries. @@ -391,37 +384,37 @@ See fdp_if() entry. (C) -=item $fdp->c_ip() +=item $fdp->fdp_ip() Returns remote IP address (C) -=item $fdp->c_platform() +=item $fdp->fdp_platform() Returns remote platform id (C) -=item $fdp->c_port() +=item $fdp->fdp_port() Returns remote port ID (C) -=item $fdp->c_proto() +=item $fdp->fdp_proto() Returns remote address type received. Usually IP. (C) -=item $fdp->c_ver() +=item $fdp->fdp_ver() Returns remote hardware version (C) -=item $fdp->c_vlan() +=item $fdp->fdp_vlan() Returns the remote interface native VLAN. diff --git a/Info/Layer2/Baystack.pm b/Info/Layer2/Baystack.pm index 4160b453..99404708 100644 --- a/Info/Layer2/Baystack.pm +++ b/Info/Layer2/Baystack.pm @@ -79,27 +79,20 @@ $SNMP::Info::SPEED_MAP{2_000_000_000} = '1.0 Gbps'; sub os { my $baystack = shift; - my $descr = $baystack->description(); - my $model = $baystack->model(); + my $descr = $baystack->description() || ""; + my $model = $baystack->model() || ""; - if ( ( defined $descr and $descr =~ /Business Ethernet Switch.*SW:v/i ) ) - { + if ( $descr =~ /Business Ethernet Switch.*SW:v/i ) { return 'bes'; } - if ( - ( - (defined $model and $model =~ /(420|425|BPS)/ ) - and - (defined $descr and $descr =~ m/SW:v[1-2]/i ) - ) - or - ( - (defined $model and $model =~ /(410|450|380)/ ) - ) - ) + if ( ( ( $model =~ /(420|425|BPS)/ ) and ( $descr =~ m/SW:v[1-2]/i ) ) + or ( ( $model =~ /(410|450|380)/ ) ) ) { return 'baystack'; } + if ( $model =~ /VSP/ ) { + return 'vsp'; + } return 'boss'; } @@ -126,7 +119,7 @@ sub os_bin { } sub vendor { - return 'nortel'; + return 'avaya'; } sub model { @@ -141,9 +134,11 @@ sub model { return '303' if ( defined $descr and $descr =~ /\D303\D/ ); return '304' if ( defined $descr and $descr =~ /\D304\D/ ); return 'BPS' if ( $model =~ /BPS2000/i ); - return $2 - if ( $model - =~ /(ES|ERS|BayStack|EthernetRoutingSwitch|EthernetSwitch)-?(\d+)/ ); + + # Pull sreg- from all + $model =~ s/^sreg-//; + # Strip ES/ERS/BayStack etc. from those families + $model =~ s/^(E(R)?S|BayStack|Ethernet(Routing)?Switch)-?//; return $model; } @@ -214,7 +209,7 @@ sub i_name { sub index_factor { my $baystack = shift; - my $model = $baystack->model(); + my $model = $baystack->model() || ""; my $os = $baystack->os(); my $os_ver = $baystack->os_ver(); my $op_mode = $baystack->ns_op_mode(); @@ -228,142 +223,16 @@ sub index_factor { my $index_factor = 32; $index_factor = 64 - if ( ( defined $model and $model =~ /(470)/ ) + if ( ( $model =~ /(470)/ ) or ( $os =~ m/(boss|bes)/ ) and ( $op_mode eq 'pure' ) ); $index_factor = 128 - if ( ( defined $model and $model =~ /(5[56]\d\d)/ ) + if ( ( $model =~ /(5[56]\d\d)|VSP/ ) and ( $os_ver >= 6 ) ); return $index_factor; } -# Use SONMP and/or LLDP -sub hasCDP { - my $baystack = shift; - - return $baystack->hasLLDP() || $baystack->SUPER::hasCDP(); -} - -sub c_ip { - my $baystack = shift; - my $partial = shift; - - my $cdp = $baystack->SUPER::c_ip($partial) || {}; - my $lldp = $baystack->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $baystack = shift; - my $partial = shift; - - my $lldp = $baystack->lldp_if($partial) || {}; - my $cdp = $baystack->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $baystack = shift; - my $partial = shift; - - my $lldp = $baystack->lldp_port($partial) || {}; - my $cdp = $baystack->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $baystack = shift; - my $partial = shift; - - my $lldp = $baystack->lldp_id($partial) || {}; - my $cdp = $baystack->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $baystack = shift; - my $partial = shift; - - my $lldp = $baystack->lldp_rem_sysdesc($partial) || {}; - my $cdp = $baystack->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} # Newer devices support ENTITY-MIB, use if available otherwise use proprietary # methods. @@ -475,8 +344,8 @@ __END__ =head1 NAME -SNMP::Info::Layer2::Baystack - SNMP Interface to Nortel Ethernet (Baystack) -Switches +SNMP::Info::Layer2::Baystack - SNMP Interface to Avaya Ethernet (Baystack) +and VSP 7000 series switches =head1 AUTHOR @@ -499,8 +368,8 @@ Eric Miller =head1 DESCRIPTION -Provides abstraction to the configuration information obtainable from a Nortel -Ethernet Switch (Baystack) through SNMP. +Provides abstraction to the configuration information obtainable from an +Avaya Ethernet Switch (Baystack) and VSP 7000 series through SNMP. For speed or debugging purposes you can call the subclass directly, but not after determining a more specific class using the method above. @@ -523,12 +392,6 @@ my $baystack = new SNMP::Info::Layer2::Baystack(...); =back -=head2 Required MIBs - -=over - -=back - =head2 Inherited MIBs See L for its MIB requirements. @@ -549,7 +412,7 @@ These are methods that return scalar value from SNMP =item $baystack->vendor() -Returns 'nortel' +Returns 'avaya' =item $baystack->model() @@ -719,54 +582,6 @@ ns_e_vendor(). =back -=head2 Topology information - -Based upon the software version devices may support SynOptics Network -Management Protocol (SONMP) and Link Layer Discovery Protocol (LLDP). These -methods will query both and return the combination of 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. - -=over - -=item $baystack->hasCDP() - -Returns true if the device is running either SONMP or LLDP. - -=item $baystack->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $baystack->c_ip() - -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 non-SONMP/LLDP device in between two or -more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $baystack->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $baystack->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $baystack->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::SONMP See L for details. diff --git a/Info/Layer2/HP.pm b/Info/Layer2/HP.pm index f1447917..a2db1b96 100644 --- a/Info/Layer2/HP.pm +++ b/Info/Layer2/HP.pm @@ -413,108 +413,6 @@ sub _sensor { return $result; } -# Use CDP and/or LLDP -sub hasCDP { - my $hp = shift; - - return $hp->hasLLDP() || $hp->SUPER::hasCDP(); -} - -sub c_ip { - my $hp = shift; - my $partial = shift; - - my $cdp = $hp->SUPER::c_ip($partial) || {}; - my $lldp = $hp->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $hp = shift; - my $partial = shift; - - my $lldp = $hp->lldp_if($partial) || {}; - my $cdp = $hp->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $hp = shift; - my $partial = shift; - - my $lldp = $hp->lldp_port($partial) || {}; - my $cdp = $hp->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $hp = shift; - my $partial = shift; - - my $lldp = $hp->lldp_id($partial) || {}; - my $cdp = $hp->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - sub munge_hp_c_id { my ($v) = @_; if ( length(unpack('H*', $v)) == 12 ){ @@ -528,30 +426,6 @@ sub munge_hp_c_id { } } -sub c_platform { - my $hp = shift; - my $partial = shift; - - my $lldp = $hp->lldp_rem_sysdesc($partial) || {}; - my $cdp = $hp->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - # POWER-ETHERNET-MIB doesn't define a mapping of its # "module"/"port" index to ifIndex. Different vendors # do this in different ways. @@ -959,53 +833,6 @@ interface index (c) =back -=head2 Topology information - -Based upon the firmware version HP devices may support Cisco Discovery -Protocol (CDP), Link Layer Discovery Protocol (LLDP), or both. These methods -will query both and return the combination of 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. - -=over - -=item $hp->hasCDP() - -Returns true if the device is running either CDP or LLDP. - -=item $hp->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $hp->c_ip() - -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 non-CDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $hp->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $hp->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $hp->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::Layer2 See documentation in L for details. diff --git a/Info/Layer2/NWSS2300.pm b/Info/Layer2/NWSS2300.pm new file mode 100644 index 00000000..2b3bef5a --- /dev/null +++ b/Info/Layer2/NWSS2300.pm @@ -0,0 +1,1291 @@ +# SNMP::Info::Layer2::NWSS2300 +# +# Copyright (c) 2012 Eric Miller +# +# 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. + +package SNMP::Info::Layer2::NWSS2300; + +use strict; +use Exporter; +use SNMP::Info; +use SNMP::Info::Bridge; + +@SNMP::Info::Layer2::NWSS2300::ISA + = qw/SNMP::Info SNMP::Info::Bridge Exporter/; +@SNMP::Info::Layer2::NWSS2300::EXPORT_OK = qw//; + +use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE/; + +$VERSION = '2.09'; + +%MIBS = ( + %SNMP::Info::MIBS, + %SNMP::Info::Bridge::MIBS, + 'NTWS-REGISTRATION-DEVICES-MIB' => 'ntwsSwitch2380', + 'NTWS-AP-STATUS-MIB' => 'ntwsApStatNumAps', + 'NTWS-CLIENT-SESSION-MIB' => 'ntwsClSessTotalSessions', + 'NTWS-SYSTEM-MIB' => 'ntwsSysCpuAverageLoad', + 'NTWS-BASIC-MIB' => 'ntwsVersionString', +); + +%GLOBALS = ( + %SNMP::Info::GLOBALS, + %SNMP::Info::Bridge::GLOBALS, + 'os_ver' => 'ntwsVersionString', + 'serial' => 'ntwsSerialNumber', + 'mac' => 'dot1dBaseBridgeAddress', +); + +%FUNCS = ( + %SNMP::Info::FUNCS, + %SNMP::Info::Bridge::FUNCS, + + # NTWS-AP-STATUS-MIB::ntwsApStatApStatusTable + 'nwss2300_ap_mac' => 'ntwsApStatApStatusBaseMac', + 'nwss2300_ap_name' => 'ntwsApStatApStatusApName', + 'nwss2300_ap_ip' => 'ntwsApStatApStatusIpAddress', + #'nwss2300_ap_loc' => 'bsnAPLocation', + 'nwss2300_ap_sw' => 'ntwsApStatApStatusSoftwareVer', + 'nwss2300_ap_fw' => 'ntwsApStatApStatusBootVer', + 'nwss2300_ap_model' => 'ntwsApStatApStatusModel', + 'nwss2300_ap_type' => 'ntwsApStatApStatusModel', + 'nwss2300_ap_status' => 'ntwsApStatApStatusApState', + 'nwss2300_ap_vendor' => 'ntwsApStatApStatusManufacturerId', + 'nwss2300_ap_num' => 'ntwsApStatApStatusApNum', + 'nwss2300_ap_dapnum' => 'ntwsApStatApStatusPortOrDapNum', + + # NTWS-AP-STATUS-MIB::ntwsApStatRadioStatusTable + 'nwss2300_apif_mac' => 'ntwsApStatRadioStatusBaseMac', + 'nwss2300_apif_type' => 'ntwsApStatRadioStatusRadioPhyType', + 'nwss2300_apif_ch_num' => 'ntwsApStatRadioStatusCurrentChannelNum', + 'nwss2300_apif_power' => 'ntwsApStatRadioStatusCurrentPowerLevel', + 'nwss2300_apif_admin' => 'ntwsApStatRadioStatusRadioMode', + + # NTWS-AP-STATUS-MIB::ntwsApStatRadioServiceTable + 'nwss2300_apif_prof' => 'ntwsApStatRadioServServiceProfileName', + + # NTWS-AP-CONFIG-MIB::ntwsApConfServiceProfileTable + 'nwss2300_ess_bcast' => 'ntwsApConfServProfBeaconEnabled', + + # NTWS-AP-CONFIG-MIB::ntwsApConfRadioConfigTable + 'nwss2300_apcr_txpwr' => 'ntwsApConfRadioConfigTxPower', + 'nwss2300_apcr_ch' => 'ntwsApConfRadioConfigChannel', + 'nwss2300_apcr_mode' => 'ntwsApConfRadioConfigRadioMode', + + # NTWS-AP-CONFIG-MIB::ntwsApConfApConfigTable + 'nwss2300_apc_descr' => 'ntwsApConfApConfigDescription', + 'nwss2300_apc_loc' => 'ntwsApConfApConfigLocation', + 'nwss2300_apc_name' => 'ntwsApConfApConfigApName', + 'nwss2300_apc_model' => 'ntwsApConfApConfigApModelName', + 'nwss2300_apc_serial' => 'ntwsApConfApConfigApSerialNum', + + # NTWS-CLIENT-SESSION-MIB::ntwsClSessClientSessionTable + 'nwss2300_sta_slot' => 'ntwsClSessClientSessRadioNum', + 'nwss2300_sta_serial' => 'ntwsClSessClientSessApSerialNum', + 'nwss2300_sta_ssid' => 'ntwsClSessClientSessSsid', + 'nwss2300_sta_ip' => 'ntwsClSessClientSessIpAddress', + + # NTWS-AP-STATUS-MIB::ntwsApStatRadioServiceTable + 'nwss2300_apif_bssid' => 'ntwsApStatRadioServBssid', + + # NTWS-CLIENT-SESSION-MIB::ntwsClSessClientSessionStatisticsTable + # Pretend to have the CISCO-DOT11-MIB for signal strengths, etc. + 'cd11_sigstrength' => 'ntwsClSessClientSessStatsLastRssi', + 'cd11_sigqual' => 'ntwsClSessClientSessStatsLastSNR', + 'cd11_txrate' => 'ntwsClSessClientSessStatsLastRate', + # These are supposed to be there... + 'cd11_rxbyte' => 'ntwsClSessClientSessStatsUniOctetIn', + 'cd11_txbyte' => 'ntwsClSessClientSessStatsUniOctetOut', + 'cd11_rxpkt' => 'ntwsClSessClientSessStatsUniPktIn', + 'cd11_txpkt' => 'ntwsClSessClientSessStatsUniPktOut', +); + +%MUNGE = ( + %SNMP::Info::MUNGE, + %SNMP::Info::Bridge::MUNGE, + 'nwss2300_apif_mac' => \&SNMP::Info::munge_mac, + 'nwss2300_apif_bssid' => \&SNMP::Info::munge_mac, +); + +sub layers { + return '00000111'; +} + +sub os { + return 'trapeze'; +} + +sub vendor { + return 'avaya'; +} + +sub model { + my $nwss2300 = shift; + my $id = $nwss2300->id(); + + unless ( defined $id ) { + print + " SNMP::Info::Layer2::NWSS2300::model() - Device does not support sysObjectID\n" + if $nwss2300->debug(); + return; + } + + my $model = &SNMP::translateObj($id); + + return $id unless defined $model; + + $model =~ s/^ntwsSwitch//i; + return $model; +} + +sub _ap_serial { + my $nwss2300 = shift; + my $partial = shift; + + my $names = $nwss2300->nwss2300_ap_name($partial) || {}; + + my %ap_serial; + foreach my $iid ( keys %$names ) { + next unless $iid; + + my $serial = join( '', map { sprintf "%c", $_ } split /\./, $iid ); + # Remove any control characters to include nulls + $serial =~ s/[\c@-\c_]//g; + + $ap_serial{$iid} = "$serial"; + } + return \%ap_serial; +} + +# Wireless switches do not support ifMIB requirements to get MAC +# and port status + +sub i_index { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->orig_i_index($partial) || {}; + my $ap_index = $nwss2300->nwss2300_apif_mac($partial) || {}; + + my %if_index; + foreach my $iid ( keys %$i_index ) { + my $index = $i_index->{$iid}; + next unless defined $index; + + $if_index{$iid} = $index; + } + + # Get Attached APs as Interfaces + foreach my $ap_id ( keys %$ap_index ) { + + my $mac = $ap_index->{$ap_id}; + next unless ($mac); + + $if_index{$ap_id} = $mac; + } + + return \%if_index; +} + +sub interfaces { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->i_index($partial) || {}; + my $descriptions = $nwss2300->SUPER::i_description($partial) || {}; + + my %if; + foreach my $iid ( keys %$i_index ) { + my $desc = $descriptions->{$iid} || $i_index->{$iid}; + next unless defined $desc; + + $if{$iid} = $desc; + } + + return \%if; +} + +sub i_description { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->i_index($partial) || {}; + my $i_desc = $nwss2300->orig_i_description($partial) || {}; + my $ap_name = $nwss2300->nwss2300_ap_name($partial) || {}; + + my %i_name; + foreach my $iid ( keys %$i_index ) { + my $index = $i_index->{$iid}; + next unless defined $index; + + if ( $index =~ /^\d+$/ ) { + my $name = $i_desc->{$iid}; + next unless defined $name; + $i_name{$iid} = $name; + } + + elsif ( $index =~ /(?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}/ ) { + my $idx = $iid; + $idx =~ s/\.(\d+)$//; + my $radio = $1; + $radio--; + my $name = $ap_name->{$idx}; + next unless defined $name; + $i_name{$iid} = "Radio-$radio: $name"; + } + + else { + $i_name{$iid} = $index; + } + } + return \%i_name; +} + +sub i_name { + my $nwss2300 = shift; + my $partial = shift; + + return $nwss2300->i_description($partial); +} + +sub i_type { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->i_index($partial) || {}; + my $i_type = $nwss2300->orig_i_type($partial) || {}; + + my %i_type; + foreach my $iid ( keys %$i_index ) { + my $index = $i_index->{$iid}; + next unless defined $index; + + if ( $index =~ /^\d+$/ ) { + my $type = $i_type->{$iid}; + next unless defined $type; + $i_type{$iid} = $type; + } + + elsif ( $index =~ /(?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}/ ) { + # Match to an ifType + $i_type{$iid} = 'capwapWtpVirtualRadio'; + } + + else { + next; + } + } + return \%i_type; +} + +sub i_up { + my $nwss2300 = shift; + my $partial = shift; + + return $nwss2300->i_up_admin($partial); +} + +sub i_up_admin { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->i_index($partial) || {}; + my $i_up = $nwss2300->orig_i_up($partial) || {}; + my $apif_up = $nwss2300->nwss2300_apif_admin($partial) || {}; + + my %i_up_admin; + foreach my $iid ( keys %$i_index ) { + my $index = $i_index->{$iid}; + next unless defined $index; + + if ( $index =~ /^\d+$/ ) { + my $stat = $i_up->{$iid}; + next unless defined $stat; + $i_up_admin{$iid} = $stat; + } + + elsif ( $index =~ /(?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}/ ) { + my $stat = $apif_up->{$iid}; + next unless defined $stat; + $i_up_admin{$iid} = $stat; + } + + else { + next; + } + } + return \%i_up_admin; +} + +sub i_mac { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->i_index($partial) || {}; + my $i_mac = $nwss2300->orig_i_mac($partial) || {}; + + my %i_mac; + foreach my $iid ( keys %$i_index ) { + my $index = $i_index->{$iid}; + next unless defined $index; + + if ( $index =~ /^\d+$/ ) { + my $mac = $i_mac->{$iid}; + next unless defined $mac; + $i_mac{$iid} = $mac; + } + + # Don't grab AP MACs - we want the AP to show up on edge switch + # ports + + else { + next; + } + } + return \%i_mac; +} + +# Wireless switches do not support the standard Bridge MIB for client devices +sub bp_index { + my $nwss2300 = shift; + my $partial = shift; + + my $i_index = $nwss2300->i_index($partial) || {}; + + my %bp_index; + foreach my $iid ( keys %$i_index ) { + my $index = $i_index->{$iid}; + next unless defined $index; + + $bp_index{$index} = $iid; + } + return \%bp_index; +} + +sub fw_mac { + my $nwss2300 = shift; + my $partial = shift; + + my $serials = $nwss2300->nwss2300_sta_serial($partial) || {}; + + my %fw_mac; + foreach my $iid ( keys %$serials ) { + next unless $iid; + + my $mac = join( ':', map { sprintf "%02x", $_ } split /\./, $iid ); + next unless $mac =~ /^([0-9A-F][0-9A-F]:){5}[0-9A-F][0-9A-F]$/i; + + $fw_mac{$iid} = $mac; + } + return \%fw_mac; +} + +sub fw_port { + my $nwss2300 = shift; + my $partial = shift; + + my $slots = $nwss2300->nwss2300_sta_slot($partial) || {}; + my $serials = $nwss2300->nwss2300_sta_serial($partial) || {}; + my $ap_serials = $nwss2300->_ap_serial($partial) || {}; + my %serial_iid = reverse %$ap_serials; + + my %fw_port; + foreach my $iid ( keys %$slots ) { + my $slot = $slots->{$iid}; + next unless defined $slot; + $slot =~ s/radio-//i; + + my $serial = $serials->{$iid}; + next unless defined $serial; + my $index = $serial_iid{$serial}; + next unless defined $index; + + $fw_port{$iid} = "$index.$slot"; + } + return \%fw_port; +} + +sub i_ssidlist { + my $nwss2300 = shift; + my $partial = shift; + + my $apif_bssid = $nwss2300->nwss2300_apif_bssid($partial) || {}; + my $i_index = $nwss2300->i_index($partial) || {}; + + my %i_ssidlist; + foreach my $iid ( keys %$i_index ) { + # Skip non-radio interfaces + next if $iid =~ /^\d+$/; + + foreach my $idx ( keys %$apif_bssid) { + next unless ($idx =~ /^$iid\./); + my $bssid_mac = $apif_bssid->{$idx}; + next unless $bssid_mac; + # Give the SSID a numeric value based upon tail of BSSID + my $id = hex $1 if $bssid_mac =~ /:([0-9A-F]{1,2})$/i; + next unless (defined $id and $id =~ /\d+/); + my $ssid_oid = $idx; + $ssid_oid =~ s/^$iid\.//; + + my $ssid = join( '', map { sprintf "%c", $_ } split /\./, $ssid_oid ); + # Remove any control characters including nulls + $ssid =~ s/[\c@-\c_]//g; + $i_ssidlist{"$iid.$id"} = $ssid; + } + } + return \%i_ssidlist; +} + +# Can't find in MIB +# +#sub i_ssidbcast { +# +#} + +sub i_80211channel { + my $nwss2300 = shift; + my $partial = shift; + + my $ch_list = $nwss2300->nwss2300_apif_ch_num($partial) || {}; + + my %i_80211channel; + foreach my $iid ( keys %$ch_list ) { + my $ch = $ch_list->{$iid}; + next unless $ch =~ /\d+/; + $i_80211channel{$iid} = $ch; + } + return \%i_80211channel; +} + +sub dot11_cur_tx_pwr_mw { + my $nwss2300 = shift; + my $partial = shift; + + my $cur = $nwss2300->nwss2300_apif_power($partial); + + my $dot11_cur_tx_pwr_mw = {}; + foreach my $idx ( keys %$cur ) { + my $pwr_dbm = $cur->{$idx}; + next unless $pwr_dbm; + #Convert to milliWatts = 10(dBm/10) + my $pwr = int (10 ** ($pwr_dbm / 10)); + + $dot11_cur_tx_pwr_mw->{$idx} = $pwr; + } + return $dot11_cur_tx_pwr_mw; +} + +# Pseudo ENTITY-MIB methods + +sub e_index { + my $nwss2300 = shift; + + # Try new first, fall back to depreciated + my $ap_num = $nwss2300->nwss2300_ap_num() || $nwss2300->nwss2300_ap_dapnum() || {}; + + my %e_index; + + # Chassis + $e_index{1} = 1; + + # We're going to hack an index to capture APs + foreach my $idx ( keys %$ap_num ) { + my $number = $ap_num->{$idx}; + next unless $number =~ /\d+/; + + $e_index{$idx} = $number; + } + return \%e_index; +} + +sub e_class { + my $nwss2300 = shift; + + my $e_idx = $nwss2300->e_index() || {}; + + my %e_class; + foreach my $iid ( keys %$e_idx ) { + if ( $iid eq "1" ) { + $e_class{$iid} = 'chassis'; + } + + # This isn't a valid PhysicalClass, but we're hacking this anyway + else { + $e_class{$iid} = 'ap'; + } + } + return \%e_class; +} + +sub e_name { + my $nwss2300 = shift; + + my $ap_name = $nwss2300->nwss2300_ap_name() || {}; + + my %e_name; + + # Chassis + $e_name{1} = 'WLAN Controller'; + + # APs + foreach my $iid ( keys %$ap_name ) { + $e_name{$iid} = 'AP'; + } + return \%e_name; +} + +sub e_descr { + my $nwss2300 = shift; + + my $ap_model = $nwss2300->nwss2300_ap_model() || {}; + my $ap_name = $nwss2300->nwss2300_ap_name() || {}; + + my %e_descr; + + # Chassis + $e_descr{1} = $nwss2300->model(); + + # APs + foreach my $iid ( keys %$ap_name ) { + my $name = $ap_name->{$iid}; + next unless defined $name; + my $model = $ap_model->{$iid} || 'AP'; + + $e_descr{$iid} = "$model: $name"; + } + return \%e_descr; +} + +sub e_model { + my $nwss2300 = shift; + + my $ap_model = $nwss2300->nwss2300_ap_model() || {}; + + my %e_model; + + # Chassis + $e_model{1} = $nwss2300->model(); + + # APs + foreach my $iid ( keys %$ap_model ) { + my $model = $ap_model->{$iid}; + next unless defined $model; + + $e_model{$iid} = $model; + } + return \%e_model; +} + +sub e_type { + my $nwss2300 = shift; + + return $nwss2300->e_model(); +} + +sub e_fwver { + my $nwss2300 = shift; + + my $ap_fw = $nwss2300->nwss2300_ap_fw() || {}; + + my %e_fwver; + # APs + foreach my $iid ( keys %$ap_fw ) { + my $fw = $ap_fw->{$iid}; + next unless defined $fw; + + $e_fwver{$iid} = $fw; + } + return \%e_fwver; +} + +sub e_vendor { + my $nwss2300 = shift; + + my $vendors = $nwss2300->nwss2300_ap_vendor() || {}; + + my %e_vendor; + + # Chassis + $e_vendor{1} = 'avaya'; + + # APs + foreach my $iid ( keys %$vendors ) { + my $vendor = $vendors->{$iid}; + next unless defined $vendor; + + $e_vendor{$iid} = $vendor; + } + return \%e_vendor; +} + +sub e_serial { + my $nwss2300 = shift; + + my $ap_serial = $nwss2300->_ap_serial() || {}; + + my %e_serial; + + # Chassis + $e_serial{1} = $nwss2300->serial(); + + # APs + foreach my $iid ( keys %$ap_serial ) { + my $serial = $ap_serial->{$iid}; + next unless defined $serial; + + $e_serial{$iid} = $serial; + } + return \%e_serial; +} + +sub e_pos { + my $nwss2300 = shift; + + my $e_idx = $nwss2300->e_index() || {}; + + my %e_pos; + my $pos = 0; + foreach my $iid ( sort keys %$e_idx ) { + if ( $iid eq "1" ) { + $e_pos{$iid} = -1; + next; + } + else { + $pos++; + $e_pos{$iid} = $pos; + } + } + return \%e_pos; +} + +sub e_swver { + my $nwss2300 = shift; + + my $ap_sw = $nwss2300->nwss2300_ap_sw() || {}; + + my %e_swver; + + # Chassis + $e_swver{1} = $nwss2300->os_ver(); + + # APs + foreach my $iid ( keys %$ap_sw ) { + my $sw = $ap_sw->{$iid}; + next unless defined $sw; + + $e_swver{$iid} = $sw; + } + return \%e_swver; +} + +sub e_parent { + my $nwss2300 = shift; + + my $e_idx = $nwss2300->e_index() || {}; + + my %e_parent; + foreach my $iid ( sort keys %$e_idx ) { + if ( $iid eq "1" ) { + $e_parent{$iid} = 0; + next; + } + else { + $e_parent{$iid} = 1; + } + } + return \%e_parent; +} + +# arpnip: +# +# This is the controller snooping on the MAC->IP mappings. +# Pretending this is arpnip data allows us to get MAC->IP +# mappings even for stations that only communicate locally. + +sub at_paddr { + my $nwss2300 = shift; + + my $mac2ip = $nwss2300->nwss2300_sta_ip(); + + my $ret = {}; + foreach my $idx ( keys %$mac2ip ) { + next if ( $mac2ip->{ $idx } eq '0.0.0.0' ); + my $mac = join( ":", map { sprintf "%02x", $_ } split /\./, $idx ); + $ret->{$idx} = $mac; + } + return $ret; +} + +sub at_netaddr { + my $nwss2300 = shift; + + my $mac2ip = $nwss2300->nwss2300_sta_ip(); + + my $ret = {}; + foreach my $idx ( keys %$mac2ip ) { + next if ( $mac2ip->{ $idx } eq '0.0.0.0' ); + $ret->{$idx} = $mac2ip->{ $idx }; + } + return $ret; +} + +# Client MAC +sub cd11_mac { + my $nwss2300 = shift; + my $cd11_sigstrength = $nwss2300->cd11_sigstrength(); + + my $ret = {}; + foreach my $idx ( keys %$cd11_sigstrength ) { + my $mac = join( ":", map { sprintf "%02x", $_ } split /\./, $idx ); + $ret->{$idx} = $mac + } + return $ret; +} + + +1; +__END__ + +=head1 NAME + +SNMP::Info::Layer2::NWSS2300 - SNMP Interface to Avaya (Trapeze) Wireless +Controllers + +=head1 AUTHOR + +Eric Miller + +=head1 SYNOPSIS + + #Let SNMP::Info determine the correct subclass for you. + + my $nwss2300 = new SNMP::Info( + AutoSpecify => 1, + Debug => 1, + DestHost => 'myswitch', + Community => 'public', + Version => 2 + ) + + or die "Can't connect to DestHost.\n"; + + my $class = $nwss2300->class(); + print " Using device sub class : $class\n"; + +=head1 DESCRIPTION + +Provides abstraction to the configuration information obtainable from +Avaya (Trapeze) Wireless Controllers through SNMP. + +This class emulates bridge functionality for the wireless switch. This enables +end station MAC addresses collection and correlation to the thin access point +the end station is using for communication. + +For speed or debugging purposes you can call the subclass directly, but not +after determining a more specific class using the method above. + +my $nwss2300 = new SNMP::Info::Layer2::NWSS2300(...); + +=head2 Inherited Classes + +=over + +=item SNMP::Info + +=item SNMP::Info::Bridge + +=back + +=head2 Required MIBs + +=over + +=item F + +=item F + +=item F + +=item F + +=item F + +=back + +=head2 Inherited Classes' MIBs + +See L for its own MIB requirements. + +See L for its own MIB requirements. + +=head1 GLOBALS + +These are methods that return scalar value from SNMP + +=over + +=item $nwss2300->vendor() + +Returns 'avaya' + +=item $nwss2300->os() + +Returns 'trapeze' + +=item $nwss2300->os_ver() + +(C) + +=item $nwss2300->model() + +Tries to reference $nwss2300->id() to F + +Removes 'ntwsSwitch' for readability. + +=item $nwss2300->serial() + +(C) + +=item $nwss2300->mac() + +(C) + +=back + +=head2 Overrides + +=over + +=item $nwss2300->layers() + +Returns 00000011. Class emulates Layer 2 functionality for Thin APs through +proprietary MIBs. + +=back + +=head2 Global Methods imported from SNMP::Info + +See documentation in L for details. + +=head2 Globals imported from SNMP::Info::Bridge + +See documentation in L for details. + +=head1 TABLE METHODS + +These are methods that return tables of information in the form of a reference +to a hash. + +=over + +=item $nwss2300->i_ssidlist() + +Returns reference to hash. SSID's recognized by the radio interface. + +=item $nwss2300->i_80211channel() + +Returns reference to hash. Current operating frequency channel of the radio +interface. + +=item $nwss2300->dot11_cur_tx_pwr_mw() + +Returns reference to hash. Current transmit power, in milliwatts, of the +radio interface. + +=item cd11_mac() + +Client MAC address. + +=back + +=head2 AP Status Table (C) + +A table describing all the APs currently present and managed by the +controller. + +=over + +=item $nwss2300->nwss2300_ap_mac() + +(C) + +=item $nwss2300->nwss2300_ap_name() + +(C) + +=item $nws2300->nwss2300_ap_ip() + +(C) + +=item $nws2300->nwss2300_ap_sw() + +(C) + +=item $nws2300->nwss2300_ap_fw() + +(C) + +=item $nws2300->nwss2300_ap_model() + +(C) + +=item $nws2300->nwss2300_ap_type() + +(C) + +=item $nws2300->nwss2300_ap_status() + +(C) + +=item $nws2300->nwss2300_ap_vendor() + +(C) + +=item $nws2300->nwss2300_ap_num() + +(C) + +=item $nws2300->nwss2300_ap_dapnum() + +(C) + +=back + +=head2 AP Radio Status Table (C) + +A table describing all radios on all the APs currently present and managed +by the controller. + +=over + +=item $nws2300->nwss2300_apif_mac() + +(C) + +=item $nws2300->nwss2300_apif_type() + +(C) + +=item $nws2300->nwss2300_apif_ch_num() + +(C) + +=item $nws2300->nwss2300_apif_power() + +(C) + +=item $nws2300->nwss2300_apif_admin() + +(C) + +=back + +=head2 AP Radio Status Service Table (C) + +A table describing radio services associated with APs currently present +and managed by the controller. + +=over + +=item $nws2300->nwss2300_apif_bssid() + +(C) + +=item $nws2300->nwss2300_apif_prof() + +(C) + +=back + +=head2 AP Service Profile Config Table (C) + +=over + +=item $nws2300->nwss2300_ess_bcast() + +(C) + +=back + +=head2 AP Radio Config Table (C) + +=over + +=item $nws2300->nwss2300_apcr_txpwr() + +(C) + +=item $nws2300->nwss2300_apcr_ch() + +(C) + +=item $nws2300->nwss2300_apcr_mode() + +(C) + +=back + +=head2 AP Config Table (C) + +=over + +=item $nws2300->nwss2300_apc_descr() + +(C) + +=item $nws2300->nwss2300_apc_loc() + +(C) + +=item $nws2300->nwss2300_apc_name() + +(C) + +=item $nws2300->nwss2300_apc_model() + +(C) + +=item $nws2300->nwss2300_apc_serial() + +(C) + +=back + +=head2 Client Session Table (C) + +=over + +=item $nws2300->nwss2300_sta_slot() + +(C) + +=item $nws2300->nwss2300_sta_serial() + +(C) + +=item $nws2300->nwss2300_sta_ssid() + +(C) + +=item $nws2300->nwss2300_sta_ip() + +(C) + +=back + +=head2 Client Session Statistics Table (C) + +These emulate the F + +=over + +=item $nws2300->cd11_sigstrength() + +(C) + +=item $nws2300->cd11_sigqual() + +(C) + +=item $nws2300->cd11_txrate() + +(C) + +=item $nws2300->cd11_rxbyte() + +(C) + +=item $nws2300->cd11_txbyte() + +(C) + +=item $nws2300->cd11_rxpkt() + +(C) + +=item $nws2300->cd11_txpkt() + +(C) + +=back + +=head2 Table Methods imported from SNMP::Info + +See documentation in L for details. + +=head2 Table Methods imported from SNMP::Info::Bridge + +See documentation in L for details. + +=head2 Overrides + +=over + +=item $nwss2300->i_index() + +Returns reference to map of IIDs to Interface index. + +Extends C to support thin APs and WLAN virtual interfaces as device +interfaces. + +=item $nwss2300->interfaces() + +Returns reference to map of IIDs to ports. Thin APs are implemented as device +interfaces. The thin AP MAC address and Slot ID nwss2300_apif_slot() are +used as the port identifier. + +=item $nwss2300->i_name() + +Returns reference to map of IIDs to interface names. Returns C for +Ethernet interfaces and nwss2300_ap_name() for thin AP interfaces. + +=item $nwss2300->i_description() + +Returns reference to map of IIDs to interface types. Returns C +for Ethernet interfaces, nwss2300_ap_name() for thin AP interfaces. + +=item $nwss2300->i_type() + +Returns reference to map of IIDs to interface descriptions. Returns +C for Ethernet interfaces and 'capwapWtpVirtualRadio' for thin AP +interfaces. + +=item $nwss2300->i_up() + +Returns reference to map of IIDs to link status of the interface. Returns +C for Ethernet interfaces and nwss2300_apif_admin() for thin AP +interfaces. + +=item $nwss2300->i_up_admin() + +Returns reference to map of IIDs to administrative status of the interface. +Returns C for Ethernet interfaces and nwss2300_apif_admin() +for thin AP interfaces. + +=item $nwss2300->i_mac() + +Returns reference to map of IIDs to MAC address of the interface. Returns +C for Ethernet interfaces. + +=item $nwss2300->bp_index() + +Simulates bridge MIB by returning reference to a hash mapping i_index() to +the interface iid. + +=item $nwss2300->fw_port() + +Returns reference to a hash, value being mac and +nwss2300_sta_slot() combined to match the interface iid. + +=item $nwss2300->fw_mac() + +Extracts the MAC from the nwss2300_sta_serial() index. + +=back + +=head2 Pseudo ARP Cache Entries + +The controller snoops on the MAC->IP mappings. Using this as ARP cache data +allows us to get MAC->IP mappings even for stations that only +communicate locally. The data is gathered from nwss2300_sta_ip(). + +=over + +=item $nwss2300->at_paddr() + +Returns reference to hash of Pseudo Arp Cache Entries to MAC address + +=item $nwss2300->at_netaddr() + +Returns reference to hash of Pseudo Arp Cache Entries to IP Address + +=back + +=head2 Pseudo F information + +These methods emulate F Physical Table methods using +F. Thin APs are included as subcomponents of +the wireless controller. + +=over + +=item $nwss2300->e_index() + +Returns reference to hash. Key: IID and Value: Integer. The index for APs is +created with an integer representation of the last three octets of the +AP MAC address. + +=item $nwss2300->e_class() + +Returns reference to hash. Key: IID, Value: General hardware type. Return ap +for wireless access points. + +=item $nwss2300->e_descr() + +Returns reference to hash. Key: IID, Value: Human friendly name. + +=item $nwss2300->e_model() + +Returns reference to hash. Key: IID, Value: Model name. + +=item $nwss2300->e_name() + +More computer friendly name of entity. Name is either 'WLAN Controller' or +'AP'. + +=item $nwss2300->e_vendor() + +Returns reference to hash. Key: IID, Value: avaya. + +=item $nwss2300->e_serial() + +Returns reference to hash. Key: IID, Value: Serial number. + +=item $nwss2300->e_pos() + +Returns reference to hash. Key: IID, Value: The relative position among all +entities sharing the same parent. + +=item $nwss2300->e_type() + +Returns reference to hash. Key: IID, Value: Type of component. + +=item $nwss2300->e_fwver() + +Returns reference to hash. Key: IID, Value: Firmware revision. + +=item $nwss2300->e_swver() + +Returns reference to hash. Key: IID, Value: Software revision. + +=item $nwss2300->e_parent() + +Returns reference to hash. Key: IID, Value: The value of e_index() for the +entity which 'contains' this entity. + +=back + +=cut diff --git a/Info/Layer2/Netgear.pm b/Info/Layer2/Netgear.pm index a400fd48..13c684c6 100644 --- a/Info/Layer2/Netgear.pm +++ b/Info/Layer2/Netgear.pm @@ -105,49 +105,6 @@ sub serial { return $self->ng_serial(); } -# Use LLDP - -sub hasCDP { - my $netgear = shift; - return $netgear->hasLLDP(); -} - -sub c_ip { - my $netgear = shift; - my $partial = shift; - - return $netgear->lldp_ip($partial); -} - -sub c_if { - my $netgear = shift; - my $partial = shift; - - return $netgear->lldp_if($partial); -} - -sub c_port { - my $netgear = shift; - my $partial = shift; - - return $netgear->lldp_port($partial); -} - -sub c_id { - my $netgear = shift; - my $partial = shift; - - return $netgear->lldp_id($partial); -} - -sub c_platform { - my $netgear = shift; - my $partial = shift; - - return $netgear->lldp_rem_sysdesc($partial); -} - - 1; __END__ @@ -271,51 +228,12 @@ C doesn't return anything. =back -=head2 Topology information - -Based upon the software version devices may support Link Layer Discovery -Protocol (LLDP). - -=over - -=item $netgear->hasCDP() - -Returns true if the device is running LLDP. - -=item $netgear->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $netgear->c_ip() - -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 non-LLDP device in between two or -more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $netgear->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $netgear->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $netgear->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::Layer2 See documentation in L for details. +=head2 Table Methods imported from SNMP::Info::LLDP + +See documentation in L for details. + =cut diff --git a/Info/Layer3/AlcatelLucent.pm b/Info/Layer3/AlcatelLucent.pm index aee0cd3d..3a61e8aa 100644 --- a/Info/Layer3/AlcatelLucent.pm +++ b/Info/Layer3/AlcatelLucent.pm @@ -34,6 +34,12 @@ use strict; use Exporter; use SNMP::Info::Layer3; use SNMP::Info::MAU; +# Use LLDP +# (or at least try. The versions I've seen have two problems: +# 1. they report ifIndex values as 'local'; we don't support ifIndex +# but *could* +# 2. They report 0.0.0.0 as the management address +# ) use SNMP::Info::LLDP; @SNMP::Info::Layer3::AlcatelLucent::ISA = qw/SNMP::Info::LLDP SNMP::Info::MAU @@ -285,53 +291,6 @@ sub bp_index { # return $i_vlan; #} -# Use LLDP -# (or at least try. The versions I've seen have two problems: -# 1. they report ifIndex values as 'local'; we don't support ifIndex -# but *could* -# 2. They report 0.0.0.0 as the management address -# ) -sub hasCDP { - my $alu = shift; - - return $alu->hasLLDP(); -} - -sub c_ip { - my $alu = shift; - my $partial = shift; - - return $alu->lldp_ip($partial); -} - -sub c_if { - my $alu = shift; - my $partial = shift; - - return $alu->lldp_if($partial); -} - -sub c_port { - my $alu = shift; - my $partial = shift; - - return $alu->lldp_port($partial); -} - -sub c_id { - my $alu = shift; - my $partial = shift; - - return $alu->lldp_id($partial); -} - -sub c_platform { - my $alu = shift; - my $partial = shift; - - return $alu->lldp_rem_sysdesc($partial); -} - # Power-Ethernet ifIndex mapping. I've only seen this from a # fixed-config single-module system, so this is only a plausible # guess as to the mapping on a stack or modular system. @@ -428,10 +387,6 @@ These are methods that return scalar value from SNMP Returns 'alcatel-lucent' -=item $alu->hasCDP() - - Returns whether LLDP is enabled. - =item $alu->model() Tries to reference $alu->id() to one of the product MIBs listed above @@ -502,26 +457,6 @@ Work around various bugs in the F and F implementations, by returning both C and C mappings to C values. -=item $alu->c_id() - -Returns LLDP information. - -=item $alu->c_if() - -Returns LLDP information. - -=item $alu->c_ip() - -Returns LLDP information. - -=item $alu->c_platform() - -Returns LLDP information. - -=item $alu->c_port() - -Returns LLDP information. - =item $alu->i_duplex_admin() Returns info from F diff --git a/Info/Layer3/Altiga.pm b/Info/Layer3/Altiga.pm index 17766b23..1d51a3a5 100644 --- a/Info/Layer3/Altiga.pm +++ b/Info/Layer3/Altiga.pm @@ -152,10 +152,6 @@ sub os { return 'altiga'; } -sub hasCDP { - return 0; -} - # $altiga->interfaces() - Map the Interfaces to their physical names # Add interface number to interface name to prevent duplicate ifDescr # Included statically configured VPN tunnels if ($int_include_vpn) @@ -350,10 +346,6 @@ Tries to determine OS version from the C field. Returns version or C Combines results from C, C, and C methods. -=item $altiga->hasCDP() - -No. - =item $altiga->ps1_status() Combines C and C methods. diff --git a/Info/Layer3/Arista.pm b/Info/Layer3/Arista.pm index 7b0f0ff5..df47604c 100644 --- a/Info/Layer3/Arista.pm +++ b/Info/Layer3/Arista.pm @@ -120,49 +120,6 @@ sub fw_port { return $arista->qb_fw_port($partial); } -# Use LLDP - -sub hasCDP { - my $arista = shift; - - return $arista->hasLLDP(); -} - -sub c_ip { - my $arista = shift; - my $partial = shift; - - return $arista->lldp_ip($partial); -} - -sub c_if { - my $arista = shift; - my $partial = shift; - - return $arista->lldp_if($partial); -} - -sub c_port { - my $arista = shift; - my $partial = shift; - - return $arista->lldp_port($partial); -} - -sub c_id { - my $arista = shift; - my $partial = shift; - - return $arista->lldp_id($partial); -} - -sub c_platform { - my $arista = shift; - my $partial = shift; - - return $arista->lldp_rem_sysdesc($partial); -} - 1; __END__ @@ -232,10 +189,6 @@ These are methods that return scalar values from SNMP Returns 'Arista Networks, Inc.' -=item $arista->hasCDP() - - Returns whether LLDP is enabled. - =item $arista->model() Tries to reference $arista->id() to one of the product MIBs listed above @@ -279,26 +232,6 @@ Use the F instead of F Use the F instead of F -=item $arista->c_id() - -Returns LLDP information. - -=item $arista->c_if() - -Returns LLDP information. - -=item $arista->c_ip() - -Returns LLDP information. - -=item $arista->c_platform() - -Returns LLDP information. - -=item $arista->c_port() - -Returns LLDP information. - =item $arista->i_duplex_admin() Returns info from F diff --git a/Info/Layer3/C3550.pm b/Info/Layer3/C3550.pm index 01d8dda9..dd26a935 100644 --- a/Info/Layer3/C3550.pm +++ b/Info/Layer3/C3550.pm @@ -236,141 +236,6 @@ sub cisco_comm_indexing { return 1; } -# Use CDP and/or LLDP -sub hasCDP { - my $c3550 = shift; - return $c3550->hasLLDP() || $c3550->SUPER::hasCDP(); -} - -sub c_ip { - my $c3550 = shift; - my $partial = shift; - - my $cdp = $c3550->SUPER::c_ip($partial) || {}; - my $lldp = $c3550->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $c3550 = shift; - my $partial = shift; - - my $cdp = $c3550->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - # We need to match the lldp key with the ifIndex - # via lldpLocPortId and ifName - my $i_name = $c3550->ifName($partial) || {}; - my $i_name_rev = {}; - while ( my($key,$val) = each %$i_name ){ - $i_name_rev->{$val} = $key; - } - my $loc_port_id = $c3550->lldpLocPortId($partial) || {}; - my $lldp = $c3550->lldp_if($partial) || {}; - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid} || next; - my $name = $loc_port_id->{$if} || next; - my $i_index = $i_name_rev->{$name} || next; - $c_if{$iid} = $i_index; - } - return \%c_if; -} - -sub c_port { - my $c3550 = shift; - my $partial = shift; - - my $lldp = $c3550->lldp_port($partial) || {}; - my $cdp = $c3550->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $c3550 = shift; - my $partial = shift; - - my $lldp = $c3550->lldp_id($partial) || {}; - my $cdp = $c3550->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $c3550 = shift; - my $partial = shift; - - my $lldp = $c3550->lldp_rem_sysdesc($partial) || {}; - my $cdp = $c3550->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - - 1; __END__ @@ -494,23 +359,6 @@ Returns 1. Use vlan indexing. =back -=head2 Topology information - -Based upon the firmware version Cisco devices may support Link Layer Discovery -Protocol (LLDP) in addition to Cisco Discovery Protocol (CDP). These methods -will query both and return the combination of 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. - -=over - -=item $c3550->hasCDP() - -Returns true if the device is running either CDP or LLDP. - -=back - =head2 Globals imported from SNMP::Info::Layer3 See documentation in L for details. @@ -556,40 +404,6 @@ See documentation in L for details. These are methods that return tables of information in the form of a reference to a hash. -=over - -=item $c3550->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $c3550->c_ip() - -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 non-CDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $c3550->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $c3550->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $c3550->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Overrides =over diff --git a/Info/Layer3/C6500.pm b/Info/Layer3/C6500.pm index 1de2ba12..b0cdd255 100644 --- a/Info/Layer3/C6500.pm +++ b/Info/Layer3/C6500.pm @@ -207,133 +207,6 @@ sub set_i_duplex_admin { } } -# Use CDP and/or LLDP -sub hasCDP { - my $c6500 = shift; - - return $c6500->hasLLDP() || $c6500->SUPER::hasCDP(); -} - -sub c_ip { - my $c6500 = shift; - my $partial = shift; - - my $cdp = $c6500->SUPER::c_ip($partial) || {}; - my $lldp = $c6500->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $c6500 = shift; - my $partial = shift; - - my $lldp = $c6500->lldp_if($partial) || {}; - my $cdp = $c6500->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $c6500 = shift; - my $partial = shift; - - my $lldp = $c6500->lldp_port($partial) || {}; - my $cdp = $c6500->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $c6500 = shift; - my $partial = shift; - - my $lldp = $c6500->lldp_id($partial) || {}; - my $cdp = $c6500->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $c6500 = shift; - my $partial = shift; - - my $lldp = $c6500->lldp_rem_sysdesc($partial) || {}; - my $cdp = $c6500->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - - 1; __END__ @@ -531,53 +404,6 @@ Crosses $c6500->p_port() with $c6500->p_duplex() to utilize port C. =back -=head2 Topology information - -Based upon the firmware version Cisco devices may support Link Layer Discover -Protocol (LLDP) in addition to the Cisco-proprietary CDP. These methods -will query both and return the combination of 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. - -=over - -=item $c6500->hasCDP() - -Returns true if the device is running either CDP or LLDP. - -=item $c6500->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $c6500->c_ip() - -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 non-CDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $c6500->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $c6500->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $c6500->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::CiscoVTP See documentation in L for details. diff --git a/Info/Layer3/Dell.pm b/Info/Layer3/Dell.pm index a8e0fda3..5819b2c3 100644 --- a/Info/Layer3/Dell.pm +++ b/Info/Layer3/Dell.pm @@ -232,47 +232,6 @@ sub _vendor { } } -# lldp support -sub hasCDP { - my $dell = shift; - return $dell->hasLLDP(); -} - -sub c_ip { - my $dell = shift; - my $partial = shift; - - return $dell->lldp_ip($partial); -} - -sub c_if { - my $dell = shift; - my $partial = shift; - - return $dell->lldp_if($partial); -} - -sub c_port { - my $dell = shift; - my $partial = shift; - - return $dell->lldp_port($partial); -} - -sub c_id { - my $dell = shift; - my $partial = shift; - - return $dell->lldp_id($partial); -} - -sub c_platform { - my $dell = shift; - my $partial = shift; - - return $dell->lldp_rem_sysdesc($partial); -} - 1; __END__ @@ -368,10 +327,6 @@ id(). Defaults to 'dlink'. Returns 'dell', 'dlink', or 'ibm' based upon the IANA enterprise number in id(). Defaults to 'dlink'. -=item $dell->hasCDP() - -Returns whether LLDP is enabled. - =back =head2 Overrides @@ -389,6 +344,10 @@ otherwise uses the Layer3 serial method. See documentation in L for details. +=head2 Globals imported from SNMP::Info::LLDP + +See documentation in L for details. + =head1 TABLE METHODS These are methods that return tables of information in the form of a reference @@ -464,30 +423,14 @@ Some devices don't implement the C forwarding table, so we use the C forwarding table. Fall back to the C if C doesn't return anything. -=item $dell->c_id() - -Returns LLDP information. - -=item $dell->c_if() - -Returns LLDP information. - -=item $dell->c_ip() - -Returns LLDP information. - -=item $dell->c_platform() - -Returns LLDP information. - -=item $dell->c_port() - -Returns LLDP information. - =back =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. +=head2 Table Methods imported from SNMP::Info::LLDP + +See documentation in L for details. + =cut diff --git a/Info/Layer3/Enterasys.pm b/Info/Layer3/Enterasys.pm index b7dd0b78..b54ab659 100644 --- a/Info/Layer3/Enterasys.pm +++ b/Info/Layer3/Enterasys.pm @@ -165,138 +165,45 @@ sub fw_port { return $enterasys->qb_fw_port($partial); } -# Use CDP and/or LLDP -# # LLDP table timefilter implementation continuously increments when walked # and we may never reach the end of the table. This behavior can be # modified with the "set snmp timefilter break disable" command, # unfortunately it is not the default. Query with a partial value of zero # which means no time filter. -sub hasCDP { +sub lldp_ip { my $enterasys = shift; + my $partial = shift || 0; - return $enterasys->hasLLDP() || $enterasys->SUPER::hasCDP(); + return $enterasys->SUPER::lldp_ip($partial); } -sub c_ip { +sub lldp_if { my $enterasys = shift; - my $partial = shift; + my $partial = shift || 0; - my $cdp = $enterasys->SUPER::c_ip($partial) || {}; - my $lldp = $enterasys->lldp_ip(0) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; + return $enterasys->SUPER::lldp_if($partial); } -sub c_if { +sub lldp_port { my $enterasys = shift; - my $partial = shift; + my $partial = shift || 0; - my $lldp = $enterasys->lldp_if(0) || {}; - my $cdp = $enterasys->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; + return $enterasys->SUPER::lldp_port($partial); } -sub c_port { +sub lldp_id { my $enterasys = shift; - my $partial = shift; + my $partial = shift || 0; - my $lldp = $enterasys->lldp_port(0) || {}; - my $cdp = $enterasys->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - return \%c_port; + return $enterasys->SUPER::lldp_id($partial); } -sub c_id { +sub lldp_platform { my $enterasys = shift; - my $partial = shift; + my $partial = shift || 0; - my $lldp = $enterasys->lldp_id(0) || {}; - my $cdp = $enterasys->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $enterasys = shift; - my $partial = shift; - - my $lldp = $enterasys->lldp_rem_sysdesc(0) || {}; - my $cdp = $enterasys->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; + return $enterasys->SUPER::lldp_rem_sysdesc($partial); } 1; @@ -399,12 +306,6 @@ Returns base mac =back -=head2 Overrides - -=over - -=back - =head2 Globals imported from SNMP::Info::MAU See documentation in L for details. @@ -463,52 +364,25 @@ identifier (iid). =back -=head2 Topology information +=head2 Link Layer Discovery Protocol (LLDP) Overrides -Based upon the firmware version Enterasys devices may support Cabletron -Discovery Protocol (CTRON CDP), Cisco Discovery Protocol (CDP), Link Layer -Discovery Protocol (LLDP), or all. This module currently supports CDP and -LLDP, but not CTRON CDP. These methods will query both CDP and LLDP and -return the combination of 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. +The LLDP table timefilter implementation continuously increments when +walked and we may never reach the end of the table. This behavior can be +modified with the "set snmp timefilter break disable" command, +unfortunately it is not the default. These methods are overriden to +supply a partial value of zero which means no time filter. =over -=item $enterasys->hasCDP() +=item $enterasys->lldp_if() -Returns true if the device is running either CDP or LLDP. +=item $enterasys->lldp_ip() -=item $enterasys->c_if() +=item $enterasys->lldp_port() -Returns reference to hash. Key: iid Value: local device port (interfaces) +=item $enterasys->lldp_id() -=item $enterasys->c_ip() - -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 non-CDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $enterasys->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $enterasys->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $enterasys->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type +=item $enterasys->lldp_platform() =back diff --git a/Info/Layer3/Extreme.pm b/Info/Layer3/Extreme.pm index 8f47d599..9ecfd89a 100644 --- a/Info/Layer3/Extreme.pm +++ b/Info/Layer3/Extreme.pm @@ -80,19 +80,18 @@ $VERSION = '2.09'; %SNMP::Info::LLDP::FUNCS, %SNMP::Info::EDP::FUNCS, 'fan_state' => 'extremeFanOperational', - # EXTREME-FDB-MIB:extremeFdbMacFdbTable 'ex_fw_mac' => 'extremeFdbMacFdbMacAddress', 'ex_fw_port' => 'extremeFdbMacFdbPortIfIndex', 'ex_fw_status' => 'extremeFdbMacFdbStatus', - # EXTREME-VLAN-MIB:extremeVlanIfTable 'ex_vlan_descr' => 'extremeVlanIfDescr', 'ex_vlan_global_id' => 'extremeVlanIfGlobalIdentifier', - # EXTREME-VLAN-MIB:extremeVlanEncapsIfTable 'ex_vlan_encap_tag' => 'extremeVlanEncapsIfTag', - + # EXTREME-POE-MIB::extremePethPseSlotTable + 'peth_power_watts' => 'extremePethSlotPowerLimit', + # EXTREME-POE-MIB::extremePethPsePortTable 'peth_port_power' => 'extremePethPortMeasuredPower', ); @@ -549,125 +548,6 @@ sub set_add_i_vlan_tagged { return $rv; } -# Use EDP and/or LLDP -sub hasCDP { - my $extreme = shift; - - return $extreme->hasLLDP() || $extreme->hasEDP(); -} - -sub c_ip { - my $extreme = shift; - my $partial = shift; - - my $edp = $extreme->edp_ip() || {}; - my $lldp = $extreme->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$edp ) { - my $ip = $edp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $extreme = shift; - my $partial = shift; - - my $lldp = $extreme->lldp_if($partial) || {}; - my $edp = $extreme->edp_if() || {}; - - my %c_if; - foreach my $iid ( keys %$edp ) { - my $if = $edp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $extreme = shift; - my $partial = shift; - - my $lldp = $extreme->lldp_port($partial) || {}; - my $edp = $extreme->edp_port() || {}; - - my %c_port; - foreach my $iid ( keys %$edp ) { - my $port = $edp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $extreme = shift; - my $partial = shift; - - my $lldp = $extreme->lldp_id($partial) || {}; - my $edp = $extreme->edp_id() || {}; - - my %c_id; - foreach my $iid ( keys %$edp ) { - my $id = $edp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $extreme = shift; - my $partial = shift; - - my $lldp = $extreme->lldp_rem_sysdesc($partial) || {}; - - my %c_platform; - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - 1; __END__ @@ -900,59 +780,14 @@ F rather than F. =item $extreme->peth_port_power() Power supplied by PoE ports, in milliwatts -("extremePethPortMeasuredPower") -=back +(C) -=head2 Topology information +=item $extreme->peth_power_watts() -Based upon the firmware version Extreme devices may support Extreme Discovery -Protocol (EDP), Link Layer Discovery Protocol (LLDP), or both. These methods -will query both and return the combination of 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. +The configured maximum amount of inline power available to the slot. -=over - -=item $extreme->hasCDP() - -Returns true if the device is running either EDP or LLDP. - -=item $extreme->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $extreme->c_ip() - -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. - -With EDP multiple entries may exist with the same local port, c_if(), and -different IPv4 addresses, c_ip(), as EDP reports addresses for each VLAN -transported across the trunk. In the case of LLDP with multiple addresses -there is either a non-LLDP device in between two or more devices or multiple -devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $extreme->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $extreme->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $extreme->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -This information is only available from LLDP. EDP does not provide an -equivalent. +(C) =back diff --git a/Info/Layer3/Foundry.pm b/Info/Layer3/Foundry.pm index 9ea7b052..e0ef1683 100644 --- a/Info/Layer3/Foundry.pm +++ b/Info/Layer3/Foundry.pm @@ -65,6 +65,8 @@ $VERSION = '2.09'; 'ps1_type' => 'snChasPwrSupplyDescription.1', 'ps1_status' => 'snChasPwrSupplyOperStatus.1', 'fan' => 'snChasFanOperStatus.1', + 'img_ver' => 'snAgImgVer', + 'ch_serial' => 'snChasSerNum', ); @@ -165,7 +167,7 @@ sub vendor { sub os_ver { my $foundry = shift; - return $foundry->snAgImgVer() if ( defined $foundry->snAgImgVer() ); + return $foundry->img_ver() if ( defined $foundry->img_ver() ); # Some older ones don't have this value,so we cull it from the description my $descr = $foundry->description(); @@ -204,10 +206,10 @@ sub serial { my $foundry = shift; # Return chassis serial number if available - return $foundry->snChasSerNum() if ( $foundry->snChasSerNum() ); + return $foundry->ch_serial() if ( $foundry->ch_serial() ); # If no chassis serial use first module serial - my $mod_serials = $foundry->snAgentConfigModuleSerialNumber(); + my $mod_serials = $foundry->snAgentConfigModuleSerialNumber() || {}; foreach my $mod ( sort keys %$mod_serials ) { my $serial = $mod_serials->{$mod} || ''; @@ -268,134 +270,6 @@ sub stp_p_state { } -# Use FDP and/or LLDP - -sub hasCDP { - my $foundry = shift; - - return $foundry->hasLLDP() || $foundry->hasFDP(); -} - -sub c_ip { - my $foundry = shift; - my $partial = shift; - - my $cdp = $foundry->SUPER::c_ip($partial) || {}; - my $lldp = $foundry->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $foundry = shift; - my $partial = shift; - - my $lldp = $foundry->lldp_if($partial) || {}; - my $cdp = $foundry->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $foundry = shift; - my $partial = shift; - - my $lldp = $foundry->lldp_port($partial) || {}; - my $cdp = $foundry->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $foundry = shift; - my $partial = shift; - - my $lldp = $foundry->lldp_id($partial) || {}; - my $cdp = $foundry->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $foundry = shift; - my $partial = shift; - - my $lldp = $foundry->lldp_rem_sysdesc($partial) || {}; - my $cdp = $foundry->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - 1; __END__ @@ -527,6 +401,18 @@ Returns the status of the chassis fan. (C) +=item $foundry->img_ver() + +Returns device image version. + +(C) + +=item $foundry->ch_serial() + +Returns chassis serial number. + +(C) + =back =head2 Global Methods imported from SNMP::Info::Layer3 @@ -607,54 +493,6 @@ Returns reference to hash. Current Port Speed. =back -=head2 Topology information - -Based upon the software version devices may support Foundry Discovery -Protocol (FDP) and Link Layer Discovery Protocol (LLDP). These -methods will query both and return the combination of 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. - -=over - -=item $foundry->hasCDP() - -Returns true if the device is running either FDP or LLDP. - -=item $foundry->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $foundry->c_ip() - -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 non-FDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $foundry->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $foundry->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $foundry->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. diff --git a/Info/Layer3/HP9300.pm b/Info/Layer3/HP9300.pm index 8c628b83..7fab5fae 100644 --- a/Info/Layer3/HP9300.pm +++ b/Info/Layer3/HP9300.pm @@ -196,134 +196,6 @@ sub interfaces { return $i_descr; } -# Use FDP and/or LLDP - -sub hasCDP { - my $hp9300 = shift; - - return $hp9300->hasLLDP() || $hp9300->SUPER::hasCDP(); -} - -sub c_ip { - my $hp9300 = shift; - my $partial = shift; - - my $cdp = $hp9300->SUPER::c_ip($partial) || {}; - my $lldp = $hp9300->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $hp9300 = shift; - my $partial = shift; - - my $lldp = $hp9300->lldp_if($partial) || {}; - my $cdp = $hp9300->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $hp9300 = shift; - my $partial = shift; - - my $lldp = $hp9300->lldp_port($partial) || {}; - my $cdp = $hp9300->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $hp9300 = shift; - my $partial = shift; - - my $lldp = $hp9300->lldp_id($partial) || {}; - my $cdp = $hp9300->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $hp9300 = shift; - my $partial = shift; - - my $lldp = $hp9300->lldp_rem_sysdesc($partial) || {}; - my $cdp = $hp9300->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - 1; __END__ @@ -527,54 +399,6 @@ Returns reference to hash. Current Port Speed. =back -=head2 Topology information - -Based upon the software version devices may support Foundry Discovery -Protocol (FDP) and Link Layer Discovery Protocol (LLDP). These -methods will query both and return the combination of 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. - -=over - -=item $hp9300->hasCDP() - -Returns true if the device is running either FDP or LLDP. - -=item $hp9300->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $hp9300->c_ip() - -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 non-FDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $hp9300->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $hp9300->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $hp9300->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. diff --git a/Info/Layer3/Juniper.pm b/Info/Layer3/Juniper.pm index 63702e7c..9fbe1bfb 100644 --- a/Info/Layer3/Juniper.pm +++ b/Info/Layer3/Juniper.pm @@ -53,8 +53,9 @@ $VERSION = '2.09'; %GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, %SNMP::Info::LLDP::GLOBALS, - 'serial' => 'jnxBoxSerialNo.0', - 'mac' => 'dot1dBaseBridgeAddress', + 'serial' => 'jnxBoxSerialNo.0', + 'mac' => 'dot1dBaseBridgeAddress', + 'box_descr' => 'jnxBoxDescr' ); %FUNCS = ( %SNMP::Info::Layer3::FUNCS, @@ -248,49 +249,6 @@ sub fw_port { return $juniper->qb_fw_port($partial); } -# Use LLDP - -sub hasCDP { - my $juniper = shift; - - return $juniper->hasLLDP(); -} - -sub c_ip { - my $juniper = shift; - my $partial = shift; - - return $juniper->lldp_ip($partial); -} - -sub c_if { - my $juniper = shift; - my $partial = shift; - - return $juniper->lldp_if($partial); -} - -sub c_port { - my $juniper = shift; - my $partial = shift; - - return $juniper->lldp_port($partial); -} - -sub c_id { - my $juniper = shift; - my $partial = shift; - - return $juniper->lldp_id($partial); -} - -sub c_platform { - my $juniper = shift; - my $partial = shift; - - return $juniper->lldp_rem_sysdesc($partial); -} - # Pseudo ENTITY-MIB methods # This class supports both virtual chassis (stackable) and physical chassis @@ -406,7 +364,7 @@ sub e_descr { my $juniper = shift; my $e_index = $juniper->e_index() || {}; - my $box_descr = $juniper->jnxBoxDescr || 0; + my $box_descr = $juniper->box_descr; my $contents = $juniper->jnxContentsDescr() || {}; my $containers = $juniper->jnxContainersDescr() || {}; @@ -663,16 +621,18 @@ Returns serial number (C) -=item $juniper->serial() +=item $juniper->mac() Returns the MAC address used by this bridge when it must be referred to in a unique fashion. (C) -=item $juniper->hasCDP() +=item $juniper->box_descr() -Returns whether LLDP is enabled. +The name, model, or detailed description of the device. + +(C) =back @@ -718,35 +678,6 @@ IDs. These are the VLANs which are members of the egress list for the port. =back -=head2 Topology information - -These methods return Link Layer Discovery Protocol (LLDP) information. See -documentation in L for details. - -=over - -=item $juniper->c_id() - -Returns C - -=item $juniper->c_if() - -Returns C - -=item $juniper->c_ip() - -Returns C - -=item $juniper->c_platform() - -Returns C - -=item $juniper->c_port() - -Returns C - -=back - =head2 Forwarding Table (C) =over diff --git a/Info/Layer3/NetSNMP.pm b/Info/Layer3/NetSNMP.pm index a344853d..1be4d1bf 100644 --- a/Info/Layer3/NetSNMP.pm +++ b/Info/Layer3/NetSNMP.pm @@ -130,42 +130,6 @@ sub i_ignore { return \%i_ignore; } -# Use LLDP -sub hasCDP { - my $netsnmp = shift; - return $netsnmp->hasLLDP(); -} - -sub c_ip { - my $netsnmp = shift; - my $partial = shift; - return $netsnmp->lldp_ip($partial); -} - -sub c_if { - my $netsnmp = shift; - my $partial = shift; - return $netsnmp->lldp_if($partial); -} - -sub c_port { - my $netsnmp = shift; - my $partial = shift; - return $netsnmp->lldp_port($partial); -} - -sub c_id { - my $netsnmp = shift; - my $partial = shift; - return $netsnmp->lldp_id($partial); -} - -sub c_platform { - my $netsnmp = shift; - my $partial = shift; - return $netsnmp->lldp_rem_sysdesc($partial); -} - 1; __END__ @@ -278,46 +242,6 @@ Ignores loopback =back -=head2 Topology information - -Link Layer Discovery Protocol (LLDP) support. The device must be running -an optional LLDP agent, such as lldpd, which can integrate with the SNMP agent. - -=over - -=item $netsnmp->hasCDP() - -Returns true if the device is running LLDP. - -=item $netsnmp->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $netsnmp->c_ip() - -Returns reference to hash. Key: iid Value: remote IPv4 address - -If multiple entries exist with the same local port, c_if(), with different -IPv4 addresses, c_ip(), there is either a non-LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $netsnmp->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $netsnmp->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $netsnmp->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. diff --git a/Info/Layer3/Nexus.pm b/Info/Layer3/Nexus.pm index 7eb94cb4..271473ca 100644 --- a/Info/Layer3/Nexus.pm +++ b/Info/Layer3/Nexus.pm @@ -174,132 +174,6 @@ sub model { return $model; } -# Use CDP and/or LLDP -sub hasCDP { - my $nexus = shift; - - return $nexus->hasLLDP() || $nexus->SUPER::hasCDP(); -} - -sub c_ip { - my $nexus = shift; - my $partial = shift; - - my $cdp = $nexus->SUPER::c_ip($partial) || {}; - my $lldp = $nexus->lldp_ip($partial) || {}; - - my %c_ip; - foreach my $iid ( keys %$cdp ) { - my $ip = $cdp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - - foreach my $iid ( keys %$lldp ) { - my $ip = $lldp->{$iid}; - next unless defined $ip; - - $c_ip{$iid} = $ip; - } - return \%c_ip; -} - -sub c_if { - my $nexus = shift; - my $partial = shift; - - my $lldp = $nexus->lldp_if($partial) || {}; - my $cdp = $nexus->SUPER::c_if($partial) || {}; - - my %c_if; - foreach my $iid ( keys %$cdp ) { - my $if = $cdp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - - foreach my $iid ( keys %$lldp ) { - my $if = $lldp->{$iid}; - next unless defined $if; - - $c_if{$iid} = $if; - } - return \%c_if; -} - -sub c_port { - my $nexus = shift; - my $partial = shift; - - my $lldp = $nexus->lldp_port($partial) || {}; - my $cdp = $nexus->SUPER::c_port($partial) || {}; - - my %c_port; - foreach my $iid ( keys %$cdp ) { - my $port = $cdp->{$iid}; - next unless defined $port; - - $c_port{$iid} = $port; - } - - foreach my $iid ( keys %$lldp ) { - my $port = $lldp->{$iid}; - next unless defined $port; - $c_port{$iid} = $port; - } - return \%c_port; -} - -sub c_id { - my $nexus = shift; - my $partial = shift; - - my $lldp = $nexus->lldp_id($partial) || {}; - my $cdp = $nexus->SUPER::c_id($partial) || {}; - - my %c_id; - foreach my $iid ( keys %$cdp ) { - my $id = $cdp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - - foreach my $iid ( keys %$lldp ) { - my $id = $lldp->{$iid}; - next unless defined $id; - - $c_id{$iid} = $id; - } - return \%c_id; -} - -sub c_platform { - my $nexus = shift; - my $partial = shift; - - my $lldp = $nexus->lldp_rem_sysdesc($partial) || {}; - my $cdp = $nexus->SUPER::c_platform($partial) || {}; - - my %c_platform; - foreach my $iid ( keys %$cdp ) { - my $platform = $cdp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - - foreach my $iid ( keys %$lldp ) { - my $platform = $lldp->{$iid}; - next unless defined $platform; - - $c_platform{$iid} = $platform; - } - return \%c_platform; -} - 1; __END__ @@ -473,53 +347,6 @@ See documentation in L for details. These are methods that return tables of information in the form of a reference to a hash. -=head2 Topology information - -Based upon the firmware version Cisco devices may support Link Layer Discover -Protocol (LLDP) in addition to the Cisco-proprietary CDP. These methods -will query both and return the combination of 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. - -=over - -=item $nexus->hasCDP() - -Returns true if the device is running either CDP or LLDP. - -=item $nexus->c_if() - -Returns reference to hash. Key: iid Value: local device port (interfaces) - -=item $nexus->c_ip() - -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 non-CDP/LLDP device in between two -or more devices or multiple devices which are not directly connected. - -Use the data from the Layer2 Topology Table below to dig deeper. - -=item $nexus->c_port() - -Returns reference to hash. Key: iid Value: remote port (interfaces) - -=item $nexus->c_id() - -Returns reference to hash. Key: iid Value: string value used to identify the -chassis component associated with the remote system. - -=item $nexus->c_platform() - -Returns reference to hash. Key: iid Value: Remote Device Type - -=back - =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. diff --git a/Info/Layer3/Passport.pm b/Info/Layer3/Passport.pm index 6798feb5..20c043a3 100644 --- a/Info/Layer3/Passport.pm +++ b/Info/Layer3/Passport.pm @@ -1,7 +1,6 @@ # SNMP::Info::Layer3::Passport -# $Id$ # -# Copyright (c) 2008 Eric Miller +# Copyright (c) 2012 Eric Miller # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,6 +29,7 @@ package SNMP::Info::Layer3::Passport; +use warnings; use strict; use Exporter; use SNMP::Info::SONMP; @@ -80,7 +80,7 @@ sub model { return $id unless defined $model; - $model =~ s/^rcA//i; + $model =~ s/^rc(A)?//i; return $model; } @@ -126,9 +126,9 @@ sub i_index { # Get VLAN Virtual Router Interfaces if (!defined $partial - or (defined $model - and ( ( $partial > 2000 and $model =~ /(86|83|81|16)/ ) - or ( $partial > 256 and $model =~ /(105|11[05]0|12[05])/ ) ) + || (defined $model + && ( ( $partial > 2000 && $model =~ /(86|83|81|16|VSP)/ ) + || ( $partial > 256 && $model =~ /(105|11[05]0|12[05])/ ) ) ) ) { @@ -182,9 +182,9 @@ sub interfaces { my $vlan_id = {}; if (!defined $partial - or (defined $model - and ( ( $partial > 2000 and $model =~ /(86|83|81|16)/ ) - or ( $partial > 256 and $model =~ /(105|11[05]0|12[05])/ ) ) + || (defined $model + && ( ( $partial > 2000 && $model =~ /(86|83|81|16|VSP)/ ) + || ( $partial > 256 && $model =~ /(105|11[05]0|12[05])/ ) ) ) ) { @@ -214,7 +214,7 @@ sub interfaces { $if{$index} = 'Cpu.6'; } - elsif (( $index > 2000 and $model =~ /(86|83|81|16)/ ) + elsif (( $index > 2000 and $model =~ /(86|83|81|16|VSP)/ ) or ( $index > 256 and $model =~ /(105|11[05]0|12[05])/ ) ) { @@ -255,9 +255,9 @@ sub i_mac { # Get VLAN Virtual Router Interfaces if (!defined $partial - or (defined $model - and ( ( $partial > 2000 and $model =~ /(86|83|81|16)/ ) - or ( $partial > 256 and $model =~ /(105|11[05]0|12[05])/ ) ) + || (defined $model + && ( ( $partial > 2000 && $model =~ /(86|83|81|16|VSP)/ ) + || ( $partial > 256 && $model =~ /(105|11[05]0|12[05])/ ) ) ) ) { @@ -329,9 +329,9 @@ sub i_description { # Get VLAN Virtual Router Interfaces if (!defined $partial - or (defined $model - and ( ( $partial > 2000 and $model =~ /(86|83|81|16)/ ) - or ( $partial > 256 and $model =~ /(105|11[05]0|12[05])/ ) ) + || (defined $model + && ( ( $partial > 2000 && $model =~ /(86|83|81|16|VSP)/ ) + || ( $partial > 256 && $model =~ /(105|11[05]0|12[05])/ ) ) ) ) { @@ -365,9 +365,9 @@ sub i_name { my %reverse_vlan; if (!defined $partial - or (defined $model - and ( ( $partial > 2000 and $model =~ /(86|83|81|16)/ ) - or ( $partial > 256 and $model =~ /(105|11[05]0|12[05])/ ) ) + || (defined $model + && ( ( $partial > 2000 && $model =~ /(86|83|81|16|VSP)/ ) + || ( $partial > 256 && $model =~ /(105|11[05]0|12[05])/ ) ) ) ) { @@ -402,8 +402,8 @@ sub i_name { and $model =~ /(105|11[05]0|12[05])/ ) ) { - my $vlan_index = $reverse_vlan{$iid}; - my $vlan_name = $v_name->{$vlan_index}; + my $vlan_idx = $reverse_vlan{$iid}; + my $vlan_name = $v_name->{$vlan_idx}; next unless defined $vlan_name; $i_name{$iid} = $vlan_name; @@ -510,7 +510,7 @@ sub root_ip { my $sonmp_topo_ip = $passport->sonmp_topo_ip(); # Only 8600 and 1600 have CLIP or Management Virtual IP - if ( defined $model and $model =~ /(86|16)/ ) { + if ( defined $model and $model =~ /(86|16|VSP)/ ) { # Return CLIP (CircuitLess IP) foreach my $iid ( keys %$rc_ip_type ) { @@ -683,7 +683,7 @@ sub e_descr { my $model = $passport->model(); my $rc_ps = $passport->rc_ps_detail() || {}; - my $rc_ch = $passport->rcChasType(); + my $rc_ch = $passport->chassis(); $rc_ch =~ s/a//; my %rc_e_descr; @@ -752,7 +752,7 @@ sub e_type { my $model = $passport->model(); my $rc_ps = $passport->rc_ps_type() || {}; - my $rc_ch = $passport->rcChasType(); + my $rc_ch = $passport->chassis(); my %rc_e_type; diff --git a/Info/Layer3/Pf.pm b/Info/Layer3/Pf.pm index ce84ec2e..6138cabf 100644 --- a/Info/Layer3/Pf.pm +++ b/Info/Layer3/Pf.pm @@ -118,42 +118,6 @@ sub os_ver { return $os_ver; } -# Use LLDP -sub hasCDP { - my $pf = shift; - return $pf->hasLLDP(); -} - -sub c_ip { - my $pf = shift; - my $partial = shift; - return $pf->lldp_ip($partial); -} - -sub c_if { - my $pf = shift; - my $partial = shift; - return $pf->lldp_if($partial); -} - -sub c_port { - my $pf = shift; - my $partial = shift; - return $pf->lldp_port($partial); -} - -sub c_id { - my $pf = shift; - my $partial = shift; - return $pf->lldp_id($partial); -} - -sub c_platform { - my $pf = shift; - my $partial = shift; - return $pf->lldp_rem_sysdesc($partial); -} - 1; __END__ @@ -230,10 +194,6 @@ These are methods that return scalar values from SNMP Returns 'FreeBSD' -=item $pf->hasCDP() - - Returns whether LLDP is enabled. - =item $pf->model() Grabs the os version from C @@ -259,30 +219,6 @@ See documentation in L for details. These are methods that return tables of information in the form of a reference to a hash. -=over - -=item $pf->c_id() - -Returns LLDP information. - -=item $pf->c_if() - -Returns LLDP information. - -=item $pf->c_ip() - -Returns LLDP information. - -=item $pf->c_platform() - -Returns LLDP information. - -=item $pf->c_port() - -Returns LLDP information. - -=back - =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. diff --git a/Info/Layer3/Tasman.pm b/Info/Layer3/Tasman.pm index f1895e70..d96bdded 100644 --- a/Info/Layer3/Tasman.pm +++ b/Info/Layer3/Tasman.pm @@ -55,10 +55,14 @@ $VERSION = '2.09'; %GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, %SNMP::Info::MAU::GLOBALS, - 'ps1_type' => 'nnenvPwrsupType.1', - 'ps1_status' => 'nnenvPwrsupStatus.1', - 'ps2_type' => 'nnenvPwrsupType.2', - 'ps2_status' => 'nnenvPwrsupStatus.2', + 'ps1_type' => 'nnenvPwrsupType.1', + 'ps1_status' => 'nnenvPwrsupStatus.1', + 'ps2_type' => 'nnenvPwrsupType.2', + 'ps2_status' => 'nnenvPwrsupStatus.2', + 'nn_sys_ver' => 'nnsysVersion', + 'nn_ch_model' => 'nnchassisModel', + 'nn_ch_op_stat' => 'nnchassisOperStatus', + 'nn_ch_serial' => 'nnchassisSerialNumber', ); %FUNCS = ( @@ -87,7 +91,7 @@ sub os { sub os_ver { my $tasman = shift; - my $version = $tasman->nnsysVersion() || ""; + my $version = $tasman->nn_sys_ver() || ""; my $descr = $tasman->description() || ""; # Newer versions @@ -102,7 +106,7 @@ sub model { my $tasman = shift; my $id = $tasman->id(); - my $ch_model = $tasman->nnchassisModel(); + my $ch_model = $tasman->nn_ch_model(); return $ch_model if $ch_model; @@ -118,12 +122,12 @@ sub serial { # Newer versions of the software redefined the MIB in a non-backwards # compatible manner. Try the old OID first. - my $serial = $tasman->nnchassisOperStatus(); + my $serial = $tasman->nn_ch_op_stat(); # Newer versions populate status, serial should contain some numbers return $serial if ($serial !~ /^\D+$/); # Unfortunately newer versions don't seem to populate the newer OID. - return $tasman->nnchassisSerialNumber(); + return $tasman->nn_ch_serial(); } 1; @@ -225,9 +229,25 @@ Grabs the os version from C (C) =item $tasman->ps2_status() - + (C) +=item $tasman->nn_sys_ver() + +(C) + +=item $tasman->nn_ch_model() + +(C) + +=item $tasman->nn_ch_op_stat() + +(C) + +=item $tasman->nn_ch_serial() + +(C) + =item $tasman->serial() Tries both (C) and (C) as OID's diff --git a/Info/SONMP.pm b/Info/SONMP.pm index 536f7981..4afcda20 100644 --- a/Info/SONMP.pm +++ b/Info/SONMP.pm @@ -1,7 +1,6 @@ # SNMP::Info::SONMP -# $Id$ # -# Copyright (c) 2008 Eric Miller +# Copyright (c) 2012 Eric Miller # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,6 +29,7 @@ package SNMP::Info::SONMP; +use warnings; use strict; use Exporter; use SNMP::Info; @@ -47,8 +47,8 @@ $VERSION = '2.09'; ); %GLOBALS = ( - 'cdp_id' => 's5EnMsTopIpAddr', - 'cdp_run' => 's5EnMsTopStatus', + 'sonmp_gid' => 's5EnMsTopIpAddr', + 'sonmp_run' => 's5EnMsTopStatus', ); %FUNCS = ( @@ -77,12 +77,14 @@ sub port_offset { return 0; } -sub hasCDP { +sub hasSONMP { my $sonmp = shift; - return $sonmp->cdp_run(); + + return 1 if defined $sonmp->sonmp_run(); + return; } -sub c_if { +sub sonmp_if { my $sonmp = shift; my $partial = shift; @@ -93,7 +95,7 @@ sub c_if { my $port_offset = $sonmp->port_offset(); my $model = $sonmp->model(); - my %c_if; + my %sonmp_if; foreach my $entry ( keys %$sonmp_topo_port ) { my $port = $sonmp_topo_port->{$entry}; next unless defined $port; @@ -118,31 +120,31 @@ sub c_if { my $index = ( ( $slot - $slot_offset ) * $index_factor ) + ( $port - $port_offset ); - $c_if{$entry} = $index; + $sonmp_if{$entry} = $index; } - return \%c_if; + return \%sonmp_if; } -sub c_ip { +sub sonmp_ip { my $sonmp = shift; my $partial = shift; my $sonmp_topo_port = $sonmp->sonmp_topo_port($partial) || {}; my $sonmp_topo_ip = $sonmp->sonmp_topo_ip($partial) || {}; - my %c_ip; + my %sonmp_ip; foreach my $entry ( keys %$sonmp_topo_ip ) { my $port = $sonmp_topo_port->{$entry}; next unless defined $port; next if $port == 0; my $ip = $sonmp_topo_ip->{$entry}; - $c_ip{$entry} = $ip; + $sonmp_ip{$entry} = $ip; } - return \%c_ip; + return \%sonmp_ip; } -sub c_port { +sub sonmp_port { my $sonmp = shift; my $partial = shift; @@ -150,7 +152,7 @@ sub c_port { my $sonmp_topo_seg = $sonmp->sonmp_topo_seg($partial) || {}; my $sonmp_topo_platform = $sonmp->sonmp_topo_platform($partial) || {}; - my %c_port; + my %sonmp_port; foreach my $entry ( keys %$sonmp_topo_seg ) { my $port = $sonmp_topo_port->{$entry}; next unless defined $port; @@ -161,12 +163,12 @@ sub c_port { # AP-222x Series does not adhere to port numbering if ( $platform =~ /AccessPoint/i ) { - $c_port{$entry} = 'dp0'; + $sonmp_port{$entry} = 'dp0'; } # BayHubs send the lower three bytes of the MAC not the slot/port elsif ( $seg > 4000 ) { - $c_port{$entry} = 'unknown'; + $sonmp_port{$entry} = 'unknown'; } else { @@ -174,20 +176,20 @@ sub c_port { my $remote_port = $seg % 256; my $remote_slot = int( $seg / 256 ); - $c_port{$entry} = "$remote_slot.$remote_port"; + $sonmp_port{$entry} = "$remote_slot.$remote_port"; } } - return \%c_port; + return \%sonmp_port; } -sub c_platform { +sub sonmp_platform { my $sonmp = shift; my $partial = shift; my $sonmp_topo_port = $sonmp->sonmp_topo_port($partial) || {}; my $sonmp_topo_platform = $sonmp->sonmp_topo_platform($partial) || {}; - my %c_platform; + my %sonmp_platform; foreach my $entry ( keys %$sonmp_topo_platform ) { my $port = $sonmp_topo_port->{$entry}; next unless defined $port; @@ -195,9 +197,9 @@ sub c_platform { my $platform = $sonmp_topo_platform->{$entry}; - $c_platform{$entry} = $platform; + $sonmp_platform{$entry} = $platform; } - return \%c_platform; + return \%sonmp_platform; } sub mac { @@ -242,19 +244,19 @@ Eric Miller my $class = $sonmp->class(); print " Using device sub class : $class\n"; - $hascdp = $sonmp->hasCDP() ? 'yes' : 'no'; + $hassonmp = $sonmp->hasSONMP() ? 'yes' : 'no'; # Print out a map of device ports with CDP neighbors: my $interfaces = $sonmp->interfaces(); - my $c_if = $sonmp->c_if(); - my $c_ip = $sonmp->c_ip(); - my $c_port = $sonmp->c_port(); + my $sonmp_if = $sonmp->sonmp_if(); + my $sonmp_ip = $sonmp->sonmp_ip(); + my $sonmp_port = $sonmp->sonmp_port(); - foreach my $cdp_key (keys %$c_ip){ - my $iid = $c_if->{$cdp_key}; + foreach my $sonmp_key (keys %$sonmp_ip){ + my $iid = $sonmp_if->{$sonmp_key}; my $port = $interfaces->{$iid}; - my $neighbor = $c_ip->{$cdp_key}; - my $neighbor_port = $c_port->{$cdp_key}; + my $neighbor = $sonmp_ip->{$sonmp_key}; + my $neighbor_port = $sonmp_port->{$sonmp_key}; print "Port : $port connected to $neighbor / $neighbor_port\n"; } @@ -266,8 +268,8 @@ through SNMP. SONMP is a Layer 2 protocol that supplies topology information of devices that also speak SONMP, mostly switches and hubs. SONMP is implemented in -SynOptics, Bay, and Nortel devices. SONMP has been rebranded by Bay then -Nortel and is know by several different names, most recently Nortel +SynOptics, Bay, Nortel, and Avaya devices. SONMP has been rebranded by Bay +then Nortel and may be referred to by several different names, including Nortel Discovery Protocol (NDP). Create or use a device subclass that inherits this class. Do not use @@ -309,17 +311,17 @@ Returns the offset if slot numbering does not start at 0. Defaults to 1. Returns the offset if port numbering does not start at 0. Defaults to 0. -=item $cdp->hasCDP() +=item $sonmp->hasSONMP() Is SONMP is active in this device? -=item $sonmp->cdp_id() +=item $sonmp->sonmp_gid() Returns the IP that the device is sending out for its Nmm topology info. (C) -=item $sonmp->cdp_run() +=item $sonmp->sonmp_run() Returns true if SONMP is on for this device. @@ -386,31 +388,31 @@ bay_topo_seg() is local. =back -=head2 Pseudo CDP information +=head2 Common topology information All entries with port=0 are local and ignored. =over -=item $sonmp->c_if() +=item $sonmp->sonmp_if() Returns reference to hash. Key: IID, Value: Local port (interfaces) -=item $sonmp->c_ip() +=item $sonmp->sonmp_ip() Returns reference to hash. Key: IID, Value: Remote IP address -If multiple entries exist with the same local port, c_if(), with different -IPv4 addresses, c_ip(), there is either a non SONMP device in between two or +If multiple entries exist with the same local port, sonmp_if(), with different +IPv4 addresses, sonmp_ip(), there is either a non SONMP device in between two or more devices or multiple devices which are not directly connected. Use the data from the Layer2 Topology Table below to dig deeper. -=item $sonmp->c_port() +=item $sonmp->sonmp_port() Returns reference to hash. Key: IID, Value: Remote port (interfaces) -=item $sonmp->c_platform() +=item $sonmp->sonmp_platform() Returns reference to hash. Key: IID, Value: Remote device type