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

Reply via email to