From 9c306812f9b08d8783ad9ca29d306b968fa610de Mon Sep 17 00:00:00 2001 From: Jeroen van Ingen Date: Fri, 11 Jun 2021 14:54:48 +0200 Subject: [PATCH 1/2] Add support for Aruba CX switches --- lib/SNMP/Info.pm | 2 + lib/SNMP/Info/Layer3/ArubaCX.pm | 328 ++++++++++++++++++++++++++++++++ 2 files changed, 330 insertions(+) create mode 100644 lib/SNMP/Info/Layer3/ArubaCX.pm diff --git a/lib/SNMP/Info.pm b/lib/SNMP/Info.pm index 3bb30c5c..92ee26e1 100644 --- a/lib/SNMP/Info.pm +++ b/lib/SNMP/Info.pm @@ -1729,6 +1729,7 @@ sub device_type { 40310 => 'SNMP::Info::Layer3::Cumulus', 41112 => 'SNMP::Info::Layer2::Ubiquiti', 44641 => 'SNMP::Info::Layer3::VyOS', + 47196 => 'SNMP::Info::Layer3::ArubaCX', 48690 => 'SNMP::Info::Layer3::Teltonika', ); @@ -1767,6 +1768,7 @@ sub device_type { 21091 => 'SNMP::Info::Layer2::Exinda', 26543 => 'SNMP::Info::Layer3::IBMGbTor', 26928 => 'SNMP::Info::Layer2::Aerohive', + 47196 => 'SNMP::Info::Layer3::ArubaCX', 48690 => 'SNMP::Info::Layer3::Teltonika', ); diff --git a/lib/SNMP/Info/Layer3/ArubaCX.pm b/lib/SNMP/Info/Layer3/ArubaCX.pm new file mode 100644 index 00000000..c79bba01 --- /dev/null +++ b/lib/SNMP/Info/Layer3/ArubaCX.pm @@ -0,0 +1,328 @@ +# SNMP::Info::Layer3::ArubaCX +# +# Copyright (c) 2021 Jeroen van Ingen +# 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::Layer3::ArubaCX; + +use strict; +use warnings; +use Exporter; +use SNMP::Info::IEEE802dot3ad 'agg_ports_lag'; +use SNMP::Info::Layer3; +use SNMP::Info::IEEE802_Bridge; + +@SNMP::Info::Layer3::ArubaCX::ISA = qw/ + SNMP::Info::IEEE802dot3ad + SNMP::Info::Layer3 + SNMP::Info::IEEE802_Bridge + Exporter +/; +@SNMP::Info::Layer3::ArubaCX::EXPORT_OK = qw/ + agg_ports +/; + +our ($VERSION, %GLOBALS, %MIBS, %FUNCS, %MUNGE); + +$VERSION = '3.71'; + +%MIBS = ( + %SNMP::Info::Layer3::MIBS, + %SNMP::Info::IEEE802dot3ad::MIBS, + %SNMP::Info::IEEE802_Bridge::MIBS, + 'ARUBAWIRED-FAN-MIB' => 'arubaWiredFanName', + 'ARUBAWIRED-VSF-MIB' => 'arubaWiredVsfTrapEnable', + 'ARUBAWIRED-POWERSUPPLY-MIB' => 'arubaWiredPSUName', +); + +%GLOBALS = ( + %SNMP::Info::Layer3::GLOBALS, + %SNMP::Info::IEEE802_Bridge::GLOBALS, + 'ps1_type' => 'arubaWiredPSUProductName.1.1', + 'ps2_type' => 'arubaWiredPSUProductName.1.2', + 'ps1_status' => 'arubaWiredPSUState.1.1', + 'ps2_status' => 'arubaWiredPSUState.1.2', + 'vsf_topology' => 'arubaWiredVsfTopology', +); + +%FUNCS = ( + %SNMP::Info::Layer3::FUNCS, + %SNMP::Info::IEEE802dot3ad::FUNCS, + %SNMP::Info::IEEE802_Bridge::FUNCS, + 'fan_names' => 'arubaWiredFanName', + 'fan_states' => 'arubaWiredFanState', + 'psu_names' => 'arubaWiredPSUName', + 'psu_types' => 'arubaWiredPSUProductName', + 'psu_states' => 'arubaWiredPSUState', + 'vsf_prod_names' => 'arubaWiredVsfMemberProductName', +); + +%MUNGE = ( + %SNMP::Info::Layer3::MUNGE, + %SNMP::Info::IEEE802dot3ad::MUNGE, + %SNMP::Info::IEEE802_Bridge::MUNGE, +); + +sub _at_pbb_one { + my $in = shift // {}; + my $ret = {}; + foreach my $key (keys %$in) { + if ($key =~ /^1\.(\d+)$/) { + $ret->{$1} = $in->{$key}; + } + } + return $ret; +} + +sub fan { + my $cx = shift; + my $names = $cx->fan_names() || {}; + my $states = $cx->fan_states() || {}; + my @ary = (); + foreach my $idx (sort keys %$names) { + my $name = $names->{$idx} // 'n/a'; + my $state = $states->{$idx} // 'n/a'; + push @ary, sprintf("%s: %s", $name, $state); + } + return join (', ', @ary); +} + +sub vendor { + my $cx = shift; + my $mfg = $cx->entPhysicalMfgName(1) || {}; + my $vendor = $mfg->{1} || "aruba"; + return lc($vendor); +} + +sub stack_info { + my $cx = shift; + my $vsf_topo = $cx->vsf_topology(); + if (defined $vsf_topo and $vsf_topo ne 'standalone') { + my $member_prod_names = $cx->vsf_prod_names() || {}; + my $num_members = scalar keys %$member_prod_names; + my $fullname = (values %$member_prod_names)[0]; + my $modelname = ''; + if ($fullname =~ /^(\S+)/) { + $modelname = $1; + } + return sprintf("%s (stack of %d)", $modelname, $num_members); + } else { + return undef; + } +} + +sub model { + my $cx = shift; + my $model = $cx->entPhysicalModelName(1) || {}; + my $id = $cx->id(); + my $translated_id = &SNMP::translateObj($id) || $id; + $translated_id =~ s/arubaWiredSwitch//i; + return $cx->stack_info() || $model->{1} || $translated_id; +} + +sub os { + return "arubaos-cx"; +} + +sub os_ver { + my $cx = shift; + my $ver_release = $cx->entPhysicalSoftwareRev(1) || {}; + return $ver_release->{1}; +} + +sub agg_ports { return agg_ports_lag(@_) } + +# Overrides for VLAN & forwarding table methods +sub v_name { + my $cx = shift; + return _at_pbb_one($cx->iqb_v_name()) || $cx->SUPER::v_name(); +} +sub qb_i_vlan { + my $cx = shift; + return _at_pbb_one($cx->iqb_i_vlan()) || $cx->SUPER::qb_i_vlan(); +} +sub i_vlan_type { + my $cx = shift; + return _at_pbb_one($cx->iqb_i_vlan_type()) || $cx->SUPER::qb_i_vlan_type(); +} +sub qb_v_egress { + my $cx = shift; + return $cx->iqb_v_egress() || $cx->SUPER::qb_v_egress(); +} +sub qb_cv_egress { + my $cx = shift; + return $cx->iqb_cv_egress() || $cx->SUPER::qb_cv_egress(); +} +sub qb_v_untagged { + my $cx = shift; + return $cx->iqb_v_untagged() || $cx->SUPER::qb_v_untagged(); +} +sub qb_cv_untagged { + my $cx = shift; + return $cx->iqb_cv_untagged() || $cx->SUPER::qb_cv_untagged(); +} + +1; +__END__ + +=head1 NAME + +SNMP::Info::Layer3::ArubaCX - SNMP Interface to L3 Devices running ArubaOS-CX + +=head1 AUTHORS + +Jeroen van Ingen + +=head1 SYNOPSIS + + # Let SNMP::Info determine the correct subclass for you. + my $cx = new SNMP::Info( + AutoSpecify => 1, + Debug => 1, + DestHost => 'myrouter', + Community => 'public', + Version => 2 + ) + or die "Can't connect to DestHost.\n"; + + my $class = $cx->class(); + print "SNMP::Info determined this device to fall under subclass : $class\n"; + +=head1 DESCRIPTION + +Subclass for devices running ArubaOS-CX + +=head2 Inherited Classes + +=over + +=item SNMP::Info::Layer3 + +=item SNMP::Info::IEEE802dot3ad + +=back + +=head2 Required MIBs + +=over + +=item F +=item F +=item F + +=item Inherited Classes' MIBs + +See L for its own MIB requirements. + +See L for its own MIB requirements. + +=back + +=head1 GLOBALS + +These are methods that return scalar value from SNMP + +=over + +=item $cx->stack_info() + +If the device supports VSF stacking and is not in standalone mode, returns +a string describing the switch family and the number of stack members. +Example return value: '6300M (stack of 2)'. Will return undef when VSF is not +supported or when the device is VSF standalone/ + +=item $cx->model() + +Returns L if defined, otherwise will fall back to returning the +model from C; if that's also not set, will use +C as a last resort, stripping 'arubaWiredSwitch' from the value. + +=item $cx->vendor() + +Returns (lowercased) value for C, or 'aruba'. + +=item $cx->os() + +Returns 'arubaos-cx'. + +=item $cx->os_ver() + +Returns the software version. Either C or +extracted from C. + +=item $cx->fan() + +Returns a string with status information for all fans listed in +C. + +=back + +=head2 Globals imported from SNMP::Info::Layer3 + +See documentation in L for details. + +=head2 Globals imported from SNMP::Info::IEEE802dot3ad + +See documentation in L for details. + +=head1 TABLE ENTRIES + +These are methods that return tables of information in the form of a reference +to a hash. + +=head2 Overrides + +=over + +=item C + +Returns a HASH reference mapping from slave to master port for each member of +a port bundle on the device. Keys are ifIndex of the slave ports, Values are +ifIndex of the corresponding master ports. + +=item C +=item C +=item C +=item C +=item C +=item C +=item C +All overridden to return the VLAN data structures that we'd expect for a +device that implements C, but with data from +L at PBB 1. + +=back + +=head2 Table Methods imported from SNMP::Info::Layer3 + +See documentation in L for details. + +=head2 Table Methods imported from SNMP::Info::IEEE802dot3ad + +See documentation in L for details. + +=cut From 3ae7073198fa63f83d760d2af5975f99c5107675 Mon Sep 17 00:00:00 2001 From: Jeroen van Ingen Date: Fri, 11 Jun 2021 14:55:26 +0200 Subject: [PATCH 2/2] Small Bridge.pm fix This change will make sure that the internal _vlan_hoa() function will strip any additional index levels that may be present in input data. Not only applies to Q-BRIDGE-MIB tables with a TimeFilter index, but also to tables where part of the data comes from IEEE8021-Q-BRIDGE-MIB with both TimeFilter and PBB ID. --- lib/SNMP/Info/Bridge.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SNMP/Info/Bridge.pm b/lib/SNMP/Info/Bridge.pm index e530cf77..354e7106 100644 --- a/lib/SNMP/Info/Bridge.pm +++ b/lib/SNMP/Info/Bridge.pm @@ -429,7 +429,7 @@ sub _vlan_hoa { my $vlan; # Strip TimeFilter if we're using VlanCurrentTable - ( $vlan = $idx ) =~ s/^\d+\.//; + ($vlan = $idx) =~ s/^(\d+\.)*//g; # Convert portlist bit array to bp_index array for ( my $i = 0; $i <= $#$portlist; $i++ ) {