SNMPv3 bulkwalk()/get() fail when using async/callback AND explicit
EngineID (Issue 3)
I'm having issues retrieving data via SNMPv3 when using async/callback
AND explicitly specifying the EngineID.
(This is separate to the EngineID discovery blocking issue I've logged
elsewhere)
FAIL:
If I make an asynchronous bulkwalk() request, explicity specifying the
EngineID, I receive an immediate empty callback. Debugging shows the
first SNMP request/reply packet successfully returned complete with
device data, but this is never returned to the user and there is no
further SNMP traffic or callbacks.
SUCCESS:
If I make a Non-asynchronous bulkwalk() request explicity specifying
the EngineID, the requested table is returned once polled.
SUCCESS:
If I make an asynchronous bulkwalk() request, leaving the EngineID to
be automagically discovered, the requested table is returned via
callback (VarList of VarBinds).
Similarly with get()
FAIL:
If I make an asynchronous get() request, explicity specifying the
EngineID, I get a segmentation fault.
SUCCESS:
If I make a Non-asynchronous get() request explicity specifying the
EngineID, the requested MIB value is returned.
SUCCESS:
If I make an asynchronous get() request, leaving the EngineID to be
automagically discovered, the correct VarBind result is returned via
callback.
If feel this indicates that I'm correctly handling both callbacks and
the setting of the EngineID, but used together it surfaces some bug.
Anyone any workaround such that I can use async AND explicit EngineID?
Any advice gratefully received. Further details below.
Background:
I use async/callbacks because of the number of devices I'm regularly
polling (thousands)
I'm looking to explicitly specify the EngineIDs because:
1) It reduces SNMPv3 overhead as I already have the EngineIDs available
2) It removes the blocking during the automagic EngineID discovery
that occurs in bulkwalk(), get(), etc. when a device is unavailable.
I potentially have a couple of dozen inaccessible devices at any time,
and these block the running of my MainLoop() against accessible
devices. This causes:
2a) Timeout of devices that are accessible as the inaccessible device
blocking of MainLoop() affects SNMP data processing of accessible
devices.
2b) Inaccessible devices whose automagic EngineID discovery fails do
not release their SNMP::Session. This cannot be closed manually and
the UDP socket is not returned to the OS until Perl exits.
Test script which fails - (use only async OR EngineID and this should work):
#!/usr/bin/perl
use warnings;
use strict;
use SNMP;
$SNMP::auto_init_mib=0;
$SNMP::use_numeric=1;
$SNMP::debugging=2;
$SNMP::verbose=2;
$SNMP::non_increasing=1;
use Time::HiRes qw(gettimeofday);
use POSIX qw(strftime);
my $generic_dev = { dev=> {
DestHost => '172.19.99.99',
RemotePort => 161,
Version => '3',
SecName => "RO-SECNAME",
SecLevel => "authPriv",
AuthProto => "SHA",
AuthPass => 'AUTHPASS',
PrivProto => "AES",
PrivPass => 'PRIVPASS',
#SecEngineId => '', #Autodiscover
SecEngineId => '800012345678901234567890', #Explicit EngineID
previously acquired
ContextEngineId => '',
Retries => 3,
Timeout => 1000000,
}};
my $varlist = snmpwalk($generic_dev);
logMe('Result count (non-async): '. scalar @{$varlist->[0]})
if((ref($varlist) eq 'ARRAY') && ($varlist->[0])); #Non-async
result count
die "Cannot do bulkwalk: $generic_dev->{ErrorStr}
($generic_dev->{ErrorNum})\n" if $generic_dev->{ErrorNum};
&SNMP::MainLoop();
exit;
sub snmpwalk {
my $tr=shift;
if(!defined($tr->{sess})) {
$tr->{sess} = SNMP::Session->new( %{$tr->{dev}} ) or logMe("$0:
impossible to obtain a new work v3 SNMP::Session; $!");
}
my $oid='.1.3.6.1.2.1.2.2.1.2'; #ifName table
my @arr=( [ $oid ] );
my $vars = new SNMP::VarList(@arr);
logMe('v3 calling bulkwalk() - ' . $tr->{dev}->{DestHost});
#my $varlist = $tr->{sess}->bulkwalk(0, 25, $vars);
#Non-async
my $varlist = $tr->{sess}->bulkwalk(0, 25, $vars, [ \&callback,
$tr, $vars ]); #Async
logMe('v3 returned bulkwalk() - ' . $tr->{dev}->{DestHost});
return $varlist;
}
sub callback { #Should be called on data returned, or (no response) timeout
my $tr=shift;
my $vars=shift;
my $vals=shift;
logMe('Callback for ' . $tr->{dev}->{DestHost});
logMe('Result count (async): '. scalar @{$vals->[0]})
if($vals->[0]); #Async result count
}
sub logMe {
my ($t, $nsec) = gettimeofday;
my @t = localtime $t;
printf("%s %s\n", POSIX::strftime('%T.', @t) . $nsec, shift);
}
Environment:
Ubuntu 22.04.5 LTS
libsnmp-base/jammy-updates,jammy-security,now 5.9.1+dfsg-1ubuntu2.9
libsnmp40/jammy-updates,jammy-security,now 5.9.1+dfsg-1ubuntu2.9 amd64
[installed,automatic]
libsnmp-perl/jammy-updates,jammy-security,now 5.9.1+dfsg-1ubuntu2.9
amd64 [installed]
perl5 (revision 5 version 34 subversion 0)
Many thanks,
Paul S.
_______________________________________________
Net-snmp-coders mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders