SNMPv3 bulkwalk()/get() fail when using async/callback AND explicit EngineID

Paul S <[email protected]> Wed, 17 Jun 2026 14:33:35 +0100
Newsgroups gmane.network.net-snmp.devel
Message-ID <[email protected]>
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.