netdisco/snmp-info

SNMP::Info method resolution issue

Closed this issue · 6 comments

As described on IRC: after upgrading our primary management server, suddenly I'm running into problems with SNMP::Info methods that "bleed" from one device class to another.

The situation arises when our script polls devices from different device classes. I managed to create a fairly minimal reproduction script, with the v_name() method as an example.

I called it 'snmp_info_mro_bug.pl'; code is below.

Simply run the script with multiple pairs of hostname/ip and SNMP community, eg './snmp_info_mro_bug.pl switch1 public switch2 private' or something like that. When 'switch1' is an HP device (Layer2::HP) and 'switch2' is Cisco (Layer3::Cisco), I see on both occasions that v_name() is resolved to Q-BRIDGE-MIB::dot1qVlanStaticName. When I switch the order of switches, suddenly both devices are polled with v_name() resolving to CISCO-VTP-MIB::vtpVlanName. I would expect the order not to matter, and the HP device to always use Q-BRIDGE-MIB for the v_name() method and the Cisco to always use VTP-MIB.

#!/usr/bin/perl -w
use strict;
use warnings;

use SNMP::Info;
use Data::Dumper;

my @mibdirs = (
    '/usr/local/netdisco/mibs',
    '/usr/local/netdisco/mibs/rfc',
    '/usr/local/netdisco/mibs/cisco',
    '/usr/local/netdisco/mibs/hp',
    '/usr/local/netdisco/mibs/net-snmp',
);

while (@ARGV) {
    printf("%s\n", '=' x 40);
    my $ip = shift @ARGV;
    my $com = shift @ARGV;
    my $info = &connect($ip, $com);
    print Dumper($info->v_name());
    printf("%s\n", '=' x 40);
}

exit;

### end of main ###

sub connect {
    my $dns = shift;
    my $comm = shift;
    my $ver = shift || 2;
    my $info = new SNMP::Info(
        AutoSpecify => 1,
        Debug      => 1,
        SNMPDebug  => 1,,
        BulkWalk    => 1,
        MibDirs  => \@mibdirs,
        DestHost    => $dns,
        Community   => $comm,
        Version  => $ver,
        IgnoreNetSNMPConf => 1,
    );
    return $info;
}

Cisco -> HP order:

netmgt@linux469:~/bin$ ./snmp_info_mro_bug.pl simon rocommu sw1-beachveld rocummu
========================================
SNMP::Info::_global layers : SNMPv2-MIB::sysServices.0 : .1.3.6.1.2.1.1.7.0
SNMP::Info::_global description : SNMPv2-MIB::sysDescr.0 : .1.3.6.1.2.1.1.1.0
SNMP::Info::_global id : SNMPv2-MIB::sysObjectID.0 : .1.3.6.1.2.1.1.2.0
SNMP::Info 3.70
SNMP::Info::device_type() layers:01001110 id:9 sysDescr:"Cisco IOS Software, c6848x Software (c6848x-ADVENTERPRISEK9-M), Version 15.5(1)SY5, RELEASE SOFTWARE (fc3) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2020 by Cisco Systems, Inc. Compiled Tue 04-Feb-20 14:27 by prod_rel_team"
SNMP::Info::specify() - Changed Class to SNMP::Info::Layer3::Cisco.
SNMP::Info::_load_attr v_name : CISCO-VTP-MIB::vtpVlanName : .1.3.6.1.4.1.9.9.46.1.3.1.1.4
$VAR1 = {
          '1.21' => 'VLAN0021',
          '1.1' => 'default',
          '1.16' => 'VLAN0016',
          '1.11' => 'VLAN0011',
          '1.18' => 'VLAN0018',
          '1.17' => 'VLAN0017',
          '1.12' => 'VLAN0012',
          '1.22' => 'VLAN0022',
          '1.13' => 'VLAN0013',
          '1.23' => 'VLAN0023',
          '1.1002' => 'fddi-default',
          '1.19' => 'VLAN0019',
          '1.15' => 'VLAN0015',
          '1.1004' => 'fddinet-default',
          '1.20' => 'VLAN0020',
          '1.1005' => 'trnet-default',
          '1.14' => 'VLAN0014',
          '1.1003' => 'token-ring-default'
        };
========================================
========================================
SNMP::Info::_global layers : SNMPv2-MIB::sysServices.0 : .1.3.6.1.2.1.1.7.0
SNMP::Info::_global description : SNMPv2-MIB::sysDescr.0 : .1.3.6.1.2.1.1.1.0
SNMP::Info::_global id : SNMPv2-MIB::sysObjectID.0 : .1.3.6.1.2.1.1.2.0
SNMP::Info 3.70
SNMP::Info::device_type() layers:01001010 id:11 sysDescr:"Aruba JL258A 2930F-8G-PoE+-2SFP+ Switch, revision WC.16.10.0007, ROM WC.16.01.0008 (/ws/swbuildm/ajanta_qt_qaoff/code/build/lvm(swbuildm_ajanta_qt_qaoff_ajanta_qt))"
SNMP::Info::specify() - Changed Class to SNMP::Info::Layer2::HP.
SNMP::Info::_load_attr v_name : CISCO-VTP-MIB::vtpVlanName : .1.3.6.1.4.1.9.9.46.1.3.1.1.4
$VAR1 = undef;
========================================

HP -> Cisco order:

netmgt@linux469:~/bin$ ./snmp_info_mro_bug.pl sw1-beachveld rocommu simon rocommu
========================================
SNMP::Info::_global layers : SNMPv2-MIB::sysServices.0 : .1.3.6.1.2.1.1.7.0
SNMP::Info::_global description : SNMPv2-MIB::sysDescr.0 : .1.3.6.1.2.1.1.1.0
SNMP::Info::_global id : SNMPv2-MIB::sysObjectID.0 : .1.3.6.1.2.1.1.2.0
SNMP::Info 3.70
SNMP::Info::device_type() layers:01001010 id:11 sysDescr:"Aruba JL258A 2930F-8G-PoE+-2SFP+ Switch, revision WC.16.10.0007, ROM WC.16.01.0008 (/ws/swbuildm/ajanta_qt_qaoff/code/build/lvm(swbuildm_ajanta_qt_qaoff_ajanta_qt))"
SNMP::Info::specify() - Changed Class to SNMP::Info::Layer2::HP.
SNMP::Info::_load_attr v_name : Q-BRIDGE-MIB::dot1qVlanStaticName : .1.3.6.1.2.1.17.7.1.4.3.1.1
$VAR1 = {
          '3164' => 'CAM-POIP',
          '3101' => 'CAM-WLAN',
          '3102' => 'CAM-VOIP',
          '3100' => 'CAM-NMS',
          '3113' => 'CAM-Print',
          '3118' => 'CAM-CAM',
          '3105' => 'CAM-Werkplek',
          '3114' => 'CAM-IPTV',
          '3108' => 'CAM-Meters',
          '103' => 'Campusnet',
          '1' => 'DEFAULT_VLAN'
        };
========================================
========================================
SNMP::Info::_global layers : SNMPv2-MIB::sysServices.0 : .1.3.6.1.2.1.1.7.0
SNMP::Info::_global description : SNMPv2-MIB::sysDescr.0 : .1.3.6.1.2.1.1.1.0
SNMP::Info::_global id : SNMPv2-MIB::sysObjectID.0 : .1.3.6.1.2.1.1.2.0
SNMP::Info 3.70
SNMP::Info::device_type() layers:01001110 id:9 sysDescr:"Cisco IOS Software, c6848x Software (c6848x-ADVENTERPRISEK9-M), Version 15.5(1)SY5, RELEASE SOFTWARE (fc3) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2020 by Cisco Systems, Inc. Compiled Tue 04-Feb-20 14:27 by prod_rel_team"
SNMP::Info::specify() - Changed Class to SNMP::Info::Layer3::Cisco.
SNMP::Info::_load_attr v_name : Q-BRIDGE-MIB::dot1qVlanStaticName : .1.3.6.1.2.1.17.7.1.4.3.1.1
$VAR1 = undef;
========================================

# NOTE: Order creates precedence
# Example: v_name exists in Bridge.pm and CiscoVTP.pm
# Bridge is called from Layer3 and CiscoStpExtensions
# So we want CiscoVTP to come last to get the right one.
# The @ISA order should match these orders.

since layer2::hp includes layer3:

@SNMP::Info::Layer2::HP::ISA = qw/
SNMP::Info::Aggregate
SNMP::Info::Layer3
SNMP::Info::MAU
SNMP::Info::CDP
Exporter

it will depend on the loading order of snmp, which afaik i undefined:
#325 (comment)
netdisco/netdisco-mibs#104

imo the correct fix should be to refine the loading order in layer2::hp or clear cached functions when changing devices (can createa performance hit). https://metacpan.org/pod/SNMP::Info#update()

after upgrading our primary management server

site note, what version of net-snmp & such are provided after the upgrade? 5.7.3, 5.8 or 5.9?

specific in 5.9:

libsnmp:
Scan MIB directories in alphabetical order This guarantees that
e.g. mibs/RFC1213-MIB.txt is read before mibs/SNMPv2-MIB.txt. The
order in which these MIBs is read matters because both define
sysLocation but with different attributes.

#!/usr/bin/perl -w

[...]

while (@argv) {
printf("%s\n", '=' x 40);
my $ip = shift @argv;
my $com = shift @argv;

undef *SNMP::Info::v_name;

my $info = &connect($ip, $com);
print Dumper($info->v_name());
printf("%s\n", '=' x 40);

}

exit;
[...]

Adding that 'undef *SNMP::Info::v_name;' line fixes it. Apparently, the v_name() method is added to the (global) Perl script symbol table, under the SNMP::Info namespace. So this is not an issue with MIB loading order, it's the first SNMP::Info instance that leaves SNMP::Info methods lingering around which are then erroneously used by newly created SNMP::Info instances in the script.

Not sure how to fix this, though... @jeneric , iirc you know a lot more about these SNMP::Info internals, hop that you can help out here?

after upgrading our primary management server

site note, what version of net-snmp & such are provided after the upgrade? 5.7.3, 5.8 or 5.9?

Just checked: it's Ubuntu 20.04.01 LTS, with net-snmp 5.8 ("5.8+dfsg-2ubuntu2.3") and Perl 5.30 ("5.30.0-9build1").

The issue doesn't seem to come from net-snmp though, I believe that it's due to SNMP::Info adding AUTOLOAD'ed methods into the SNMP::Info class symbol table.

Edit: can't explain yet why I never ran into issues with this before upgrading (or at least, didn't notice); the specific SNMP::Info bit of code that appears to be at fault was committed in 2012 and was already present in the library version that we used before upgrading. I believe that we used Perl 5.22 earlier, so maybe that made some difference.

ollyg commented

I'm gonna say resolved, then?