Add fan and power supply status to L3::Huawei

Override ifMTU with max frame size when applicable in L3::Huawei
Correct POE power module to port mapping in L3::Huawei
This commit is contained in:
Eric A. Miller
2018-04-29 12:03:05 -04:00
parent d0887fbea7
commit 2344a1eacf
3 changed files with 248 additions and 36 deletions

11
Changes
View File

@@ -1,3 +1,14 @@
Version 3.58
[ENHANCEMENTS]
* Add fan and power supply status to L3::Huawei
* Override ifMTU with max frame size when applicable in L3::Huawei
[BUG FIXES]
* Correct POE power module to port mapping in L3::Huawei
Version 3.57 (2018-04-26) Version 3.57 (2018-04-26)
[ENHANCEMENTS] [ENHANCEMENTS]

View File

@@ -48,11 +48,12 @@ $VERSION = '3.57';
%MIBS = ( %MIBS = (
%SNMP::Info::Layer3::MIBS, %SNMP::Info::Layer3::MIBS,
%SNMP::Info::IEEE802dot3ad::MIBS, %SNMP::Info::IEEE802dot3ad::MIBS,
'HUAWEI-MIB' => 'quidway', 'HUAWEI-MIB' => 'quidway',
'HUAWEI-PORT-MIB' => 'hwEthernetDuplex', 'HUAWEI-PORT-MIB' => 'hwEthernetDuplex',
'HUAWEI-IF-EXT-MIB' => 'hwTrunkIfIndex', 'HUAWEI-IF-EXT-MIB' => 'hwTrunkIfIndex',
'HUAWEI-L2IF-MIB' => 'hwL2IfPortIfIndex', 'HUAWEI-L2IF-MIB' => 'hwL2IfPortIfIndex',
'HUAWEI-POE-MIB' => 'hwPoePower', 'HUAWEI-POE-MIB' => 'hwPoePower',
'HUAWEI-ENTITY-EXTENT-MIB' => 'hwEntityFanState',
); );
%GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, ); %GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, );
@@ -61,12 +62,13 @@ $VERSION = '3.57';
%SNMP::Info::Layer3::FUNCS, %SNMP::Info::Layer3::FUNCS,
%SNMP::Info::IEEE802dot3ad::FUNCS, %SNMP::Info::IEEE802dot3ad::FUNCS,
# HUAWEI-PORT-MIB:: # HUAWEI-PORT-MIB::hwEthernetTable
'hw_eth_speed_admin' => 'hwEthernetSpeedSet', 'hw_eth_speed_admin' => 'hwEthernetSpeedSet',
'hw_eth_duplex' => 'hwEthernetDuplex', 'hw_eth_duplex' => 'hwEthernetDuplex',
'hw_eth_auto' => 'hwEthernetNegotiation', 'hw_eth_auto' => 'hwEthernetNegotiation',
'hw_eth_frame_len' => 'hwEthernetJumboframeMaxLength',
# HUAWEI-PORT-MIB:: # HUAWEI-PORT-MIB::hwPhysicalPortTable
'hw_phy_port_slot' => 'hwPhysicalPortInSlot', 'hw_phy_port_slot' => 'hwPhysicalPortInSlot',
# HUAWEI-IF-EXT-MIB::hwTrunkIfTable # HUAWEI-IF-EXT-MIB::hwTrunkIfTable
@@ -87,6 +89,13 @@ $VERSION = '3.57';
'peth_power_consumption' => 'hwPoeSlotConsumingPower', 'peth_power_consumption' => 'hwPoeSlotConsumingPower',
'peth_power_threshold' => 'hwPoeSlotPowerUtilizationThreshold', 'peth_power_threshold' => 'hwPoeSlotPowerUtilizationThreshold',
# HUAWEI-ENTITY-EXTENT-MIB::hwFanStatusTable
'hw_fan_state' => 'hwEntityFanState',
'hw_fan_descr' => 'hwEntityFanDesc',
# HUAWEI-ENTITY-EXTENT-MIB::hwPwrStatusTable
'hw_pwr_state' => 'hwEntityPwrState',
'hw_pwr_descr' => 'hwEntityPwrDesc',
); );
%MUNGE = ( %MUNGE = (
@@ -109,7 +118,9 @@ sub os {
my $huawei = shift; my $huawei = shift;
my $descr = $huawei->description(); my $descr = $huawei->description();
return $1 if ( $descr =~ /\b(VRP)\b/ ); if ( $descr =~ /\b(VRP)\b/ ) {
return $1;
}
return "huawei"; return "huawei";
} }
@@ -151,7 +162,7 @@ sub i_ignore {
foreach my $if ( keys %$interfaces ) { foreach my $if ( keys %$interfaces ) {
# lo0 etc # lo0 etc
if ( $interfaces->{$if} =~ /\b(inloopback|console)\d*\b/i ) { if ( $interfaces->{$if} =~ /\b(inloopback|console)\d*\b/ix ) {
$i_ignore{$if}++; $i_ignore{$if}++;
} }
} }
@@ -238,14 +249,12 @@ sub agg_ports {
# The HUAWEI-POE-MIB only indexes by ifIndex, we need to match the standard # The HUAWEI-POE-MIB only indexes by ifIndex, we need to match the standard
# for so method calls across classes work the same # 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 { sub peth_port_ifindex {
my $huawei = shift; my $huawei = shift;
my $peth_port_status = $huawei->hw_peth_port_status() || {}; my $peth_port_status = $huawei->hw_peth_port_status() || {};
my $peth_port_slot = $huawei->hw_phy_port_slot() || {}; my $peth_port_slot = $huawei->hw_phy_port_slot() || {};
my $i_descr = $huawei->i_description() || {};
my $peth_port_ifindex = {}; my $peth_port_ifindex = {};
@@ -256,6 +265,11 @@ sub peth_port_ifindex {
{ {
$slot = $peth_port_slot->{$i}; $slot = $peth_port_slot->{$i};
} }
elsif ( exists $i_descr->{$i}
&& $i_descr->{$i} =~ /(\d+)(?:\/\d+){2,3}$/x )
{
$slot = $1;
}
$peth_port_ifindex->{"$slot.$i"} = $i; $peth_port_ifindex->{"$slot.$i"} = $i;
} }
return $peth_port_ifindex; return $peth_port_ifindex;
@@ -359,6 +373,79 @@ sub peth_port_neg_power {
return $peth_port_neg_power; return $peth_port_neg_power;
} }
sub fan {
my $huawei = shift;
my $fan = $huawei->hw_fan_descr() || {};
my $state = $huawei->hw_fan_state() || {};
if ( scalar keys %$fan ) {
my @messages = ();
foreach my $k ( keys %$fan ) {
next if $state->{$k} and $state->{$k} eq 'normal';
push @messages, "$fan->{$k}: $state->{$k}";
}
push @messages, ( ( scalar keys %$fan ) . " fans OK" )
if scalar @messages == 0;
return ( join ", ", @messages );
}
return;
}
sub ps1_status {
my $huawei = shift;
my $pwr_state = $huawei->hw_pwr_state() || {};
my $pwr_descr = $huawei->hw_pwr_descr() || {};
my $ret = "";
my $s = "";
foreach my $i ( sort keys %$pwr_state ) {
my ( $slot, $num ) = split( /\./, $i );
next unless $num == 1;
$ret .= $s . $pwr_descr->{$i} . ": " . $pwr_state->{$i};
$s = ", ";
}
return if ( $s eq "" );
return $ret;
}
sub ps2_status {
my $huawei = shift;
my $pwr_state = $huawei->hw_pwr_state() || {};
my $pwr_descr = $huawei->hw_pwr_descr() || {};
my $ret = "";
my $s = "";
foreach my $i ( sort keys %$pwr_state ) {
my ( $slot, $num ) = split( /\./, $i );
next unless $num == 2;
$ret .= $s . $pwr_descr->{$i} . ": " . $pwr_state->{$i};
$s = ", ";
}
return if ( $s eq "" );
return $ret;
}
sub i_mtu {
my $huawei = shift;
my $mtus = $huawei->SUPER::i_mtu() || {};
my $frames = $huawei->hw_eth_frame_len() || {};
foreach my $idx ( keys %$mtus ) {
my $frame_sz = $frames->{$idx};
next unless $frame_sz;
$mtus->{$idx} = $frame_sz;
}
return $mtus;
}
sub munge_hw_peth_admin { sub munge_hw_peth_admin {
my $admin = shift; my $admin = shift;
@@ -387,7 +474,7 @@ sub munge_hw_peth_status {
# The status is an octet string rather than enum # The status is an octet string rather than enum
# so use regex rather than hash lookup # so use regex rather than hash lookup
$pwr = 'disabled' if $pwr =~ /Disabled/i; $pwr = 'disabled' if $pwr =~ /Disabled/i;
$pwr = 'searching' if $pwr =~ /(Powering|Power-ready|Detecting)/i; $pwr = 'searching' if $pwr =~ /(Powering|Power-ready|Detecting)/ix;
$pwr = 'deliveringPower' if $pwr =~ /Powered/i; $pwr = 'deliveringPower' if $pwr =~ /Powered/i;
$pwr = 'fault' if $pwr =~ /fault/i; $pwr = 'fault' if $pwr =~ /fault/i;
@@ -449,6 +536,8 @@ Subclass for Huawei switches
=item F<HUAWEI-POE-MIB> =item F<HUAWEI-POE-MIB>
=item F<HUAWEI-ENTITY-EXTENT-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.
@@ -476,6 +565,22 @@ Returns 'VRP' if contained in C<sysDescr>, 'huawei' otherwise.
Returns the software version derived from the C<ENTITY-MIB> or Returns the software version derived from the C<ENTITY-MIB> or
extracted from C<sysDescr>. extracted from C<sysDescr>.
=item $huawei->fan()
Return the status of all fans from the F<HUAWEI-ENTITY-EXTENT-MIB>. Returns
a string indicating the number of fans 'OK' or identification of any fan without
a 'normal' operating status
=item $huawei->ps1_status()
Return the status of the first power supply in each chassis or switch from
the F<HUAWEI-ENTITY-EXTENT-MIB>
=item $huawei->ps2_status()
Return the status of the second power supply in each chassis or switch from
the F<HUAWEI-ENTITY-EXTENT-MIB>
=back =back
=head2 Globals imported from SNMP::Info::Layer3 =head2 Globals imported from SNMP::Info::Layer3
@@ -548,6 +653,11 @@ a port bundle on the device. Keys are ifIndex of the slave ports, Values are
ifIndex of the corresponding master ports. Attempts to use C<hwTrunkIfTable> ifIndex of the corresponding master ports. Attempts to use C<hwTrunkIfTable>
first and then C<dot3adAggPortListPorts> if that is unavailable. first and then C<dot3adAggPortListPorts> if that is unavailable.
=item C<i_mtu>
Interface MTU value. Overriden with corresponding frame size entry from
C<hwEthernetJumboframeMaxLength> if one exists.
=back =back
=head2 Power Port Table =head2 Power Port Table

View File

@@ -50,6 +50,7 @@ sub setup : Tests(setup) {
'_id' => '.1.3.6.1.4.1.2011.2.239.12', '_id' => '.1.3.6.1.4.1.2011.2.239.12',
'_i_index' => 1, '_i_index' => 1,
'_i_description' => 1, '_i_description' => 1,
'_i_mtu' => 1,
'_hw_eth_duplex' => 1, '_hw_eth_duplex' => 1,
'_hw_eth_auto' => 1, '_hw_eth_auto' => 1,
'_el_index' => 1, '_el_index' => 1,
@@ -65,31 +66,47 @@ sub setup : Tests(setup) {
'_hw_peth_port_status' => 1, '_hw_peth_port_status' => 1,
'_hw_peth_port_class' => 1, '_hw_peth_port_class' => 1,
'_hw_peth_port_power' => 1, '_hw_peth_port_power' => 1,
'_hw_fan_state' => 1,
'_hw_fan_descr' => 1,
'_hw_pwr_state' => 1,
'_hw_pwr_descr' => 1,
'store' => { 'store' => {
'i_index' => {1 => 1, 6 => 6, 7 => 7, 8 => 8}, 'i_index' => {1 => 1, 6 => 6, 7 => 7, 8 => 8, 108 => 108},
'i_description' => { 'i_description' => {
1 => 'InLoopBack0', 1 => 'InLoopBack0',
6 => 'GigabitEthernet0/0/1', 6 => 'GigabitEthernet0/0/1',
7 => 'GigabitEthernet0/0/2', 7 => 'GigabitEthernet0/0/2',
8 => 'GigabitEthernet0/0/3' 8 => 'GigabitEthernet0/0/3',
108 => 'GigabitEthernet1/0/1'
}, },
'hw_eth_duplex' => {6 => 'full', 7 => 'full', 8 => 'half'}, 'i_mtu' => {6 => 1500, 7 => 1500, 8 => 1500},
'hw_eth_auto' => {6 => 'enabled', 7 => 'disabled', 8 => 'disabled'}, 'hw_eth_frame_len' => {6 => 2000, 7 => 2000},
'el_index' => {9 => 9, 10 => 10}, 'hw_eth_duplex' => {6 => 'full', 7 => 'full', 8 => 'half'},
'el_duplex' => {9 => 'full', 10 => 'half'}, 'hw_eth_auto' => {6 => 'enabled', 7 => 'disabled', 8 => 'disabled'},
'hw_trunk_if_idx' => {0 => 121}, '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'}, 'hw_trunk_entry' => {'0.55' => 'valid', '0.110' => 'valid'},
'ad_lag_ports' => {34 => pack("H*", '00000060')}, 'ad_lag_ports' => {34 => pack("H*", '00000060')},
'hw_l2if_port_idx' => {26 => 30, 27 => 31}, 'hw_l2if_port_idx' => {26 => 30, 27 => 31},
'bp_index' => {2 => 1, 7 => 3}, 'bp_index' => {2 => 1, 7 => 3},
'hw_phy_port_slot' => {6 => 0, 7 => 0, 8 => 0}, 'hw_phy_port_slot' => {6 => 0, 7 => 0, 8 => 0, 108 => 1},
'hw_peth_power_watts' => {0 => 369600}, 'hw_peth_power_watts' => {0 => 369600, 1 => 739200},
'hw_peth_port_admin' => {6 => 'enabled', 7 => 'disabled', 8 => 'enabled'}, 'hw_peth_port_admin' =>
{6 => 'enabled', 7 => 'disabled', 8 => 'enabled', 108 => 'enabled'},
'hw_peth_port_status' => 'hw_peth_port_status' =>
{6 => 'Powered', 7 => 'Disabled', 8 => 'Detecting'}, {6 => 'Powered', 7 => 'Disabled', 8 => 'Detecting', 108 => 'Powered'},
'hw_peth_port_class' => {6 => 3, 7 => 0, 8 => 0}, 'hw_peth_port_class' => {6 => 3, 7 => 0, 8 => 0, 108 => 4},
'hw_peth_port_power' => {6 => 3763, 7 => 0, 8 => 0}, 'hw_peth_port_power' => {6 => 3763, 7 => 0, 8 => 0, 108 => 8374},
'hw_fan_state' =>
{'1.1' => 'normal', '1.2' => 'abnormal', '2.1' => 'normal'},
'hw_fan_descr' =>
{'1.1' => 'slot1,FAN1', '1.2' => 'slot1,FAN2', '2.1' => 'slot2,FAN1'},
'hw_pwr_state' =>
{'1.1' => 'supply', '1.2' => 'notSupply', '2.1' => 'unknown'},
'hw_pwr_descr' =>
{'1.1' => 'slot1,PWR1', '1.2' => 'slot1,PWR2', '2.1' => 'slot2,PWR1'},
}, },
}; };
$test->{info}->cache($cache_data); $test->{info}->cache($cache_data);
@@ -254,7 +271,7 @@ sub peth_port_ifindex : Tests(3) {
can_ok($test->{info}, 'peth_port_ifindex'); can_ok($test->{info}, 'peth_port_ifindex');
my $expected = {'0.6' => 6, '0.7' => 7, '0.8' => 8},; my $expected = {'0.6' => 6, '0.7' => 7, '0.8' => 8, '1.108' => 108};
cmp_deeply($test->{info}->peth_port_ifindex(), cmp_deeply($test->{info}->peth_port_ifindex(),
$expected, q(POE port 'ifIndex' mapping returns expected values)); $expected, q(POE port 'ifIndex' mapping returns expected values));
@@ -269,7 +286,8 @@ sub peth_port_admin : Tests(3) {
can_ok($test->{info}, 'peth_port_admin'); can_ok($test->{info}, 'peth_port_admin');
my $expected = {'0.6' => 'true', '0.7' => 'false', '0.8' => 'true'}; my $expected
= {'0.6' => 'true', '0.7' => 'false', '0.8' => 'true', '1.108' => 'true'};
cmp_deeply($test->{info}->peth_port_admin(), cmp_deeply($test->{info}->peth_port_admin(),
$expected, q(POE port admin status returns expected values)); $expected, q(POE port admin status returns expected values));
@@ -284,8 +302,12 @@ sub peth_port_status : Tests(3) {
can_ok($test->{info}, 'peth_port_status'); can_ok($test->{info}, 'peth_port_status');
my $expected my $expected = {
= {'0.6' => 'deliveringPower', '0.7' => 'disabled', '0.8' => 'searching'}; '0.6' => 'deliveringPower',
'0.7' => 'disabled',
'0.8' => 'searching',
'1.108' => 'deliveringPower'
};
cmp_deeply($test->{info}->peth_port_status(), cmp_deeply($test->{info}->peth_port_status(),
$expected, q(POE port status returns expected values)); $expected, q(POE port status returns expected values));
@@ -300,7 +322,12 @@ sub peth_port_class : Tests(3) {
can_ok($test->{info}, 'peth_port_class'); can_ok($test->{info}, 'peth_port_class');
my $expected = {'0.6' => 'class3', '0.7' => 'class0', '0.8' => 'class0'}; my $expected = {
'0.6' => 'class3',
'0.7' => 'class0',
'0.8' => 'class0',
'1.108' => 'class4'
};
cmp_deeply($test->{info}->peth_port_class(), cmp_deeply($test->{info}->peth_port_class(),
$expected, q(POE port class returns expected values)); $expected, q(POE port class returns expected values));
@@ -315,7 +342,7 @@ sub peth_port_power : Tests(3) {
can_ok($test->{info}, 'peth_port_power'); can_ok($test->{info}, 'peth_port_power');
my $expected = {'0.6' => 3763, '0.7' => 0, '0.8' => 0}; my $expected = {'0.6' => 3763, '0.7' => 0, '0.8' => 0, '1.108' => 8374};
cmp_deeply($test->{info}->peth_port_power(), cmp_deeply($test->{info}->peth_port_power(),
$expected, q(POE port power returns expected values)); $expected, q(POE port power returns expected values));
@@ -330,7 +357,7 @@ sub peth_port_neg_power : Tests(3) {
can_ok($test->{info}, 'peth_port_neg_power'); can_ok($test->{info}, 'peth_port_neg_power');
my $expected = {'0.6' => 12950}; my $expected = {'0.6' => 12950, '1.108' => 25500};
cmp_deeply($test->{info}->peth_port_neg_power(), cmp_deeply($test->{info}->peth_port_neg_power(),
$expected, q(POE port negotiated power returns expected values)); $expected, q(POE port negotiated power returns expected values));
@@ -340,6 +367,70 @@ sub peth_port_neg_power : Tests(3) {
{}, q(No data returns empty hash)); {}, q(No data returns empty hash));
} }
sub fan : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'fan');
my $expected = 'slot1,FAN2: abnormal';
is($test->{info}->fan(), $expected, q(Fan returns expected value));
# Change abnormal fan state to normal to test alternate message
$test->{info}{store}{hw_fan_state}{'1.2'} = 'normal';
$expected = '3 fans OK';
is($test->{info}->fan(), $expected, q(Fans OK returns expected value));
$test->{info}->clear_cache();
is($test->{info}->fan(), undef, q(No data returns undef));
}
sub ps1_status : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'ps1_status');
my $expected = 'slot1,PWR1: supply, slot2,PWR1: unknown';
is($test->{info}->ps1_status(), $expected, q(PS1 returns expected value));
$test->{info}->clear_cache();
is($test->{info}->ps1_status(), undef, q(No data returns undef));
}
sub ps2_status : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'ps2_status');
my $expected = 'slot1,PWR2: notSupply';
is($test->{info}->ps2_status(), $expected, q(PS2 returns expected value));
$test->{info}->clear_cache();
is($test->{info}->ps2_status(), undef, q(No data returns undef));
}
sub i_mtu : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'i_mtu');
# Test with 'ifMtu' first, so we don't overwrite the i_mtu cache values
my $expected = {6 => 1500, 7 => 1500, 8 => 1500};
cmp_deeply($test->{info}->i_mtu(), $expected, q(MTU values using 'ifMtu'));
# Make the 'hw_eth_frame_len' cahce values visible
$test->{info}{'_hw_eth_frame_len'} = 1;
$expected = {6 => 2000, 7 => 2000, 8 => 1500};
cmp_deeply($test->{info}->i_mtu(),
$expected, q(MTU values using 'hwEthernetJumboframeMaxLength'));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_mtu(), {}, q(No mapping returns empty hash));
}
sub munge_hw_peth_admin : Tests(4) { sub munge_hw_peth_admin : Tests(4) {
my $test = shift; my $test = shift;