1 # Copyright (C) 2002-2007 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id: SNMP.pm,v 1.1 2010-12-27 00:03:58 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 package Torrus::Collector::SNMP;
22 use Torrus::Collector::SNMP_Params;
23 use Torrus::ConfigTree;
25 use Torrus::SNMP_Failures;
30 use Net::SNMP qw(:snmp);
34 # Register the collector type
35 $Torrus::Collector::collectorTypes{'snmp'} = 1;
38 # List of needed parameters and default values
40 $Torrus::Collector::params{'snmp'} = {
41 'snmp-ipversion' => undef,
42 'snmp-transport' => undef,
43 'snmp-version' => undef,
45 'snmp-community' => undef,
46 'snmp-username' => undef,
47 'snmp-authkey' => undef,
48 'snmp-authpassword' => undef,
49 'snmp-authprotocol' => 'md5',
50 'snmp-privkey' => undef,
51 'snmp-privpassword' => undef,
52 'snmp-privprotocol' => 'des',
53 'snmp-timeout' => undef,
54 'snmp-retries' => undef,
55 'domain-name' => undef,
57 'snmp-localaddr' => undef,
58 'snmp-localport' => undef,
59 'snmp-object' => undef,
60 'snmp-oids-per-pdu' => undef,
61 'snmp-object-type' => 'OTHER',
62 'snmp-check-sysuptime' => 'yes',
63 'snmp-max-msg-size' => undef,
64 'snmp-ignore-mib-errors' => undef,
67 my $sysUpTime = '1.3.6.1.2.1.1.3.0';
69 # Hosts that are running SNMPv1. We do not reresh maps on them, as
73 # SNMP tables lookup maps
76 # Old lookup maps, used temporarily during refresh cycle
79 # How frequent we refresh the SNMP mapping
80 our $mapsRefreshPeriod;
82 # Random factor in refresh period
83 our $mapsRefreshRandom;
85 # Time period after configuration re-compile when we refresh existing mappings
86 our $mapsUpdateInterval;
88 # how often we check for expired maps
89 our $mapsExpireCheckPeriod;
91 # expiration time for each map
94 # Lookups scheduled for execution
95 my %mapLookupScheduled;
97 # SNMP session objects for map lookups
101 # Timestamps of hosts last found unreachable
102 my %hostUnreachableSeen;
104 # Last time we tried to reach an unreachable host
105 my %hostUnreachableRetry;
107 # Hosts that were deleted because of unreachability for too long
108 my %unreachableHostDeleted;
113 # Flush stats after a restart or recompile
114 $Torrus::Collector::initCollectorGlobals{'snmp'} =
115 \&Torrus::Collector::SNMP::initCollectorGlobals;
117 sub initCollectorGlobals
120 my $instance = shift;
122 if( not defined( $db_failures ) )
125 new Torrus::SNMP_Failures( -Tree => $tree,
126 -Instance => $instance,
130 if( defined( $db_failures ) )
132 $db_failures->init();
135 # re-init counters and collect garbage
137 %hostUnreachableSeen = ();
138 %hostUnreachableRetry = ();
139 %unreachableHostDeleted = ();
141 # Configuration re-compile was probably caused by new object instances
142 # appearing on the monitored devices. Here we force the maps to refresh
143 # soon enough in order to catch up with the changes
146 foreach my $maphash ( keys %mapsExpire )
148 $mapsExpire{$maphash} = int( $now + rand( $mapsUpdateInterval ) );
153 # This is first executed per target
155 $Torrus::Collector::initTarget{'snmp'} = \&Torrus::Collector::SNMP::initTarget;
161 my $collector = shift;
164 my $tref = $collector->tokenData( $token );
165 my $cref = $collector->collectorData( 'snmp' );
167 $collector->registerDeleteCallback
168 ( $token, \&Torrus::Collector::SNMP::deleteTarget );
170 my $hostname = getHostname( $collector, $token );
171 if( not defined( $hostname ) )
176 $tref->{'hostname'} = $hostname;
178 return Torrus::Collector::SNMP::initTargetAttributes( $collector, $token );
182 sub initTargetAttributes
184 my $collector = shift;
187 &Torrus::DB::checkInterrupted();
189 my $tref = $collector->tokenData( $token );
190 my $cref = $collector->collectorData( 'snmp' );
192 my $hostname = $tref->{'hostname'};
193 my $port = $collector->param($token, 'snmp-port');
194 my $version = $collector->param($token, 'snmp-version');
197 if( $version eq '1' or $version eq '2c' )
199 $community = $collector->param($token, 'snmp-community');
203 # We use community string to identify the agent.
204 # For SNMPv3, it's the user name
205 $community = $collector->param($token, 'snmp-username');
208 my $hosthash = join('|', $hostname, $port, $community);
209 $tref->{'hosthash'} = $hosthash;
211 if( $version eq '1' )
213 $snmpV1Hosts{$hosthash} = 1;
216 # If the object is defined as a map, retrieve the whole map
219 if( isHostDead( $collector, $hosthash ) )
224 if( not checkUnreachableRetry( $collector, $hosthash ) )
226 $cref->{'needsRemapping'}{$token} = 1;
230 my $oid = $collector->param($token, 'snmp-object');
231 $oid = expandOidMappings( $collector, $token, $hosthash, $oid );
235 if( $unreachableHostDeleted{$hosthash} )
237 # we tried our best, but the target is dead
242 # we return OK status, to let the storage initiate
243 $cref->{'needsRemapping'}{$token} = 1;
247 elsif( $oid eq 'notfound' )
252 # Collector should be able to find the target
253 # by host, port, community, and oid.
254 # There can be several targets with the same host|port|community+oid set.
256 $cref->{'targets'}{$hosthash}{$oid}{$token} = 1;
257 $cref->{'activehosts'}{$hosthash} = 1;
259 $tref->{'oid'} = $oid;
261 $cref->{'oids_per_pdu'}{$hosthash} =
262 $collector->param($token, 'snmp-oids-per-pdu');
264 if( $collector->param($token, 'snmp-object-type') eq 'COUNTER64' )
266 $cref->{'64bit_oid'}{$oid} = 1;
269 if( $collector->param($token, 'snmp-check-sysuptime') eq 'no' )
271 $cref->{'nosysuptime'}{$hosthash} = 1;
274 if( $collector->param($token, 'snmp-ignore-mib-errors') eq 'yes' )
276 $cref->{'ignoremiberrors'}{$hosthash}{$oid} = 1;
285 my $collector = shift;
288 my $cref = $collector->collectorData( 'snmp' );
290 my $hostname = $collector->param($token, 'snmp-host');
291 my $domain = $collector->param($token, 'domain-name');
293 if( length( $domain ) > 0 and
294 index($hostname, '.') < 0 and
295 index($hostname, ':') < 0 )
297 $hostname .= '.' . $domain;
306 my $collector = shift;
308 my $hosthash = shift;
310 my $cref = $collector->collectorData( 'snmp' );
311 if( defined( $cref->{'snmpargs'}{$hosthash} ) )
313 return $cref->{'snmpargs'}{$hosthash};
316 my $transport = $collector->param($token, 'snmp-transport') . '/ipv' .
317 $collector->param($token, 'snmp-ipversion');
319 my ($hostname, $port, $community) = split(/\|/o, $hosthash);
321 my $version = $collector->param($token, 'snmp-version');
322 my $ret = [ -domain => $transport,
323 -hostname => $hostname,
325 -timeout => $collector->param($token, 'snmp-timeout'),
326 -retries => $collector->param($token, 'snmp-retries'),
327 -version => $version ];
329 foreach my $arg ( qw(-localaddr -localport) )
331 if( defined( $collector->param($token, 'snmp' . $arg) ) )
333 push( @{$ret}, $arg, $collector->param($token, 'snmp' . $arg) );
337 if( $version eq '1' or $version eq '2c' )
339 push( @{$ret}, '-community', $community );
343 push( @{$ret}, -username, $community);
345 foreach my $arg ( qw(-authkey -authpassword -authprotocol
346 -privkey -privpassword -privprotocol) )
348 if( defined( $collector->param($token, 'snmp' . $arg) ) )
351 $arg, $collector->param($token, 'snmp' . $arg) );
356 $cref->{'snmpargs'}{$hosthash} = $ret;
362 sub openBlockingSession
364 my $collector = shift;
366 my $hosthash = shift;
368 my $args = snmpSessionArgs( $collector, $token, $hosthash );
369 my ($session, $error) =
370 Net::SNMP->session( @{$args},
372 -translate => ['-all', 0, '-octetstring', 1] );
373 if( not defined($session) )
375 Error('Cannot create SNMP session for ' . $hosthash . ': ' . $error);
379 my $maxmsgsize = $collector->param($token, 'snmp-max-msg-size');
380 if( defined( $maxmsgsize ) and $maxmsgsize > 0 )
382 $session->max_msg_size( $maxmsgsize );
389 sub openNonblockingSession
391 my $collector = shift;
393 my $hosthash = shift;
395 my $args = snmpSessionArgs( $collector, $token, $hosthash );
397 my ($session, $error) =
398 Net::SNMP->session( @{$args},
400 -translate => ['-timeticks' => 0] );
401 if( not defined($session) )
403 Error('Cannot create SNMP session for ' . $hosthash . ': ' . $error);
407 if( $collector->param($token, 'snmp-transport') eq 'udp' )
409 # We set SO_RCVBUF only once, because Net::SNMP shares
410 # one UDP socket for all sessions.
412 my $sock_name = $session->transport()->sock_name();
413 my $refcount = $Net::SNMP::Transport::SOCKETS->{
414 $sock_name}->[&Net::SNMP::Transport::_SHARED_REFC()];
418 my $buflen = int($Torrus::Collector::SNMP::RxBuffer);
419 my $socket = $session->transport()->socket();
420 my $ok = $socket->sockopt( SO_RCVBUF, $buflen );
423 Error('Could not set SO_RCVBUF to ' .
424 $buflen . ': ' . $!);
428 Debug('Set SO_RCVBUF to ' . $buflen);
433 my $maxmsgsize = $collector->param($token, 'snmp-max-msg-size');
434 if( defined( $maxmsgsize ) and $maxmsgsize > 0 )
436 $session->max_msg_size( $maxmsgsize );
444 sub expandOidMappings
446 my $collector = shift;
448 my $hosthash = shift;
451 my $cref = $collector->collectorData( 'snmp' );
455 # Process Map statements
457 while( index( $oid, 'M(' ) >= 0 )
459 if( not $oid =~ /^(.*)M\(\s*([0-9\.]+)\s*,\s*([^\)]+)\)(.*)$/o )
461 Error("Error in OID mapping syntax: $oid");
470 # Remove trailing space from key
474 lookupMap( $collector, $token, $hosthash, $map, $key );
476 if( defined( $value ) )
478 if( $value eq 'notfound' )
484 $oid = $head . $value . $tail;
493 # process value lookups
495 while( index( $oid, 'V(' ) >= 0 )
497 if( not $oid =~ /^(.*)V\(\s*([0-9\.]+)\s*\)(.*)$/o )
499 Error("Error in OID value lookup syntax: $oid");
509 if( not defined( $cref->{'value-lookups'}
510 {$hosthash}{$key} ) )
512 # Retrieve the OID value from host
514 my $session = openBlockingSession( $collector, $token, $hosthash );
515 if( not defined($session) )
520 my $result = $session->get_request( -varbindlist => [$key] );
522 if( defined $result and defined($result->{$key}) )
524 $value = $result->{$key};
525 $cref->{'value-lookups'}{$hosthash}{$key} = $value;
529 Error("Error retrieving $key from $hosthash: " .
531 probablyDead( $collector, $hosthash );
538 $cref->{'value-lookups'}{$hosthash}{$key};
540 if( defined( $value ) )
542 $oid = $head . $value . $tail;
550 # Debug('OID expanded: ' . $oid_in . ' -> ' . $oid');
554 # Look up table index in a map by value
558 my $collector = shift;
560 my $hosthash = shift;
564 my $cref = $collector->collectorData( 'snmp' );
565 my $maphash = join('#', $hosthash, $map);
567 if( not defined( $maps{$hosthash}{$map} ) )
571 if( defined( $oldMaps{$hosthash}{$map} ) and
574 $ret = $oldMaps{$hosthash}{$map}{$key};
577 if( $mapLookupScheduled{$maphash} )
582 if( scalar(@mappingSessions) >=
583 $Torrus::Collector::SNMP::maxSessionsPerDispatcher )
586 @mappingSessions = ();
587 %mapLookupScheduled = ();
590 # Retrieve map from host
591 Debug('Retrieving map ' . $map . ' from ' . $hosthash);
593 my $session = openNonblockingSession( $collector, $token, $hosthash );
594 if( not defined($session) )
600 push( @mappingSessions, $session );
603 # Retrieve the map table
605 $session->get_table( -baseoid => $map,
606 -callback => [\&mapLookupCallback,
607 $collector, $hosthash, $map] );
609 $mapLookupScheduled{$maphash} = 1;
611 if( not $snmpV1Hosts{$hosthash} )
613 $mapsExpire{$maphash} =
614 int( time() + $mapsRefreshPeriod +
615 rand( $mapsRefreshPeriod * $mapsRefreshRandom ) );
621 if( defined( $key ) )
623 my $value = $maps{$hosthash}{$map}{$key};
624 if( not defined $value )
626 Error("Cannot find value $key in map $map for $hosthash in ".
627 $collector->path($token));
628 if( defined ( $maps{$hosthash}{$map} ) )
630 Error("Current map follows");
631 while( my($key, $val) = each
632 %{$maps{$hosthash}{$map}} )
634 Error("'$key' => '$val'");
641 if( not $snmpV1Hosts{$hosthash} )
643 $cref->{'mapsDependentTokens'}{$maphash}{$token} = 1;
644 $cref->{'mapsRelatedMaps'}{$token}{$maphash} = 1;
657 sub mapLookupCallback
660 my $collector = shift;
661 my $hosthash = shift;
664 &Torrus::DB::checkInterrupted();
666 Debug('Received mapping PDU from ' . $hosthash);
668 my $result = $session->var_bind_list();
669 if( defined $result )
671 my $preflen = length($map) + 1;
673 while( my( $oid, $key ) = each %{$result} )
675 my $val = substr($oid, $preflen);
676 $maps{$hosthash}{$map}{$key} = $val;
677 # Debug("Map $map discovered: '$key' -> '$val'");
682 Error("Error retrieving table $map from $hosthash: " .
685 probablyDead( $collector, $hosthash );
690 sub activeMappingSessions
692 return scalar( @mappingSessions );
695 # The target host is unreachable. We try to reach it few more times and
696 # give it the final diagnose.
700 my $collector = shift;
701 my $hosthash = shift;
703 my $cref = $collector->collectorData( 'snmp' );
705 # Stop all collection for this host, until next initTargetAttributes
707 delete $cref->{'activehosts'}{$hosthash};
709 my $probablyAlive = 1;
711 if( defined( $hostUnreachableSeen{$hosthash} ) )
713 if( $Torrus::Collector::SNMP::unreachableTimeout > 0 and
715 $hostUnreachableSeen{$hosthash} >
716 $Torrus::Collector::SNMP::unreachableTimeout )
723 $hostUnreachableSeen{$hosthash} = time();
725 if( defined( $db_failures ) )
727 $db_failures->host_failure('unreachable', $hosthash);
728 $db_failures->set_counter('unreachable',
729 scalar( keys %hostUnreachableSeen));
735 Info('Target host is unreachable. Will try again later: ' . $hosthash);
739 # It is dead indeed. Delete all tokens associated with this host
740 Info('Target host is unreachable during last ' .
741 $Torrus::Collector::SNMP::unreachableTimeout .
742 ' seconds. Giving it up: ' . $hosthash);
743 my @deleteTargets = ();
744 while( my ($oid, $ref1) =
745 each %{$cref->{'targets'}{$hosthash}} )
747 while( my ($token, $dummy) = each %{$ref1} )
749 push( @deleteTargets, $token );
753 Debug('Deleting ' . scalar( @deleteTargets ) . ' tokens');
754 foreach my $token ( @deleteTargets )
756 $collector->deleteTarget($token);
759 delete $hostUnreachableSeen{$hosthash};
760 delete $hostUnreachableRetry{$hosthash};
761 $unreachableHostDeleted{$hosthash} = 1;
763 if( defined( $db_failures ) )
765 $db_failures->host_failure('deleted', $hosthash);
766 $db_failures->set_counter('unreachable',
767 scalar( keys %hostUnreachableSeen));
768 $db_failures->set_counter('deleted',
769 scalar( keys %unreachableHostDeleted));
773 return $probablyAlive;
776 # Return false if the try is too early
778 sub checkUnreachableRetry
780 my $collector = shift;
781 my $hosthash = shift;
783 my $cref = $collector->collectorData( 'snmp' );
786 if( $hostUnreachableSeen{$hosthash} )
788 my $lastRetry = $hostUnreachableRetry{$hosthash};
790 if( not defined( $lastRetry ) )
792 $lastRetry = $hostUnreachableSeen{$hosthash};
795 if( time() < $lastRetry +
796 $Torrus::Collector::SNMP::unreachableRetryDelay )
802 $hostUnreachableRetry{$hosthash} = time();
812 my $collector = shift;
813 my $hosthash = shift;
815 my $cref = $collector->collectorData( 'snmp' );
816 return $unreachableHostDeleted{$hosthash};
820 sub hostReachableAgain
822 my $collector = shift;
823 my $hosthash = shift;
825 my $cref = $collector->collectorData( 'snmp' );
826 if( exists( $hostUnreachableSeen{$hosthash} ) )
828 delete $hostUnreachableSeen{$hosthash};
829 if( defined( $db_failures ) )
831 $db_failures->remove_host($hosthash);
832 $db_failures->set_counter('unreachable',
833 scalar( keys %hostUnreachableSeen));
839 # Callback executed by Collector
843 my $collector = shift;
846 my $tref = $collector->tokenData( $token );
847 my $cref = $collector->collectorData( 'snmp' );
849 my $hosthash = $tref->{'hosthash'};
850 my $oid = $tref->{'oid'};
852 delete $cref->{'targets'}{$hosthash}{$oid}{$token};
853 if( not %{$cref->{'targets'}{$hosthash}{$oid}} )
855 delete $cref->{'targets'}{$hosthash}{$oid};
857 if( not %{$cref->{'targets'}{$hosthash}} )
859 delete $cref->{'targets'}{$hosthash};
863 delete $cref->{'needsRemapping'}{$token};
865 foreach my $maphash ( keys %{$cref->{'mapsRelatedMaps'}{$token}} )
867 delete $cref->{'mapsDependentTokens'}{$maphash}{$token};
869 delete $cref->{'mapsRelatedMaps'}{$token};
872 # Main collector cycle
874 $Torrus::Collector::runCollector{'snmp'} =
875 \&Torrus::Collector::SNMP::runCollector;
879 my $collector = shift;
882 # Info(sprintf('runCollector() Offset: %d, active hosts: %d, maps: %d',
883 # $collector->offset(),
884 # scalar( keys %{$cref->{'activehosts'}} ),
885 # scalar(keys %maps)));
887 # Create one SNMP session per host address.
888 # We assume that version, timeout and retries are the same
891 # We limit the number of sessions per snmp_dispatcher run
892 # because of some strange bugs: with more than 400 sessions per
893 # dispatcher, some requests are not sent out
895 my @hosts = keys %{$cref->{'activehosts'}};
897 while( scalar(@mappingSessions) + scalar(@hosts) > 0 )
900 while( ( scalar(@mappingSessions) + scalar(@batch) <
901 $Torrus::Collector::SNMP::maxSessionsPerDispatcher )
905 push( @batch, pop( @hosts ) );
908 &Torrus::DB::checkInterrupted();
912 foreach my $hosthash ( @batch )
914 my @oids = sort keys %{$cref->{'targets'}{$hosthash}};
916 # Info(sprintf('Host %s: %d OIDs',
920 # Find one representative token for the host
922 if( scalar( @oids ) == 0 )
927 my @reptokens = keys %{$cref->{'targets'}{$hosthash}{$oids[0]}};
928 if( scalar( @reptokens ) == 0 )
932 my $reptoken = $reptokens[0];
935 openNonblockingSession( $collector, $reptoken, $hosthash );
937 &Torrus::DB::checkInterrupted();
939 if( not defined($session) )
945 Debug('Created SNMP session for ' . $hosthash);
946 push( @sessions, $session );
949 my $oids_per_pdu = $cref->{'oids_per_pdu'}{$hosthash};
954 while( scalar( @oids ) > 0 )
956 my $oid = shift @oids;
957 push( @pdu_oids, $oid );
959 if( scalar( @oids ) == 0 or
960 ( scalar( @pdu_oids ) >= $oids_per_pdu ) )
962 if( not $cref->{'nosysuptime'}{$hosthash} )
964 # We insert sysUpTime into every PDU, because
965 # we need it in further processing
966 push( @pdu_oids, $sysUpTime );
969 if( Torrus::Log::isDebug() )
971 Debug('Sending SNMP PDU to ' . $hosthash . ':');
972 foreach my $oid ( @pdu_oids )
978 # Generate the list of tokens that form this PDU
980 foreach my $oid ( @pdu_oids )
982 if( defined( $cref->{'targets'}{$hosthash}{$oid} ) )
985 ( keys %{$cref->{'targets'}{$hosthash}{$oid}} )
987 $pdu_tokens->{$oid}{$token} = 1;
993 get_request( -delay => $delay,
995 [ \&Torrus::Collector::SNMP::callback,
996 $collector, $pdu_tokens, $hosthash ],
997 -varbindlist => \@pdu_oids );
998 if( not defined $result )
1000 Error("Cannot create SNMP request: " .
1009 &Torrus::DB::checkInterrupted();
1013 # Check if there were pending map lookup sessions
1015 if( scalar( @mappingSessions ) > 0 )
1017 @mappingSessions = ();
1018 %mapLookupScheduled = ();
1026 my $session = shift;
1027 my $collector = shift;
1028 my $pdu_tokens = shift;
1029 my $hosthash = shift;
1031 &Torrus::DB::checkInterrupted();
1033 my $cref = $collector->collectorData( 'snmp' );
1035 Debug('SNMP Callback executed for ' . $hosthash);
1037 if( not defined( $session->var_bind_list() ) )
1039 Error('SNMP Error for ' . $hosthash . ': ' . $session->error() .
1040 ' when retrieving ' . join(' ', sort keys %{$pdu_tokens}));
1042 probablyDead( $collector, $hosthash );
1045 delete $maps{$hosthash};
1046 foreach my $oid ( keys %{$pdu_tokens} )
1048 foreach my $token ( keys %{$pdu_tokens->{$oid}} )
1050 $cref->{'needsRemapping'}{$token} = 1;
1057 hostReachableAgain( $collector, $hosthash );
1060 my $timestamp = time();
1062 my $checkUptime = not $cref->{'nosysuptime'}{$hosthash};
1069 my $uptimeTicks = $session->var_bind_list()->{$sysUpTime};
1070 if( defined $uptimeTicks )
1072 $uptime = $uptimeTicks / 100;
1073 Debug('Uptime: ' . $uptime);
1077 Error('Did not receive sysUpTime for ' . $hosthash);
1080 if( $uptime < $collector->period() or
1081 ( defined($cref->{'knownUptime'}{$hosthash})
1083 $uptime + $collector->period() <
1084 $cref->{'knownUptime'}{$hosthash} ) )
1086 # The agent has reloaded. Clean all maps and push UNDEF
1087 # values to the storage
1089 Info('Agent rebooted: ' . $hosthash);
1090 delete $maps{$hosthash};
1092 $timestamp -= $uptime;
1093 foreach my $oid ( keys %{$pdu_tokens} )
1095 foreach my $token ( keys %{$pdu_tokens->{$oid}} )
1097 $collector->setValue( $token, 'U', $timestamp, $uptime );
1098 $cref->{'needsRemapping'}{$token} = 1;
1104 $cref->{'knownUptime'}{$hosthash} = $uptime;
1109 while( my ($oid, $value) = each %{ $session->var_bind_list() } )
1111 # Debug("OID=$oid, VAL=$value");
1112 if( $value eq 'noSuchObject' or
1113 $value eq 'noSuchInstance' or
1114 $value eq 'endOfMibView' )
1116 if( not $cref->{'ignoremiberrors'}{$hosthash}{$oid} )
1118 Error("Error retrieving $oid from $hosthash: $value");
1120 foreach my $token ( keys %{$pdu_tokens->{$oid}} )
1122 if( defined( $db_failures ) )
1124 $db_failures->mib_error
1125 ($hosthash, $collector->path($token));
1128 $collector->deleteTarget($token);
1134 if( $cref->{'64bit_oid'}{$oid} )
1136 $value = Math::BigInt->new($value);
1139 foreach my $token ( keys %{$pdu_tokens->{$oid}} )
1141 $collector->setValue( $token, $value,
1142 $timestamp, $uptime );
1150 # Execute this after the collector has finished
1152 $Torrus::Collector::postProcess{'snmp'} =
1153 \&Torrus::Collector::SNMP::postProcess;
1157 my $collector = shift;
1160 # It could happen that postProcess is called for a collector which
1161 # has no targets, and therefore it's the only place where we can
1162 # initialize these variables
1164 if( not defined( $cref->{'mapsLastExpireChecked'} ) )
1166 $cref->{'mapsLastExpireChecked'} = 0;
1169 if( not defined( $cref->{'mapsRefreshed'} ) )
1171 $cref->{'mapsRefreshed'} = [];
1174 # look if some maps are ready after last expiration check
1175 if( scalar( @{$cref->{'mapsRefreshed'}} ) > 0 )
1177 foreach my $maphash ( @{$cref->{'mapsRefreshed'}} )
1180 ( keys %{$cref->{'mapsDependentTokens'}{$maphash}} )
1182 $cref->{'needsRemapping'}{$token} = 1;
1185 $cref->{'mapsRefreshed'} = [];
1190 if( $cref->{'mapsLastExpireChecked'} + $mapsExpireCheckPeriod <= $now )
1192 $cref->{'mapsLastExpireChecked'} = $now;
1194 # Check the maps expiration and arrange lookup for expired
1196 while( my ( $maphash, $expire ) = each %mapsExpire )
1198 if( $expire <= $now and not $mapLookupScheduled{$maphash} )
1200 &Torrus::DB::checkInterrupted();
1202 my ( $hosthash, $map ) = split( /\#/o, $maphash );
1204 if( $unreachableHostDeleted{$hosthash} )
1206 # This host is no longer polled. Remove the leftovers
1208 delete $mapsExpire{$maphash};
1209 delete $maps{$hosthash};
1213 # Find one representative token for the map
1215 keys %{$cref->{'mapsDependentTokens'}{$maphash}};
1216 if( scalar( @tokens ) == 0 )
1220 my $reptoken = $tokens[0];
1222 # save the map for the time of refresh
1223 $oldMaps{$hosthash}{$map} = $maps{$hosthash}{$map};
1224 delete $maps{$hosthash}{$map};
1226 # this will schedule the map retrieval for the next
1228 Debug('Refreshing map: ' . $maphash);
1230 lookupMap( $collector, $reptoken,
1231 $hosthash, $map, undef );
1233 # After the next collector period, the maps will be
1234 # ready and tokens may be updated without losing the data
1235 push( @{$cref->{'mapsRefreshed'}}, $maphash );
1241 foreach my $token ( keys %{$cref->{'needsRemapping'}} )
1243 &Torrus::DB::checkInterrupted();
1245 delete $cref->{'needsRemapping'}{$token};
1246 if( not Torrus::Collector::SNMP::initTargetAttributes
1247 ( $collector, $token ) )
1249 $collector->deleteTarget($token);
1259 # indent-tabs-mode: nil
1260 # perl-indent-level: 4