#!/usr/bin/perl
# -*- mode: Perl -*-
##################################################################
# Config file creator
##################################################################
# Created by Laurie Gellatly <gellatly@one.net.au>
# based on mrtg cfgmaker by Tobias Oetiker <oetiker@ee.ethz.ch>
# this produces a config file for one router, by pulling info
# off the router via snmp and then writing files ready for
# snmpCollect to use (via xnmcollect) and later ovlg calls
#################################################################
#
# Distributed under the GNU copyleft
#
# $Id: cfgmakerov,v 1.1.1.1 2002/02/26 10:16:36 oetiker Exp $
#
use SNMP_Session "0.58";
use BER "0.57";
use Socket;
use strict;
use vars '$DEBUG';
my $DEBUG = 0;
my $webdir = "/var/opt/ns-fasttrack/docs/mrtg/";

%snmpget::OIDS = (  'sysDescr' => '1.3.6.1.2.1.1.1.0',
		    'sysContact' => '1.3.6.1.2.1.1.4.0',
		    'sysName' => '1.3.6.1.2.1.1.5.0',
		    'sysLocation' => '1.3.6.1.2.1.1.6.0',
		    'sysUptime' => '1.3.6.1.2.1.1.3.0',
		    'ifNumber' =>  '1.3.6.1.2.1.2.1.0',
		    ###################################
		    # add the ifNumber ....
		    'ifDescr' => '1.3.6.1.2.1.2.2.1.2',
		    'ifType' => '1.3.6.1.2.1.2.2.1.3',
		    'ifIndex' => '1.3.6.1.2.1.2.2.1.1',
		    'ifSpeed' => '1.3.6.1.2.1.2.2.1.5', 
		    'ifOperStatus' => '1.3.6.1.2.1.2.2.1.8',             
		    'ifAdminStatus' => '1.3.6.1.2.1.2.2.1.7',            
		    # up 1, down 2, testing 3
		    'ipAdEntAddr' => '1.3.6.1.2.1.4.20.1.1',
		    'ipAdEntIfIndex' => '1.3.6.1.2.1.4.20.1.2',
		    'sysObjectID' => '1.3.6.1.2.1.1.2.0',
		    'CiscolocIfDescr' => '1.3.6.1.4.1.9.2.2.1.1.28',
		    'ifAlias' => '1.3.6.1.2.1.31.1.1.1.18',
		    'ifName' => '1.3.6.1.2.1.31.1.1.1.1'
		 );

sub main {

  my(%ifType_d)=('1'=>'Other',
		 '2'=>'regular1822',
		 '3'=>'hdh1822',
		 '4'=>'ddnX25',
		 '5'=>'rfc877x25',
		 '6'=>'ethernetCsmacd',
		 '7'=>'iso88023Csmacd',
		 '8'=>'iso88024TokenBus',
		 '9'=>'iso88025TokenRing',
		 '10'=>'iso88026Man',
		 '11'=>'starLan',
		 '12'=>'proteon10Mbit',
		 '13'=>'proteon80Mbit',
		 '14'=>'hyperchannel',
		 '15'=>'fddi',
		 '16'=>'lapb',
		 '17'=>'sdlc',
		 '18'=>'ds1',
		 '19'=>'e1',
		 '20'=>'basicISDN',
		 '21'=>'primaryISDN',
		 '22'=>'propPointToPointSerial',
		 '23'=>'ppp',
		 '24'=>'softwareLoopback',
		 '25'=>'eon',
		 '26'=>'ethernet-3Mbit',
		 '27'=>'nsip',
		 '28'=>'slip',
		 '29'=>'ultra',
		 '30'=>'ds3',
		 '31'=>'sip',
		 '32'=>'frame-relay',
		 '33'=>'rs232',
		 '34'=>'para',
		 '35'=>'arcnet',
		 '36'=>'arcnetPlus',
		 '37'=>'atm',
		 '38'=>'miox25',
		 '39'=>'sonet',
		 '40'=>'x25ple',
		 '41'=>'iso88022llc',
		 '42'=>'localTalk',
		 '43'=>'smdsDxi',
		 '44'=>'frameRelayService',
		 '45'=>'v35',
		 '46'=>'hssi',
		 '47'=>'hippi',
		 '48'=>'modem',
		 '49'=>'aal5',
		 '50'=>'sonetPath',
		 '51'=>'sonetVT',
		 '52'=>'smdsIcip',
		 '53'=>'propVirtual',
		 '54'=>'propMultiplexor',
		 '55'=>'100BaseVG'
		 );

  my($vendor)=0;

  my($router) = $ARGV[0];
  die <<USAGE  unless $router;

USAGE: cfgmakerov  'router'

EXAMPLE:  cfgmakerov ezwf7.ethz.ch >>mrtg.cfg

USAGE

  my($sysDescr,$sysContact,$sysName,$sysLocation,$ifNumber,$sysObjectID) =
    snmpget($router,
	    'sysDescr','sysContact','sysName',  'sysLocation', 'ifNumber', 'sysObjectID');

 ### The next three lines can be deleted once Someone gives this box a name  
   if ($router eq '10.26.254.1') {
      $sysName = 'nrgiga';
   }
   if ($sysName eq "") {
      $sysName = $router;
   }
   my($sysNameL) = $sysName;
   $sysNameL =~ tr/[A-Z]/[a-z]/;

   $sysDescr =~ s/\r/
/g;  # Change returns to 
   my($ciscobox) = ($sysObjectID =~ /cisco/);
   my($portmaster) = ($sysObjectID =~ /livingston/);
   $vendor = ($ciscobox || $portmaster) ;
   my($ifInErrors) = '1.3.6.1.2.1.2.2.1.14';
   my($ifOutErrors) = '1.3.6.1.2.1.2.2.1.20';

### Create the directory if it does not exist

   mkdir("$webdir$sysNameL",0777);
   
print <<ECHO;

WorkDir: $webdir$sysNameL
IconDir: ../
######################################################################
# Description: $sysDescr
#     Contact: $sysContact
# System Name: $sysName
#    Location: $sysLocation
#.....................................................................
ECHO
if ( $ciscobox ) {
   print <<ECHO;
# Router CPU load %
Target[$sysNameL.cpu]: `perl ovcvtfile $router 0 2` 
MaxBytes[$sysNameL.cpu]: 100
Title[$sysNameL.cpu]: CPU LOAD
PageTop[$sysNameL.cpu]: 
CPU Load %
ShortLegend[$sysNameL.cpu]: %
XSize[$sysNameL.cpu]: 380
YSize[$sysNameL.cpu]: 100
YLegend[$sysNameL.cpu]: CPU Utilization
Legend1[$sysNameL.cpu]: CPU Utilization in % (Load)
Legend2[$sysNameL.cpu]: CPU Utilization in % (Load)
Legend3[$sysNameL.cpu]:
Legend4[$sysNameL.cpu]:
LegendI[$sysNameL.cpu]:
LegendO[$sysNameL.cpu]:  Usage:
Options[$sysNameL.cpu]: growright, gauge
#---------------------------------------------------------------
ECHO
}

  my @ipadent = snmpgettable($router, 'ipAdEntAddr');
  print STDERR "Got Addresses\n" if $DEBUG;
  my @ipadentif = snmpgettable($router, 'ipAdEntIfIndex');
  print STDERR "Got IfTable\n" if $DEBUG;

  my(%ipaddr, %iphost,$index);
  while (scalar @ipadentif){
    $index = shift @ipadentif;
    $ipaddr{$index} = shift @ipadent;
    $iphost{$index} = 
      gethostbyaddr(pack('C4',split(/\./,$ipaddr{$index})), AF_INET);
    if ($iphost{$index} eq ''){
	 $iphost{$index} = $ipaddr{$index};
    }   
    
  }

  my(@ifdescr) = snmpgettable($router, 'ifDescr');
  print STDERR "Got IfDescr\n" if $DEBUG;
  my(@iftype) = snmpgettable($router, 'ifType');
  print STDERR "Got IfType\n" if $DEBUG;
  my(@ifspeed) = snmpgettable($router, 'ifSpeed');
  print STDERR "Got IfSpeed\n" if $DEBUG;
  my(@ifadminstatus) = snmpgettable($router, 'ifAdminStatus');
  print STDERR "Got IfStatus\n" if $DEBUG;
  my(@ifoperstatus) = snmpgettable($router, 'ifOperStatus');
  print STDERR "Got IfOperStatus\n" if $DEBUG;
  my(@ifindex) = snmpgettable($router, 'ifIndex');
  print STDERR "Got IfIndex\n" if $DEBUG;
  my(@ifname) = snmpgettable($router, 'ifName');
  print STDERR "Got IfName\n" if $DEBUG;

  my(%sifdesc,%siftype,%sifspeed,%sifadminstatus,%sifoperstatus,%sciscodescr,%sifname);

  ### May need the cisco IOS version number so we know which oid to use
  ###   to get the cisco description.
  ###
  ### - mjd 2/5/98 (Mike Diehn) (mdiehn@mindspring.net)
  ###
  my ($cisco_ver, $cisco_descr_oid, @ciscodescr);
  if ( $ciscobox ) {
    ($cisco_ver) = ($sysDescr =~ /Version\s+([\d.]+)/);
    $cisco_descr_oid = ($cisco_ver ge "11.3") ? "ifAlias" : "CiscolocIfDescr";
  }
  
  while (scalar @ifindex) {

  # as these arrays get filled from the bottom, 
  # we need to empty them from the botom as well ...
  # fifo

    $index = shift @ifindex;
    $sifdesc{$index} = shift @ifdescr;
    $sifname{$index} = shift @ifname;
    $siftype{$index} = shift @iftype;
    $sifspeed{$index} = shift @ifspeed;
    $sifadminstatus{$index} = shift @ifadminstatus;
    $sifoperstatus{$index} = shift @ifoperstatus;

    if ($portmaster) {
      # Trying to extract extra info livingston
      # We can only approximate speeds
      # 
      # so we think that ppp can do 76800 bit/s, and slip 38400.
      # (actualy, slip is a bit faster, but usualy users with newer modems
      # use ppp). Alternatively, you can set async speed to 115200 or
      # 230400 (the maximum speed supported by portmaster).
      # 
      # But if the interface is ptpW (sync), max speed is 128000
      # change it to your needs. On various Portmasters there are
      # various numbers of sync interfaces, so modify it.
      # 
      #  The most commonly used PM-2ER has only one sync.
      # 
      #  Paul Makeev (mac@redline.ru)
      # 

      if ($siftype{$index} eq 'ppp') {
	      if ($sifdesc{$index} eq 'ptpW1') {
		      $sifspeed{$index} = 128000;
	      } else {
		      $sifspeed{$index} = 76800;
	      }
      } elsif ($siftype{$index} eq 'slip') {
	      $sifspeed{$index} = 38400;
      } elsif ($siftype{$index} eq 'ethernetCsmacd') {
	      $sifspeed{$index} = 10000000;
      }
    }

    ### Move this section south so we know what type of
    ###  circuit we're looking at before we retrieve
    ###  the cisco interface alias.
    ###
    ### This whole cicso thing should be re-written, but since
    ###   this script doesn't need to run quickly...
    ###
    ###  - mjd 2/5/98
    ###
    # Get the user configurable interface description entered in the config 
    # if it's a cisco-box
    #
    if ($ciscobox) {

	my ($enoid, @descr);

	$enoid = $snmpget::OIDS{"$cisco_descr_oid"} . "." . $index;

	if ( $cisco_ver ge "11.2" or $siftype{$index} ne 'frame-relay' ) {

	  ### This is either not a frame-relay sub-interface or
	  ###  this router is running IOS 11.2+ and interface
	  ###  type won't matter. In either of these cases, it's
	  ###  ok to try getting the ifAlias or ciscoLocIfDesc.
	  ###
	  @descr = snmpget($router, $enoid);

	} else {

	  ### This is a frame-relay sub-interface *and* the router
	  ###  is running an IOS older than 11.2. Therefore, we can
	  ###  get neither ifAlias nor ciscoLocIfDesc. Do something
	  ###  useful.
	  ###
	  @descr = ("Cisco PVCs descriptions require IOS 11.2+.");

	} # end if else

	### Put whatever I got into the array we'll use later to append the result
	###   of this operation onto the results from the ifDescr fetch.
	###
	push @ciscodescr, shift @descr;

    } # end if ($ciscobox)

    # especially since cisco does not return a if
    # descr for each interface it has ...
    ## JB 2/8/97 - sometimes IOS inserts E1 controllers in the standard-MIB
    ## interface table, but not in the local interface table. This puts the
    ## local interface description table out-of-sync. the following 
    ## modification skips over E1 cards as interfaces.
    #
    ### I suspect that the mod I made above, to use the ifAlias
    ###   oid if possible, may cause problems here. If it seems
    ###   that your descriptions are out of sync, try commenting
    ###   out the "if ( condition )" and it's closing right brace
    ###   so that the "shift @ciscodescr" get executed for *all*
    ###   iterations of this loop.
    ###
    ### - mjd 2/5/95
    ###
    if ($ciscobox && $siftype{$index} ne 'ds1') {
	  $sciscodescr{$index} = "<BR>" . (shift @ciscodescr) if @ciscodescr;
    }
}

  foreach $index ( sort { $a <=> $b } keys %sifdesc) {
    my $c;
    my $speed = int($sifspeed{$index} / 8); # bits to byte
# LJG Change to report in Bits
#    my $speed_str=&fmi($speed);
    my $speed_str=&fmi($sifspeed{$index});
    my $name="$sysNameL.$index";
    my $namerr="$sysNameL.$index.err";

  if (($sifadminstatus{$index} ne "up")
# this check added by Josh - don't query E1-stack controllers
      || ($siftype{$index} eq 'ds1')
	|| ($siftype{$index} eq 'softwareLoopback')
	|| ($speed == 0 ) 
# LJG Change to report all in Bits
#	|| ($speed > 400 * 10**6)  #speeds of 400 MByte/s are not realistic
	|| ($speed > 3200 * 10**6)  #speeds of 400 MByte/s are not realistic
	|| ($sifoperstatus{$index} eq 'down')
	|| (($sifdesc{$index}=~ /Dialer/) && ($ciscobox))) {
    print <<ECHO;
########
######## This Interface is one of the following
######## - administratively not UP
######## - it is in test mode
######## - it is a softwareLoopback interface
######## - has a unrealistic speed setting
######## It is commented out for this reason.
########
ECHO
  $c="# ";
  }else {
    $c = '';
  }
    
  print <<ECHO;
${c}
${c}Target[$name]: `perl ovcvtfile $router $index 1`
${c}MaxBytes[$name]: $speed
${c}Title[$name]: $sysName ($iphost{$index}): $sifdesc{$index} $sifname{$index}
${c}Options[$name]: growright, gauge, bits
${c}PageTop[$name]: 
Traffic Analysis for $sifdesc{$index}
${c} $sciscodescr{$index}
${c} 
${c}    System: $sysName in $sysLocation
${c}    Maintainer: $sysContact
${c}    Interface: $sifdesc{$index} ($index - $sifname{$index})
${c}    IP: $iphost{$index} ($ipaddr{$index})
${c}    Max Speed:
${c}        $speed_str ($siftype{$index})
${c}  
${c}
#---------------------------------------------------------------

# In and Out Error Counts
${c}
${c}Target[$namerr]: `perl ovcvtfile $router $index 0`
${c}MaxBytes[$namerr]: 2147483600
${c}Title[$namerr]: $sysName ($iphost{$index}): $sifdesc{$index} $sifname{$index} I/O Errors
${c}Options[$namerr]: growright, gauge
${c}PageTop[$namerr]: 
I/O Error Analysis for $sifdesc{$index}
${c} $sciscodescr{$index}
${c}YLegend[$namerr]: Errors/Period
${c}Legend1[$namerr]: Inward Errors
${c}Legend2[$namerr]: Outward Errors
${c}Legend3[$namerr]: 
${c}Legend4[$namerr]: 
${c}LegendI[$namerr]:  In :
${c}LegendO[$namerr]:  Out :
${c}
#---------------------------------------------------------------

ECHO
  }
}
  
main;
exit(0);

sub snmpget{  
  my($host,@vars) = @_;
  my(@enoid, $var,$response, $bindings, $binding, $value, $inoid,$outoid,
     $upoid,$oid,@retvals,$t1,$t2,@resp,$tempo);
  my($hackcisco);
  foreach $var (@vars) {
    die "Unknown SNMP var $var\n" 
      unless $snmpget::OIDS{$var} || $var =~ /^\d+[\.\d+]*\.\d+$/;
    if ($var =~ /^\d+[\.\d+]*\.\d+/) {
	$value = $value.$var." ";
	$hackcisco = 1;
    } else {
	$value = $value.$snmpget::OIDS{$var}." ";
	$hackcisco = 0;
    }
  }
  open(SNMPG, "snmpget $host $value |");
#  print STDERR $value;
  while ($tempo =<SNMPG>){
#      print STDERR $tempo;
      ($t1, $t2, $tempo ) = split /:/ , $tempo, 3;
      if (!$tempo){
	 if ($t2){
	    $t1 = $t1 .":".$t2;
	 }
	 $tempo = pop(@retvals)." ".$t1 ;
      }
      $tempo=~s/\t/ /g;
      $tempo=~s/\n/ /g;
      $tempo=~s/^\s+//;
      $tempo=~s/\s+$//;
      push @retvals,  $tempo;
  }
#   print STDERR @retvals; 
  close (SNMPG);    
    return (@retvals);
}

sub snmpgettable{
  my($host,$var) = @_;
  my($next_oid,$enoid,$orig_oid, 
     $response, $bindings, $binding, $t1, $t2,$outoid,
     $upoid,$oid,@table,$tempo);
  die "Unknown SNMP var $var\n" 
    unless $snmpget::OIDS{$var};
  
  $orig_oid = $snmpget::OIDS{$var}." ";
  $enoid=$orig_oid;
  open(SNMPG, "snmpwalk $host $orig_oid |");
#  print STDERR $orig_oid;
  while ($tempo =<SNMPG>){
#      print STDERR $tempo;
      ($t1, $t2, $tempo ) = split /:/ , $tempo ,3;
      if (!$tempo){
	 if ($t2){
	    $t1 = $t1 .":".$t2;
	 }
	 $tempo = pop(@table)." ".$t1 ;
      }
      $tempo=~s/\t/ /g;
      $tempo=~s/\n/ /g;
      $tempo=~s/^\s+//;
      $tempo=~s/\s+$//;
      push @table, $tempo;
     
  }
 close (SNMPG);    
  return (@table);
}

sub fmi {
  my($number) = $_[0];
  my(@short);
# LJG Change to report in Bits
#  @short = ("Bytes/s","kBytes/s","MBytes/s","GBytes/s");
  @short = ("Bits/s","kBits/s","MBits/s","GBits/s");
  my $digits=length("".$number);
  my $divm=0;
  while ($digits-$divm*3 > 3) { $divm++; }
  my $divnum = $number/10**($divm*3);
  return sprintf("%1.1f %s",$divnum,$short[$divm]);
}

