Subject: [patch] Feature add - auto load_mibfile & comments functionality

From: Dirk-Willem van Gulik <[email-masked]>
Date: Wed, 25 Aug 2010 10:42:38 +0200

Folks,

A patch which does two closely related things; assuming that net-snmp is installed.

1. 'mibfile auto' magic.

I found the mibfile functionality very useful; but it gets a bit tedious to maintain the mib2schema translation file. Below will autogenerate one (and cache the results) if the filename 'auto' is used.

Not sure if this is the right caching location - and if this is the right semantics w.r.t. to cache purging (is it rebuild always as this always implies a restart/hup of the argusd ?).

This lets you cut&paste straight from the output of an SNMP walk.

2. 'COMMENT' field population.

Secondly - this patch will also fetch the description field from the MIB entry for any OID - and put it in the 'comment' field. Again caching is used.

Feedback appreciated - as I am not sure how this interact with some of the auto-table/index code (which I cannot quite find documented)*.

Thanks,

Dw.

*: in my ideal world; something like a APC-Powerunit or Switch would take the if/Port descriptions from the table power outlet or switchport table; along with things like the speed, packet flows etc - and create things like individual entries and 'stack graphs'.

# this patch is contributed under Argus its Perl Artistic License.
#
diff -c -w -r argus-dev-20100109.org/examples/config-new-features argus-dev-20100109/examples/config-new-features
*** argus-dev-20100109.org/examples/config-new-features	Tue Aug 24 23:37:17 2010
--- argus-dev-20100109/examples/config-new-features	Wed Aug 25 10:12:32 2010
***************
*** 348,350 ****
--- 348,360 ----
  notifyaudit:	auditlog:

+ # Load a MIB2SCHEMA translation file (white space separated OID/human-readable name). Typically
+ # generated with the 'snmptranslate' command form toolkits such at net-snmp.
+ #
+ mibfile: /var/argus/mibs.txt
+ 
+ # The magic filename 'auto' will generate above (and cache such in gcache) using
+ # the 'ALL' mibs known to net-snmp. Requires the latter to be installed.
+ #
+ mibfile: auto
+ 
diff -c -w -r argus-dev-20100109.org/src/Conf.pm argus-dev-20100109/src/Conf.pm
*** argus-dev-20100109.org/src/Conf.pm	Tue Aug 24 23:37:28 2010
--- argus-dev-20100109/src/Conf.pm	Wed Aug 25 10:41:37 2010
***************
*** 84,93 ****
  	},
  
  	mibfile => {
! 	    descr => 'pathname of SNMP MIB translation file (MIB2SCHEMA format)',
  	    attrs => ['config', 'top', 'multi'],
  	    versn => '3.5',
! 	    callback => \&SNMP::load_mibfile,
  	},
  	
  	resolv_timeout => {
--- 84,93 ----
  	},
  
  	mibfile => {
! 	    descr => 'pathname of SNMP MIB translation file (MIB2SCHEMA format). Use "auto" to create one on the fly based on "snmptranslate" its mALL MIB collection. "auto" requires the net snmp package to be installed.',
  	    attrs => ['config', 'top', 'multi'],
  	    versn => '3.5',
! 	    callback => \&Argus::SNMP::load_mibfile,
  	},
  	
  	resolv_timeout => {
diff -c -w -r argus-dev-20100109.org/src/Argus::SNMP.pm argus-dev-20100109/src/Argus::SNMP.pm
*** argus-dev-20100109.org/src/Argus::SNMP.pm	Tue Aug 24 23:37:27 2010
--- argus-dev-20100109/src/Argus::SNMP.pm	Wed Aug 25 09:56:05 2010
***************
*** 19,24 ****
--- 19,26 ----
  use Argus::SNMP::Helper;
  my( $HAVE_MD5, $HAVE_SHA1, $HAVE_HMAC, $HAVE_DES, $HAVE_AES);
  
+ $::path_snmptranslate = 'snmptranslate' unless defined $::path_snmptranslate;
+ 
  BEGIN {
      # these are used for SNMPv3 auth + priv
      eval{ require Digest::MD5;     $HAVE_MD5  = 1; };
***************
*** 332,338 ****
  	$me->helper_init($cf);
      }else{
  	return $cf->error( "invalid OID ($me->{snmp}{oid})" );
!     }
      
      $me;
  }
--- 334,343 ----
  	$me->helper_init($cf);
      } else {
  	return $cf->error( "invalid OID ($me->{snmp}{oid})" );
!     };
! 
!     ($me->{info}) = oid2info($oid)
!         unless defined $me->{info};
  
      $me;
  }
***************
*** 1034,1058 ****
  ################################################################
  # read-config callback
  # load MIB2SCHEMA format file of name to oid translations
  sub load_mibfile {
      my $file = shift;
  
      for my $f (split /\s+/, $file){
  	unless( open(MIB, $f) ){
! 	    ::warning("cannot open mibfile '$file': $!");
  	    next;
  	}
  	
  	while(<MIB>){
  	    chop;
  	    s/\"//g;
! 	    my($name, $oid) = split /\s+/;
  	    $OIDS{$name} = { oid => $oid }; # RSN more...
  	}
  	close MIB;
      }
  }

  ################################################################
  
--- 1039,1133 ----
  ################################################################
  # read-config callback
  # load MIB2SCHEMA format file of name to oid translations
+ # Typically generated with something like
+ #       snmptranslate -mALL -Tz
+ #
  sub load_mibfile {
      my $file = shift;
         
      for my $f (split /\s+/, $file){
+         # If the magic name 'auto' is used - try to create an automatic
+         # mib2schema file using a net-snmp tool. Cache this file if
+         # possible - but regenerate as needed.
+         #
+         if ($f eq 'auto') {
+                 $f = "$::path_snmptranslate -mALL -Tz |";
+                 my $cache = $::datadir.'/gcache/mib2schema.txt';
+                 if ((!-r $cache) && (open MIB, '>'.$cache) && (open TRS, $f)) {
+                         print MIB "# Generated from $f - ".scalar(gmtime(time))."\n";
+                         while(<TRS>) { print MIB; };
+                         close TRS; 
+                         close MIB and $f = $cache;
+                 };
+         };
+ 
  	unless( open(MIB, $f) ){
! 	    ::warning("cannot open mibfile '$f' (from '$file'): $!");
  	    next;
  	}
         
+         my($name, $oid);
  	while(<MIB>) {
  	    chop;
  	    s/\"//g;
!             s/^\s+//g;
!             s/\s+$//g;
!             s/\s+/ /g;
! 	    next unless ($name, $oid) = split /\s+/;
  	    $OIDS{$name} = { oid => $oid }; # RSN more...
  	}
  	close MIB;
      }
  }
  
+ # IF-MIB::ifHCOutOctets
+ # ifHCOutOctets OBJECT-TYPE
+ #   -- FROM       IF-MIB
+ #   SYNTAX        Counter64
+ #   MAX-ACCESS    read-only
+ #   STATUS        current
+ #   DESCRIPTION   "The total number of octets transmitted out of the
+ #             interface, including framing characters.  This object is a
+ #             64-bit version of ifOutOctets.
+ # 
+ #             Discontinuities in the value of this counter can occur at
+ #             re-initialization of the management system, and at other
+ #             times as indicated by the value of
+ #             ifCounterDiscontinuityTime."
+ # ::= { iso(1) org(3) dod(6) internet(1) mgmt(2) mib-2(1) ifMIB(31) ifMIBObjects(1) ifXTable(1) ifXEntry(1) 10 }
+ 
+ my %oid2info = ();
+ sub oid2info {
+         my ($oid) = @_;
+ 
+         return () 
+                 unless $oid =~ m/^[\d\.]+$/;
+ 
+         return @{$oid2info{$oid}}
+                 if defined $oid2info{$oid};
+ 
+         my $cache = $::datadir.'/gcache/'.$oid.'.txt';
+         return (<FH>) 
+                 if (open(FH,$cache));
+ 
+         # Intentionally ignore errors - so we 'cache' these too.
+         #
+         open(FH,"$::path_snmptranslate -mALL -Td $oid|");
+         my $body = join('',<FH>);
+         close(FH);
+ 
+         my $syn = $1 if $body =~ m/SYNTAX\s+(\w+)/s;
+         my $desc = $1 if $body =~ m/\s+DESCRIPTION\s+\"([^"]+)\"/s;
+ 
+         $desc  =~ s/\r?\n\r?\n/<p>/g;
+         $desc  =~ s/\s+/ /g;
+ 
+         # We also try to cache 'non' results
+         if (open(CH,'>'.$cache)) { print CH "$desc\n$syn\n";close(CH); };
+         $oid2info{$oid} = \[$desc,$syn];
+         return ($desc,$syn);
+ };
+ 
  
  ################################################################