#145 Patch for Huawei (robwwd)

#228 Huawei aggregate link support
POE and duplex admin support added to L3::Huawei
This commit is contained in:
Eric A. Miller
2018-04-25 22:44:13 -04:00
parent a6fdb107b4
commit f2fdbb077c
4 changed files with 788 additions and 53 deletions

View File

@@ -12,7 +12,7 @@ before_install:
- mkdir ~/netdisco-mibs - mkdir ~/netdisco-mibs
- cd ~/netdisco-mibs - cd ~/netdisco-mibs
install: install:
- curl -sL https://github.com/netdisco/netdisco-mibs/releases/download/4.008/netdisco-mibs.tar.gz | tar --strip-components=1 -zxf - - curl -sL https://github.com/netdisco/netdisco-mibs/releases/download/4.009/netdisco-mibs.tar.gz | tar --strip-components=1 -zxf -
- cpanm --quiet --notest PkgConfig Test::CChecker Alien::zlib::Static Alien::OpenSSL::Static Alien::SNMP::MAXTC - cpanm --quiet --notest PkgConfig Test::CChecker Alien::zlib::Static Alien::OpenSSL::Static Alien::SNMP::MAXTC
before_script: before_script:
- 'cd ${TRAVIS_BUILD_DIR}' - 'cd ${TRAVIS_BUILD_DIR}'

View File

@@ -1,5 +1,11 @@
Version 3.57 Version 3.57
[ENHANCEMENTS]
* #145 Patch for Huawei (robwwd)
* #228 Huawei aggregate link support
* POE and duplex admin support added to L3::Huawei
[BUG FIXES] [BUG FIXES]
* IEEE802dot3ad portlist is indexed with a dot1dBasePort, cross reference * IEEE802dot3ad portlist is indexed with a dot1dBasePort, cross reference

View File

@@ -1,6 +1,6 @@
# SNMP::Info::Layer3::Huawei # SNMP::Info::Layer3::Huawei
# #
# Copyright (c) 2018 Jeroen van Ingen # Copyright (c) 2018 Jeroen van Ingen and Eric Miller
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@@ -32,18 +32,14 @@ package SNMP::Info::Layer3::Huawei;
use strict; use strict;
use Exporter; use Exporter;
use SNMP::Info::Layer3; use SNMP::Info::Layer3;
use SNMP::Info::LLDP; use SNMP::Info::IEEE802dot3ad;
use SNMP::Info::IEEE802dot3ad 'agg_ports_lag';
@SNMP::Info::Layer3::Huawei::ISA = qw/ @SNMP::Info::Layer3::Huawei::ISA = qw/
SNMP::Info::IEEE802dot3ad SNMP::Info::IEEE802dot3ad
SNMP::Info::LLDP SNMP::Info::Layer3
SNMP::Info::Layer3 Exporter
Exporter /;
/; @SNMP::Info::Layer3::Huawei::EXPORT_OK = qw//;
@SNMP::Info::Layer3::Huawei::EXPORT_OK = qw/
agg_ports
/;
use vars qw/$VERSION %GLOBALS %MIBS %FUNCS %MUNGE/; use vars qw/$VERSION %GLOBALS %MIBS %FUNCS %MUNGE/;
@@ -51,26 +47,58 @@ $VERSION = '3.56';
%MIBS = ( %MIBS = (
%SNMP::Info::Layer3::MIBS, %SNMP::Info::Layer3::MIBS,
%SNMP::Info::LLDP::MIBS,
%SNMP::Info::IEEE802dot3ad::MIBS, %SNMP::Info::IEEE802dot3ad::MIBS,
'HUAWEI-MIB' => 'quidway', 'HUAWEI-MIB' => 'quidway',
'HUAWEI-PORT-MIB' => 'hwEthernetDuplex',
'HUAWEI-IF-EXT-MIB' => 'hwTrunkIfIndex',
'HUAWEI-L2IF-MIB' => 'hwL2IfPortIfIndex',
'HUAWEI-POE-MIB' => 'hwPoePower',
); );
%GLOBALS = ( %GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, );
%SNMP::Info::Layer3::GLOBALS,
%SNMP::Info::LLDP::GLOBALS,
);
%FUNCS = ( %FUNCS = (
%SNMP::Info::Layer3::FUNCS, %SNMP::Info::Layer3::FUNCS,
%SNMP::Info::LLDP::FUNCS,
%SNMP::Info::IEEE802dot3ad::FUNCS, %SNMP::Info::IEEE802dot3ad::FUNCS,
# HUAWEI-PORT-MIB::
'hw_eth_speed_admin' => 'hwEthernetSpeedSet',
'hw_eth_duplex' => 'hwEthernetDuplex',
'hw_eth_auto' => 'hwEthernetNegotiation',
# HUAWEI-PORT-MIB::
'hw_phy_port_slot' => 'hwPhysicalPortInSlot',
# HUAWEI-IF-EXT-MIB::hwTrunkIfTable
'hw_trunk_if_idx' => 'hwTrunkIfIndex',
'hw_trunk_entry' => 'hwTrunkValidEntry',
# HUAWEI-L2IF-MIB::hwL2IfTable
'hw_l2if_port_idx' => 'hwL2IfPortIfIndex',
# HUAWEI-POE-MIB::hwPoePortTable
'hw_peth_port_admin' => 'hwPoePortEnable',
'hw_peth_port_status' => 'hwPoePortPowerStatus',
'hw_peth_port_class' => 'hwPoePortPdClass',
'hw_peth_port_power' => 'hwPoePortConsumingPower',
# HUAWEI-POE-MIB::hwPoeSlotTable
'peth_power_watts' => 'hwPoeSlotMaximumPower',
'peth_power_consumption' => 'hwPoeSlotConsumingPower',
'peth_power_threshold' => 'hwPoeSlotPowerUtilizationThreshold',
); );
%MUNGE = ( %MUNGE = (
%SNMP::Info::Layer3::MUNGE, %SNMP::Info::Layer3::MUNGE,
%SNMP::Info::LLDP::MUNGE,
%SNMP::Info::IEEE802dot3ad::MUNGE, %SNMP::Info::IEEE802dot3ad::MUNGE,
'hw_peth_port_admin' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_admin,
'peth_power_watts' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_power,
'peth_power_consumption' =>
\&SNMP::Info::Layer3::Huawei::munge_hw_peth_power,
'hw_peth_port_status' =>
\&SNMP::Info::Layer3::Huawei::munge_hw_peth_status,
'hw_peth_port_class' => \&SNMP::Info::Layer3::Huawei::munge_hw_peth_class,
); );
sub vendor { sub vendor {
@@ -87,19 +115,37 @@ sub os {
sub os_ver { sub os_ver {
my $huawei = shift; my $huawei = shift;
my $entity_os = $huawei->entity_derived_os_ver();
if ( defined $entity_os and $entity_os !~ /^\s*$/ ) {
return $entity_os;
}
my $descr = $huawei->description(); my $descr = $huawei->description();
my $os_ver = undef; my $os_ver = undef;
$os_ver = "$1" if ( $descr =~ /\bVersion ([0-9.]+)/i ); if ($descr =~ /Version\s # Start match on Version string
([\d\.]+) # Capture the primary version in 1
,? # There may be a comma
\s # Always a space
(?:Release|Feature)? # Don't capture stanza if present
(?:\(\w+)? # If paren & model don't capture
\s # Always a space
(\w+) # If 2nd part of version capture in 2
/xi
)
{
$os_ver = $2 ? "$1 $2" : $1;
}
return $os_ver; return $os_ver;
} }
sub i_ignore { sub i_ignore {
my $l3 = shift; my $huawei = shift;
my $partial = shift; my $partial = shift;
my $interfaces = $l3->interfaces($partial) || {}; my $interfaces = $huawei->interfaces($partial) || {};
my %i_ignore; my %i_ignore;
foreach my $if ( keys %$interfaces ) { foreach my $if ( keys %$interfaces ) {
@@ -112,18 +158,253 @@ sub i_ignore {
return \%i_ignore; return \%i_ignore;
} }
sub agg_ports { return agg_ports_lag(@_) } sub bp_index {
my $huawei = shift;
my $hw_index = $huawei->hw_l2if_port_idx();
return $hw_index
if ( ref {} eq ref $hw_index and scalar keys %$hw_index );
return $huawei->SUPER::bp_index();
}
sub i_duplex {
my $huawei = shift;
my $partial = shift;
my $hw_duplex = $huawei->hw_eth_duplex($partial);
return $hw_duplex
if ( ref {} eq ref $hw_duplex and scalar keys %$hw_duplex );
return $huawei->SUPER::i_duplex($partial);
}
sub i_duplex_admin {
my $huawei = shift;
my $partial = shift;
my $hw_duplex_admin = $huawei->hw_eth_duplex($partial) || {};
my $hw_auto = $huawei->hw_eth_auto($partial) || {};
my %i_duplex_admin;
foreach my $if ( keys %$hw_duplex_admin ) {
my $duplex = $hw_duplex_admin->{$if};
next unless defined $duplex;
my $auto = $hw_auto->{$if} || 'disabled';
my $string = 'other';
$string = 'half' if ( $duplex =~ /half/i and $auto =~ /disabled/i );
$string = 'full' if ( $duplex =~ /full/i and $auto =~ /disabled/i );
$string = 'auto' if $auto =~ /enabled/i;
$i_duplex_admin{$if} = $string;
}
return \%i_duplex_admin;
}
sub agg_ports {
my $huawei = shift;
# First use proprietary MIB for broader implementation across
# devices type / os and no xref of hwL2IfPortIfIndex
my $masters = $huawei->hw_trunk_if_idx();
my $slaves = $huawei->hw_trunk_entry();
my $ret = {};
if ( ref {} eq ref $masters
and scalar keys %$masters
and ref {} eq ref $slaves
and scalar keys %$slaves )
{
foreach my $s ( keys %$slaves ) {
next if $slaves->{$s} ne 'valid';
my ( $trunk, $sl_idx ) = split( /\./, $s );
foreach my $m ( keys %$masters ) {
next unless $m == $trunk;
next unless defined $masters->{$m};
$ret->{$sl_idx} = $masters->{$m};
last;
}
}
return $ret;
}
# If for some reason we don't get the info, try IEEE8023-LAG-MIB
return $huawei->agg_ports_lag();
}
# The standard IEEE 802.af POWER-ETHERNET-MIB has an index of module.port
# The HUAWEI-POE-MIB only indexes by ifIndex, we need to match the standard
# for so method calls across classes work the same
#
# Note: Only snmpwalks with single chassis / box with single power source
# in slot zero. This may need to be revisited
#
sub peth_port_ifindex {
my $huawei = shift;
my $peth_port_status = $huawei->hw_peth_port_status() || {};
my $peth_port_slot = $huawei->hw_phy_port_slot() || {};
my $peth_port_ifindex = {};
foreach my $i ( keys %$peth_port_status ) {
my $slot = 0;
if ( exists $peth_port_slot->{$i}
&& defined $peth_port_slot->{$i} )
{
$slot = $peth_port_slot->{$i};
}
$peth_port_ifindex->{"$slot.$i"} = $i;
}
return $peth_port_ifindex;
}
sub peth_port_admin {
my $huawei = shift;
my $port_admin = $huawei->hw_peth_port_admin() || {};
my $port_ifindex = $huawei->peth_port_ifindex() || {};
my $peth_port_admin = {};
foreach my $idx ( keys %$port_ifindex ) {
my $ifindex = $port_ifindex->{$idx};
my $admin = $port_admin->{$ifindex};
next unless $admin;
$peth_port_admin->{$idx} = $admin;
}
return $peth_port_admin;
}
sub peth_port_status {
my $huawei = shift;
my $port_status = $huawei->hw_peth_port_status() || {};
my $port_ifindex = $huawei->peth_port_ifindex() || {};
my $peth_port_status = {};
foreach my $idx ( keys %$port_ifindex ) {
my $ifindex = $port_ifindex->{$idx};
my $status = $port_status->{$ifindex};
next unless $status;
$peth_port_status->{$idx} = $status;
}
return $peth_port_status;
}
sub peth_port_class {
my $huawei = shift;
my $port_class = $huawei->hw_peth_port_class() || {};
my $port_ifindex = $huawei->peth_port_ifindex() || {};
my $peth_port_class = {};
foreach my $idx ( keys %$port_ifindex ) {
my $ifindex = $port_ifindex->{$idx};
my $class = $port_class->{$ifindex};
next unless $class;
$peth_port_class->{$idx} = $class;
}
return $peth_port_class;
}
sub peth_port_power {
my $huawei = shift;
my $port_power = $huawei->hw_peth_port_power() || {};
my $port_ifindex = $huawei->peth_port_ifindex() || {};
my $peth_port_power = {};
foreach my $idx ( keys %$port_ifindex ) {
my $ifindex = $port_ifindex->{$idx};
my $power = $port_power->{$ifindex};
next unless defined $power;
$peth_port_power->{$idx} = $power;
}
return $peth_port_power;
}
sub peth_port_neg_power {
my $huawei = shift;
my $peth_port_status = $huawei->peth_port_status() || {};
my $peth_port_class = $huawei->peth_port_class() || {};
my $port_ifindex = $huawei->peth_port_ifindex() || {};
my $huaweimax = {
'class0' => 12950,
'class1' => 3840,
'class2' => 6490,
'class3' => 12950,
'class4' => 25500
};
my $peth_port_neg_power = {};
foreach my $idx ( keys %$port_ifindex ) {
if ( $peth_port_status->{$idx} eq 'deliveringPower' ) {
$peth_port_neg_power->{$idx}
= $huaweimax->{ $peth_port_class->{$idx} };
}
}
return $peth_port_neg_power;
}
sub munge_hw_peth_admin {
my $admin = shift;
$admin =~ s/enabled/true/;
$admin =~ s/disabled/false/;
return $admin;
}
sub munge_hw_peth_power {
my $pwr = shift;
$pwr = $pwr / 1000;
return sprintf( "%.0f", $pwr );
}
sub munge_hw_peth_class {
my $pwr = shift;
return "class$pwr";
}
# The values are from the MIB reference guide
sub munge_hw_peth_status {
my $pwr = shift;
# The status is an octet string rather than enum
# so use regex rather than hash lookup
$pwr = 'disabled' if $pwr =~ /Disabled/i;
$pwr = 'searching' if $pwr =~ /(Powering|Power-ready|Detecting)/i;
$pwr = 'deliveringPower' if $pwr =~ /Powered/i;
$pwr = 'fault' if $pwr =~ /fault/i;
return $pwr;
}
1; 1;
__END__ __END__
=head1 NAME =head1 NAME
SNMP::Info::Layer3::Huawei - SNMP Interface to Huawei Layer 3 switches and routers. SNMP::Info::Layer3::Huawei - SNMP Interface to Huawei switches and routers.
=head1 AUTHORS =head1 AUTHORS
Jeroen van Ingen Jeroen van Ingen and Eric Miller
=head1 SYNOPSIS =head1 SYNOPSIS
@@ -142,7 +423,7 @@ Jeroen van Ingen
=head1 DESCRIPTION =head1 DESCRIPTION
Subclass for Huawei Quidway switches Subclass for Huawei switches
=head2 Inherited Classes =head2 Inherited Classes
@@ -150,8 +431,6 @@ Subclass for Huawei Quidway switches
=item SNMP::Info::Layer3 =item SNMP::Info::Layer3
=item SNMP::Info::LLDP
=item SNMP::Info::IEEE802dot3ad =item SNMP::Info::IEEE802dot3ad
=back =back
@@ -162,12 +441,18 @@ Subclass for Huawei Quidway switches
=item F<HUAWEI-MIB> =item F<HUAWEI-MIB>
=item F<HUAWEI-PORT-MIB>
=item F<HUAWEI-IF-EXT-MIB>
=item F<HUAWEI-L2IF-MIB>
=item F<HUAWEI-POE-MIB>
=item Inherited Classes' MIBs =item Inherited Classes' MIBs
See L<SNMP::Info::Layer3> for its own MIB requirements. See L<SNMP::Info::Layer3> for its own MIB requirements.
See L<SNMP::Info::LLDP> for its own MIB requirements.
See L<SNMP::Info::IEEE802dot3ad> for its own MIB requirements. See L<SNMP::Info::IEEE802dot3ad> for its own MIB requirements.
=back =back
@@ -188,7 +473,8 @@ Returns 'VRP' if contained in C<sysDescr>, 'huawei' otherwise.
=item $huawei->os_ver() =item $huawei->os_ver()
Returns the software version extracted from C<sysDescr>. Returns the software version derived from the C<ENTITY-MIB> or
extracted from C<sysDescr>.
=back =back
@@ -196,15 +482,49 @@ Returns the software version extracted from C<sysDescr>.
See documentation in L<SNMP::Info::Layer3> for details. See documentation in L<SNMP::Info::Layer3> for details.
=head2 Globals imported from SNMP::Info::LLDP
See documentation in L<SNMP::Info::LLDP> for details.
=head1 TABLE ENTRIES =head1 TABLE ENTRIES
These are methods that return tables of information in the form of a reference These are methods that return tables of information in the form of a reference
to a hash. to a hash.
=over
=item $huawei->i_duplex()
Returns reference to map of IIDs to current link duplex.
=item $huawei->i_duplex_admin()
Returns reference to hash of IIDs to admin duplex setting.
=back
=head2 POE Slot Table
=over
=item $huawei->peth_power_watts()
The slot's power supply's capacity, in watts.
C<hwPoeSlotMaximumPower>
=item $huawei->peth_power_consumption()
How much power, in watts, this power supply has been committed to
deliver.
C<hwPoeSlotConsumingPower>
=item $huawei->peth_power_threshold()
The threshold (in percent) of consumption required to raise an
alarm.
C<hwPoeSlotPowerUtilizationThreshold>
=back
=head2 Overrides =head2 Overrides
=over =over
@@ -215,11 +535,58 @@ Returns reference to hash. Increments value of IID if port is to be ignored.
Ignores InLoopback and Console interfaces Ignores InLoopback and Console interfaces
=item $huawei->bp_index()
Returns a mapping between C<ifIndex> and the Bridge Table. Uses
C<hwL2IfPortIfIndex> for the most complete mapping and falls back to
C<dot1dBasePortIfIndex> if not available.
=item C<agg_ports> =item C<agg_ports>
Returns a HASH reference mapping from slave to master port for each member of 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 a port bundle on the device. Keys are ifIndex of the slave ports, Values are
ifIndex of the corresponding master ports. ifIndex of the corresponding master ports. Attempts to use C<hwTrunkIfTable>
first and then C<dot3adAggPortListPorts> if that is unavailable.
=back
=head2 Power Port Table
The index of these methods have been normalized to slot.port and values
munged to provide compatability with the IEEE 802.3af F<POWER-ETHERNET-MIB>
and equivalent L<SNMP::Info::PowerEthernet> methods.
=over
=item $huawei->peth_port_admin()
Administrative status: is this port permitted to deliver power?
=item $huawei->peth_port_status()
Current status: is this port delivering power, searching, disabled, etc?
=item $huawei->peth_port_class()
Device class: if status is delivering power, this represents the 802.3af
class of the device being powered.
=item $huawei->peth_port_power()
Power supplied the port, in milliwatts
=item $huawei->peth_port_ifindex()
Returns an index of slot.port to an C<ifIndex>. Slot defaults to zero
meaning chassis or box if there is no C<ifIndex> to slot mapping available in
C<hwPhysicalPortInSlot>. Mapping the index to slot.port is a normalization
function to provide compatability with the IEEE 802.3af F<POWER-ETHERNET-MIB>.
=item $huawei->peth_port_neg_power()
The power, in milliwatts, that has been committed to this port.
This value is derived from the 802.3af class of the device being
powered.
=back =back
@@ -227,12 +594,31 @@ ifIndex of the corresponding master ports.
See documentation in L<SNMP::Info::Layer3> for details. See documentation in L<SNMP::Info::Layer3> for details.
=head2 Table Methods imported from SNMP::Info::LLDP
See documentation in L<SNMP::Info::LLDP> for details.
=head2 Table Methods imported from SNMP::Info::IEEE802dot3ad =head2 Table Methods imported from SNMP::Info::IEEE802dot3ad
See documentation in L<SNMP::Info::IEEE802dot3ad> for details. See documentation in L<SNMP::Info::IEEE802dot3ad> for details.
=head1 Data Munging Callback Subroutines
=over
=item $huawei->munge_hw_peth_admin()
Normalizes C<hwPoePortEnable> values to 'true' or 'false'.
=item $huawei->munge_hw_peth_class()
Normalizes C<hwPoePortPdClass> values by prepending 'class'.
=item $huawei->munge_hw_peth_power()
Converts and rounds to a whole number milliwatts to watts.
=item $huawei->munge_hw_peth_status()
Normalizes C<hwPoePortPowerStatus> values to those that would be returned by
the the IEEE 802.3af F<POWER-ETHERNET-MIB>.
=back
=cut =cut

View File

@@ -33,30 +33,373 @@ use Test::Class::Most parent => 'My::Test::Class';
use SNMP::Info::Layer3::Huawei; use SNMP::Info::Layer3::Huawei;
# Remove this startup override once we have full method coverage
sub startup : Tests(startup => 1) {
my $test = shift;
$test->SUPER::startup();
$test->todo_methods(1);
}
sub setup : Tests(setup) { sub setup : Tests(setup) {
my $test = shift; my $test = shift;
$test->SUPER::setup; $test->SUPER::setup;
# Start with a common cache that will serve most tests # Start with a common cache that will serve most tests
my $d_string = 'Huawei Versatile Routing Platform Software VRP (R) software, '; my $d_string
= 'Huawei Versatile Routing Platform Software VRP (R) software, ';
$d_string .= 'Version 8.100 (CE6810EI V100R005C10SPC200) '; $d_string .= 'Version 8.100 (CE6810EI V100R005C10SPC200) ';
my $cache_data = { my $cache_data = {
'_layers' => 4, '_layers' => 4,
'_description' => $d_string, '_description' => $d_string,
# HUAWEI-MIB::ce6810-48S4Q-EI # HUAWEI-MIB::ce6810-48S4Q-EI
'_id' => '.1.3.6.1.4.1.2011.2.239.12', '_id' => '.1.3.6.1.4.1.2011.2.239.12',
'store' => {}, '_i_index' => 1,
'_i_description' => 1,
'_hw_eth_duplex' => 1,
'_hw_eth_auto' => 1,
'_el_index' => 1,
'_el_duplex' => 1,
'_hw_trunk_if_idx' => 1,
'_hw_trunk_entry' => 1,
'_ad_lag_ports' => 1,
'_hw_l2if_port_idx' => 1,
'_bp_index' => 1,
'_hw_phy_port_slot' => 1,
'_hw_peth_power_watts' => 1,
'_hw_peth_port_admin' => 1,
'_hw_peth_port_status' => 1,
'_hw_peth_port_class' => 1,
'_hw_peth_port_power' => 1,
'store' => {
'i_index' => {1 => 1, 6 => 6, 7 => 7, 8 => 8},
'i_description' => {
1 => 'InLoopBack0',
6 => 'GigabitEthernet0/0/1',
7 => 'GigabitEthernet0/0/2',
8 => 'GigabitEthernet0/0/3'
},
'hw_eth_duplex' => {6 => 'full', 7 => 'full', 8 => 'half'},
'hw_eth_auto' => {6 => 'enabled', 7 => 'disabled', 8 => 'disabled'},
'el_index' => {9 => 9, 10 => 10},
'el_duplex' => {9 => 'full', 10 => 'half'},
'hw_trunk_if_idx' => {0 => 121},
'hw_trunk_entry' => {'0.55' => 'valid', '0.110' => 'valid'},
'ad_lag_ports' => {34 => pack("H*", '00000060')},
'hw_l2if_port_idx' => {26 => 30, 27 => 31},
'bp_index' => {2 => 1, 7 => 3},
'hw_phy_port_slot' => {6 => 0, 7 => 0, 8 => 0},
'hw_peth_power_watts' => {0 => 369600},
'hw_peth_port_admin' => {6 => 'enabled', 7 => 'disabled', 8 => 'enabled'},
'hw_peth_port_status' =>
{6 => 'Powered', 7 => 'Disabled', 8 => 'Detecting'},
'hw_peth_port_class' => {6 => 3, 7 => 0, 8 => 0},
'hw_peth_port_power' => {6 => 3763, 7 => 0, 8 => 0},
},
}; };
$test->{info}->cache($cache_data); $test->{info}->cache($cache_data);
} }
sub vendor : Tests(2) {
my $test = shift;
can_ok($test->{info}, 'vendor');
is($test->{info}->vendor(), 'Huawei', q(Vendor returns 'Huawei'));
}
sub os : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'os');
is($test->{info}->os(), 'VRP', q(OS returns 'VRP' when description matches));
$test->{info}->clear_cache();
is($test->{info}->os(), 'huawei', q(... and 'huawei' when it doesn't));
}
sub os_ver : Tests(7) {
my $test = shift;
can_ok($test->{info}, 'os_ver');
is(
$test->{info}->os_ver(),
'8.100 V100R005C10SPC200',
q(OS version returned from 'sysDescr' example 1)
);
my $descr = 'Version 3.40, Release 0311P07 Quidway Series Router AR28-31 ';
$test->{info}{_description} = $descr;
is($test->{info}->os_ver(),
'3.40 0311P07', q(OS version returned from 'sysDescr'example 2));
$descr = 'Version 3.40, Feature 0308 Quidway Series Router AR46-40 ';
$test->{info}{_description} = $descr;
is($test->{info}->os_ver(),
'3.40 0308', q(OS version returned from 'sysDescr'example 3));
$descr = 'Version 3.40, Feature 0121L01.Quidway Router AR18-34E.';
$test->{info}{_description} = $descr;
is($test->{info}->os_ver(),
'3.40 0121L01', q(OS version returned from 'sysDescr'example 4));
$descr = 'software,Version 5.120 (AR151 V200R003C01SPC100) ';
$test->{info}{_description} = $descr;
is(
$test->{info}->os_ver(),
'5.120 V200R003C01SPC100',
q(OS version returned from 'sysDescr'example 5)
);
$test->{info}->clear_cache();
is($test->{info}->os_ver(), undef, q(No data returns undef OS version));
}
# Not overriden in class, but tested anyway
sub model : Tests(2) {
my $test = shift;
can_ok($test->{info}, 'model');
is($test->{info}->model(), 'ce6810-48S4Q-EI', q(Model translates id));
}
sub i_ignore : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'i_ignore');
my $expected = {1 => 1};
cmp_deeply($test->{info}->i_ignore(),
$expected, q(Loopback interface ignored));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_ignore(), {}, q(No matches returns empty hash));
}
sub bp_index : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'bp_index');
my $expected = {26 => 30, 27 => 31};
cmp_deeply($test->{info}->bp_index(),
$expected, q(Bridge to interface index mapping using 'hwL2IfPortIfIndex'));
delete $test->{info}{'_hw_l2if_port_idx'};
$expected = {2 => 1, 7 => 3};
cmp_deeply($test->{info}->bp_index(),
$expected,
q(Bridge to interface index mapping using 'dot1dBasePortIfIndex'));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->bp_index(), undef,
q(No mapping returns empty hash));
}
sub i_duplex : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'i_duplex');
my $expected = {6 => 'full', 7 => 'full', 8 => 'half'};
cmp_deeply($test->{info}->i_duplex(),
$expected, q(Duplex values using 'hwEthernetDuplex'));
delete $test->{info}{'_hw_eth_duplex'};
$expected = {9 => 'full', 10 => 'half'};
cmp_deeply($test->{info}->i_duplex(),
$expected, q(Duplex values using 'EtherLike-MIB'));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_duplex(), {}, q(No mapping returns empty hash));
}
sub i_duplex_admin : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'i_duplex_admin');
my $expected = {6 => 'auto', 7 => 'full', 8 => 'half'};
cmp_deeply($test->{info}->i_duplex_admin(),
$expected, q(Duplex admin values using 'hwEthernetDuplex'));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_duplex_admin(),
{}, q(No mapping returns empty hash));
}
sub agg_ports : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'agg_ports');
my $expected = {55 => 121, 110 => 121};
cmp_deeply($test->{info}->agg_ports(),
$expected,
q(Aggregated links have expected values using 'HUAWEI-IF-EXT-MIB'));
delete $test->{info}{_hw_trunk_if_idx};
$expected = {30 => 34, 31 => 34};
cmp_deeply($test->{info}->agg_ports(),
$expected,
q(Aggregated links have expected values using 'IEEE8023-LAG-MIB'));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->agg_ports(), {}, q(No data returns empty hash));
}
sub peth_port_ifindex : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'peth_port_ifindex');
my $expected = {'0.6' => 6, '0.7' => 7, '0.8' => 8},;
cmp_deeply($test->{info}->peth_port_ifindex(),
$expected, q(POE port 'ifIndex' mapping returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->peth_port_ifindex(),
{}, q(No data returns empty hash));
}
sub peth_port_admin : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'peth_port_admin');
my $expected = {'0.6' => 'true', '0.7' => 'false', '0.8' => 'true'};
cmp_deeply($test->{info}->peth_port_admin(),
$expected, q(POE port admin status returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->peth_port_admin(),
{}, q(No data returns empty hash));
}
sub peth_port_status : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'peth_port_status');
my $expected
= {'0.6' => 'deliveringPower', '0.7' => 'disabled', '0.8' => 'searching'};
cmp_deeply($test->{info}->peth_port_status(),
$expected, q(POE port status returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->peth_port_status(),
{}, q(No data returns empty hash));
}
sub peth_port_class : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'peth_port_class');
my $expected = {'0.6' => 'class3', '0.7' => 'class0', '0.8' => 'class0'};
cmp_deeply($test->{info}->peth_port_class(),
$expected, q(POE port class returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->peth_port_class(),
{}, q(No data returns empty hash));
}
sub peth_port_power : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'peth_port_power');
my $expected = {'0.6' => 3763, '0.7' => 0, '0.8' => 0};
cmp_deeply($test->{info}->peth_port_power(),
$expected, q(POE port power returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->peth_port_power(),
{}, q(No data returns empty hash));
}
sub peth_port_neg_power : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'peth_port_neg_power');
my $expected = {'0.6' => 12950};
cmp_deeply($test->{info}->peth_port_neg_power(),
$expected, q(POE port negotiated power returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->peth_port_neg_power(),
{}, q(No data returns empty hash));
}
sub munge_hw_peth_admin : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'munge_hw_peth_admin');
my $expected = 'true';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_admin('enabled'),
$expected, q(... enabled munges to true));
$expected = 'false';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_admin('disabled'),
$expected, q(... disabled munges to false));
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_admin('huh'),
'huh', q(... anything else not munged));
}
sub munge_hw_peth_power : Tests(2) {
my $test = shift;
can_ok($test->{info}, 'munge_hw_peth_power');
my $expected = '370';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_power('369600'),
$expected, q(... mW converted/rounded to W));
}
sub munge_hw_peth_class : Tests(2) {
my $test = shift;
can_ok($test->{info}, 'munge_hw_peth_class');
my $expected = 'class3';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_class(3),
$expected, q(... 'class' text added to numeric class));
}
sub munge_hw_peth_status : Tests(6) {
my $test = shift;
can_ok($test->{info}, 'munge_hw_peth_status');
my $expected = 'disabled';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_status('Disabled'),
$expected, q(... Disabled munges to disabled));
$expected = 'searching';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_status('Detecting'),
$expected, q(... Detecting munges to searching));
$expected = 'deliveringPower';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_status('Powered'),
$expected, q(... Powered munges to deliveringPower));
$expected = 'fault';
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_status('Other-fault'),
$expected, q(... Other-fault munges to fault));
is(SNMP::Info::Layer3::Huawei::munge_hw_peth_status('huh'),
'huh', q(... anything else not munged));
}
1; 1;