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:
11
Changes
11
Changes
@@ -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)
|
||||
|
||||
[ENHANCEMENTS]
|
||||
|
||||
@@ -48,11 +48,12 @@ $VERSION = '3.57';
|
||||
%MIBS = (
|
||||
%SNMP::Info::Layer3::MIBS,
|
||||
%SNMP::Info::IEEE802dot3ad::MIBS,
|
||||
'HUAWEI-MIB' => 'quidway',
|
||||
'HUAWEI-PORT-MIB' => 'hwEthernetDuplex',
|
||||
'HUAWEI-IF-EXT-MIB' => 'hwTrunkIfIndex',
|
||||
'HUAWEI-L2IF-MIB' => 'hwL2IfPortIfIndex',
|
||||
'HUAWEI-POE-MIB' => 'hwPoePower',
|
||||
'HUAWEI-MIB' => 'quidway',
|
||||
'HUAWEI-PORT-MIB' => 'hwEthernetDuplex',
|
||||
'HUAWEI-IF-EXT-MIB' => 'hwTrunkIfIndex',
|
||||
'HUAWEI-L2IF-MIB' => 'hwL2IfPortIfIndex',
|
||||
'HUAWEI-POE-MIB' => 'hwPoePower',
|
||||
'HUAWEI-ENTITY-EXTENT-MIB' => 'hwEntityFanState',
|
||||
);
|
||||
|
||||
%GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, );
|
||||
@@ -61,12 +62,13 @@ $VERSION = '3.57';
|
||||
%SNMP::Info::Layer3::FUNCS,
|
||||
%SNMP::Info::IEEE802dot3ad::FUNCS,
|
||||
|
||||
# HUAWEI-PORT-MIB::
|
||||
# HUAWEI-PORT-MIB::hwEthernetTable
|
||||
'hw_eth_speed_admin' => 'hwEthernetSpeedSet',
|
||||
'hw_eth_duplex' => 'hwEthernetDuplex',
|
||||
'hw_eth_auto' => 'hwEthernetNegotiation',
|
||||
'hw_eth_frame_len' => 'hwEthernetJumboframeMaxLength',
|
||||
|
||||
# HUAWEI-PORT-MIB::
|
||||
# HUAWEI-PORT-MIB::hwPhysicalPortTable
|
||||
'hw_phy_port_slot' => 'hwPhysicalPortInSlot',
|
||||
|
||||
# HUAWEI-IF-EXT-MIB::hwTrunkIfTable
|
||||
@@ -87,6 +89,13 @@ $VERSION = '3.57';
|
||||
'peth_power_consumption' => 'hwPoeSlotConsumingPower',
|
||||
'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 = (
|
||||
@@ -109,7 +118,9 @@ sub os {
|
||||
my $huawei = shift;
|
||||
my $descr = $huawei->description();
|
||||
|
||||
return $1 if ( $descr =~ /\b(VRP)\b/ );
|
||||
if ( $descr =~ /\b(VRP)\b/ ) {
|
||||
return $1;
|
||||
}
|
||||
return "huawei";
|
||||
}
|
||||
|
||||
@@ -151,7 +162,7 @@ sub i_ignore {
|
||||
foreach my $if ( keys %$interfaces ) {
|
||||
|
||||
# lo0 etc
|
||||
if ( $interfaces->{$if} =~ /\b(inloopback|console)\d*\b/i ) {
|
||||
if ( $interfaces->{$if} =~ /\b(inloopback|console)\d*\b/ix ) {
|
||||
$i_ignore{$if}++;
|
||||
}
|
||||
}
|
||||
@@ -238,14 +249,12 @@ sub agg_ports {
|
||||
# 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 $i_descr = $huawei->i_description() || {};
|
||||
|
||||
my $peth_port_ifindex = {};
|
||||
|
||||
@@ -256,6 +265,11 @@ sub peth_port_ifindex {
|
||||
{
|
||||
$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;
|
||||
}
|
||||
return $peth_port_ifindex;
|
||||
@@ -359,6 +373,79 @@ sub 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 {
|
||||
my $admin = shift;
|
||||
|
||||
@@ -387,7 +474,7 @@ sub munge_hw_peth_status {
|
||||
# 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 = 'searching' if $pwr =~ /(Powering|Power-ready|Detecting)/ix;
|
||||
$pwr = 'deliveringPower' if $pwr =~ /Powered/i;
|
||||
$pwr = 'fault' if $pwr =~ /fault/i;
|
||||
|
||||
@@ -449,6 +536,8 @@ Subclass for Huawei switches
|
||||
|
||||
=item F<HUAWEI-POE-MIB>
|
||||
|
||||
=item F<HUAWEI-ENTITY-EXTENT-MIB>
|
||||
|
||||
=item Inherited Classes' MIBs
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
=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>
|
||||
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
|
||||
|
||||
=head2 Power Port Table
|
||||
|
||||
@@ -50,6 +50,7 @@ sub setup : Tests(setup) {
|
||||
'_id' => '.1.3.6.1.4.1.2011.2.239.12',
|
||||
'_i_index' => 1,
|
||||
'_i_description' => 1,
|
||||
'_i_mtu' => 1,
|
||||
'_hw_eth_duplex' => 1,
|
||||
'_hw_eth_auto' => 1,
|
||||
'_el_index' => 1,
|
||||
@@ -65,31 +66,47 @@ sub setup : Tests(setup) {
|
||||
'_hw_peth_port_status' => 1,
|
||||
'_hw_peth_port_class' => 1,
|
||||
'_hw_peth_port_power' => 1,
|
||||
'_hw_fan_state' => 1,
|
||||
'_hw_fan_descr' => 1,
|
||||
'_hw_pwr_state' => 1,
|
||||
'_hw_pwr_descr' => 1,
|
||||
|
||||
'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' => {
|
||||
1 => 'InLoopBack0',
|
||||
6 => 'GigabitEthernet0/0/1',
|
||||
7 => 'GigabitEthernet0/0/2',
|
||||
8 => 'GigabitEthernet0/0/3'
|
||||
1 => 'InLoopBack0',
|
||||
6 => 'GigabitEthernet0/0/1',
|
||||
7 => 'GigabitEthernet0/0/2',
|
||||
8 => 'GigabitEthernet0/0/3',
|
||||
108 => 'GigabitEthernet1/0/1'
|
||||
},
|
||||
'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},
|
||||
'i_mtu' => {6 => 1500, 7 => 1500, 8 => 1500},
|
||||
'hw_eth_frame_len' => {6 => 2000, 7 => 2000},
|
||||
'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_phy_port_slot' => {6 => 0, 7 => 0, 8 => 0, 108 => 1},
|
||||
'hw_peth_power_watts' => {0 => 369600, 1 => 739200},
|
||||
'hw_peth_port_admin' =>
|
||||
{6 => 'enabled', 7 => 'disabled', 8 => 'enabled', 108 => '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},
|
||||
{6 => 'Powered', 7 => 'Disabled', 8 => 'Detecting', 108 => 'Powered'},
|
||||
'hw_peth_port_class' => {6 => 3, 7 => 0, 8 => 0, 108 => 4},
|
||||
'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);
|
||||
@@ -254,7 +271,7 @@ sub peth_port_ifindex : Tests(3) {
|
||||
|
||||
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(),
|
||||
$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');
|
||||
|
||||
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(),
|
||||
$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');
|
||||
|
||||
my $expected
|
||||
= {'0.6' => 'deliveringPower', '0.7' => 'disabled', '0.8' => 'searching'};
|
||||
my $expected = {
|
||||
'0.6' => 'deliveringPower',
|
||||
'0.7' => 'disabled',
|
||||
'0.8' => 'searching',
|
||||
'1.108' => 'deliveringPower'
|
||||
};
|
||||
|
||||
cmp_deeply($test->{info}->peth_port_status(),
|
||||
$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');
|
||||
|
||||
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(),
|
||||
$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');
|
||||
|
||||
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(),
|
||||
$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');
|
||||
|
||||
my $expected = {'0.6' => 12950};
|
||||
my $expected = {'0.6' => 12950, '1.108' => 25500};
|
||||
|
||||
cmp_deeply($test->{info}->peth_port_neg_power(),
|
||||
$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));
|
||||
}
|
||||
|
||||
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) {
|
||||
my $test = shift;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user