diff --git a/ChangeLog b/ChangeLog index 1166be7f..30d557fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ SNMP::Info - Friendly OO-style interface to Network devices using SNMP. +version 2.09 + + [NEW FEATURES] + + * Add EDP and LLDP L2 Topology to L3::Extreme + * [1424336] Support for Extreme Discovery Protocol (EDP) + + [ENHANCEMENTS] + + * [3418918] Extreme devices now report OS as either extremeware or xos + + [BUG FIXES] + + + version 2.08 (2012-07-15) [NEW FEATURES] diff --git a/Info/EDP.pm b/Info/EDP.pm new file mode 100644 index 00000000..bd3c68c3 --- /dev/null +++ b/Info/EDP.pm @@ -0,0 +1,295 @@ +# SNMP::Info::EDP +# +# Copyright (c) 2012 Eric Miller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the University of California, Santa Cruz nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +package SNMP::Info::EDP; + +use strict; +use Exporter; +use SNMP::Info; + +@SNMP::Info::LLDP::ISA = qw/SNMP::Info Exporter/; +@SNMP::Info::LLDP::EXPORT_OK = qw//; + +use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE/; + +$VERSION = '2.09'; + +%MIBS = ( + 'EXTREME-EDP-MIB' => 'extremeEdpPortIfIndex', +); + +%GLOBALS = ( + +); + +%FUNCS = ( + # EXTREME-EDP-MIB::extremeEdpTable + 'edp_rem_sysname' => 'extremeEdpNeighborName', +); + +%MUNGE = ( + 'edp_rem_sysname' => \&SNMP::Info::munge_null, +); + +sub hasEDP { + my $edp = shift; + + my $edp_ip = $edp->extremeEdpNeighborVlanIpAddress() || {}; + + return 1 if ( scalar( keys %$edp_ip ) ); + + return; +} + +# Since we need to get IP Addresses from the extremeEdpNeighborTable which has +# a different index (adds VLAN name) than the extremeEdpTable which holds +# the remote device details use the index from extremeEdpNeighborTable but skip +# indexes which have an address of 0.0.0.0. Would like to include only one +# address since they should all originate from the same device, but we don't +# know if they would all be reachable from the network management application. +# +# We don't inplement partials since this is private index function +sub _edp_index { + my $edp = shift; + + my $edp_ip = $edp->extremeEdpNeighborVlanIpAddress() || {}; + + my %edp_index; + foreach my $key ( keys %$edp_ip ) { + my $ip = $edp_ip->{$key}; + next if ($ip eq '0.0.0.0'); + next unless $ip; + $edp_index{$key} = $key; + } + return \%edp_index; +} + +sub edp_if { + my $edp = shift; + + my $index = $edp->_edp_index() || {}; + + my %edp_if; + foreach my $key (keys %$index) { + my $iid = $key; + # ifIndex is first part of the iid + $iid = $1 if $iid =~ /^(\d+)\./; + $edp_if{$key} = $iid; + } + + return \%edp_if; +} + +sub edp_ip { + my $edp = shift; + + my $index = $edp->_edp_index() || {}; + my $edp_ip = $edp->extremeEdpNeighborVlanIpAddress() || {}; + + my %edp_ip; + foreach my $key ( keys %$index ) { + my $ip = $edp_ip->{$key}; + # MIB says should only be IPv4 + next unless ($ip =~ /\d+(\.\d+){3}/); + $edp_ip{$key} = $ip; + } + return \%edp_ip; +} + +sub edp_port { + my $edp = shift; + + my $index = $edp->_edp_index() || {}; + my $edp_rport = $edp->extremeEdpNeighborPort() || {}; + my $edp_rslot = $edp->extremeEdpNeighborSlot() || {}; + + my %edp_port; + foreach my $key ( sort keys %$edp_rport ) { + my $port = $edp_rport->{$key}; + my $slot = $edp_rslot->{$key} || 0; + next unless $port; + my $slotport = defined $slot ? "$slot\/$port" : $port; + + foreach my $iid ( sort keys %$index ) { + $edp_port{$iid} = $slotport if ($iid =~ /^$key/); + } + } + return \%edp_port; +} + +sub edp_id { + my $edp = shift; + + my $index = $edp->_edp_index() || {}; + my $edp_name = $edp->edp_rem_sysname() || {}; + + my %edp_name; + foreach my $key ( sort keys %$edp_name ) { + my $name = $edp_name->{$key} || 0; + next unless $name; + + foreach my $iid ( sort keys %$index ) { + $edp_name{$iid} = $name if ($iid =~ /^$key/); + } + } + return \%edp_name; +} + +sub edp_ver { + my $edp = shift; + + my $index = $edp->_edp_index() || {}; + my $edp_ver = $edp->extremeEdpNeighborSoftwareVersion() || {}; + + my %edp_ver; + foreach my $key ( sort keys %$edp_ver ) { + my $ver = $edp_ver->{$key} || 0; + next unless $ver; + + foreach my $iid ( sort keys %$index ) { + $edp_ver{$iid} = $ver if ($iid =~ /^$key/); + } + } + return \%edp_ver; +} + +1; +__END__ + +=head1 NAME + +SNMP::Info::EDP - SNMP Interface to the Extreme Discovery Protocol (EDP) + +=head1 AUTHOR + +Eric Miller + +=head1 SYNOPSIS + + my $edp = new SNMP::Info ( + AutoSpecify => 1, + Debug => 1, + DestHost => 'router', + Community => 'public', + Version => 2 + ); + + my $class = $edp->class(); + print " Using device sub class : $class\n"; + + $haslldp = $edp->hasLLDP() ? 'yes' : 'no'; + + # Print out a map of device ports with LLDP neighbors: + my $interfaces = $edp->interfaces(); + my $edp_if = $edp->edp_if(); + my $edp_ip = $edp->edp_ip(); + my $edp_port = $edp->edp_port(); + + foreach my $edp_key (keys %$edp_ip){ + my $iid = $edp_if->{$edp_key}; + my $port = $interfaces->{$iid}; + my $neighbor = $edp_ip->{$edp_key}; + my $neighbor_port = $edp_port->{$edp_key}; + print "Port : $port connected to $neighbor / $neighbor_port\n"; + } + +=head1 DESCRIPTION + +SNMP::Info::EDP is a subclass of SNMP::Info that provides an object oriented +interface to EDP information through SNMP. + +EDP is a Layer 2 protocol that allows a network device to advertise its +identity and capabilities on the local network providing topology information. + +Create or use a device subclass that inherits this class. Do not use +directly. + +=head2 Inherited Classes + +None. + +=head2 Required MIBs + +=over + +=item F + +=back + +=head1 GLOBAL METHODS + +These are methods that return scalar values from SNMP + +=over + +=item $edp->hasEDP() + +Is EDP is active in this device? + +=back + +=head1 TABLE METHODS + +These are methods that return tables of information in the form of a reference +to a hash. + +=over + +=item $edp->edp_id() + +Returns the string value used to identify the chassis component associated +with the remote system. + +(C) + +=item $edp->edp_if() + +Returns the mapping to the SNMP Interface Table. + +=item $edp->edp_ip() + +Returns remote IPv4 address. + +=item $edp->edp_port() + +Returns remote port ID + +=item $edp->edp_ver() + +Returns the operating system version of the remote system. + +Nulls are removed before the value is returned. + +(C) + +=back + +=cut + diff --git a/Info/Layer3/Extreme.pm b/Info/Layer3/Extreme.pm index 57ee2572..3393a902 100644 --- a/Info/Layer3/Extreme.pm +++ b/Info/Layer3/Extreme.pm @@ -36,9 +36,12 @@ use strict; use Exporter; use SNMP::Info::Layer3; use SNMP::Info::MAU; +use SNMP::Info::LLDP; +use SNMP::Info::EDP; @SNMP::Info::Layer3::Extreme::ISA - = qw/SNMP::Info::Layer3 SNMP::Info::MAU Exporter/; + = qw/SNMP::Info::Layer3 SNMP::Info::MAU SNMP::Info::LLDP + SNMP::Info::EDP Exporter/; @SNMP::Info::Layer3::Extreme::EXPORT_OK = qw//; use vars qw/$VERSION %GLOBALS %FUNCS %MIBS %MUNGE/; @@ -48,6 +51,8 @@ $VERSION = '2.08'; %MIBS = ( %SNMP::Info::Layer3::MIBS, %SNMP::Info::MAU::MIBS, + %SNMP::Info::LLDP::MIBS, + %SNMP::Info::EDP::MIBS, 'EXTREME-BASE-MIB' => 'extremeAgent', 'EXTREME-SYSTEM-MIB' => 'extremeSystem', 'EXTREME-FDB-MIB' => 'extremeSystem', @@ -58,6 +63,8 @@ $VERSION = '2.08'; %GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, %SNMP::Info::MAU::GLOBALS, + %SNMP::Info::LLDP::GLOBALS, + %SNMP::Info::EDP::GLOBALS, 'serial1' => 'extremeSystemID.0', 'temp' => 'extremeCurrentTemperature', 'ps1_status_old' => 'extremePrimaryPowerOperational.0', @@ -70,6 +77,8 @@ $VERSION = '2.08'; %FUNCS = ( %SNMP::Info::Layer3::FUNCS, %SNMP::Info::MAU::FUNCS, + %SNMP::Info::LLDP::FUNCS, + %SNMP::Info::EDP::FUNCS, 'fan_state' => 'extremeFanOperational', # EXTREME-FDB-MIB:extremeFdbMacFdbTable @@ -92,6 +101,8 @@ $VERSION = '2.08'; # Inherit all the built in munging %SNMP::Info::Layer3::MUNGE, %SNMP::Info::MAU::MUNGE, + %SNMP::Info::LLDP::MUNGE, + %SNMP::Info::EDP::MUNGE, 'ex_fw_mac' => \&SNMP::Info::munge_mac, 'ps1_status_old' => \&munge_true_ok, 'ps1_status_new' => \&munge_power_stat, @@ -538,6 +549,125 @@ 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__ @@ -584,6 +714,10 @@ my $extreme = new SNMP::Info::Layer3::Extreme(...); =item SNMP::Info::MAU +=item SNMP::Info::LLDP + +=item SNMP::Info::EDP + =back =head2 Required MIBs @@ -666,12 +800,6 @@ Returns base mac =back -=head2 Overrides - -=over - -=back - =head2 Globals imported from SNMP::Info::Layer3 See documentation in L for details. @@ -680,6 +808,14 @@ See documentation in L for details. See documentation in L for details. +=head2 Globals imported from SNMP::Info::LLDP + +See documentation in L for details. + +=head2 Globals imported from SNMP::Info::EDP + +See documentation in L for details. + =head1 TABLE METHODS These are methods that return tables of information in the form of a reference @@ -768,6 +904,58 @@ Power supplied by PoE ports, in milliwatts =back +=head2 Topology information + +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. + +=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. + +=back + =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. @@ -776,6 +964,14 @@ See documentation in L for details. See documentation in L for details. +=head2 Table Methods imported from SNMP::Info::LLDP + +See documentation in L for details. + +=head2 Table Methods imported from SNMP::Info::EDP + +See documentation in L for details. + =head1 SET METHODS These are methods that provide SNMP set functionality for overridden methods @@ -826,7 +1022,6 @@ with the numeric VLAN ID and port C. $extreme->set_remove_i_vlan_tagged('2', $if_map{'FastEthernet0/1'}) or die "Couldn't add port to egress list. ",$extreme->error(1); - =back =head1 Data Munging Callback Subroutines