Blob Blame History Raw
#! /usr/bin/perl
# -*- mode: Perl -*-
##################################################################
# New MRTG 2.8.12 Based -- Config file creator
##################################################################
# this produces a config file for one router, by pulling info
# off the router via snmp
# Modified by Graziano Sommariva <Graziano.Sommariva@elsag.it>
# to monitor DLCI's and to include some code from newer release(2.9.12).
# NOTE: IPONLY has been disabled.
#       Added --ip option
#################################################################
#
# Distributed under the GNU copyleft

require 5.004;
use strict;

BEGIN {
    # Automatic OS detection ... do NOT touch
    if ( $^O =~ /^(?:(ms)?(dos|win(32|nt)?))/i ) {
        $main::OS = 'NT';
        $main::SL = '\\';
        $main::PS = ';';
    } elsif ( $^O =~ /^VMS$/i ) {
        $main::OS = 'VMS';
        $main::SL = '.';
        $main::PS = ':';
    } else {
        $main::OS = 'UNIX';
        $main::SL = '/';
        $main::PS = ':';
    }
}

use FindBin;
use lib "${FindBin::Bin}";
use lib "${FindBin::Bin}${main::SL}..${main::SL}lib${main::SL}mrtg2";

use BER "0.57";
use SNMP_Session "0.59";
use SNMP_util "0.57";

use Getopt::Long;
use Socket;
use strict;
use vars '$DEBUG';
my $DEBUG = 0;

my (%optctl) = ();
my ($session, %ipaddr, %iphost);

sub main {

    snmpmapOID('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');

  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',
             '56'=>'Fibre Channel',
             '57'=>'HIPPI Interface',
             '58'=>'Obsolete for FrameRelay',
             '59'=>'ATM Emulation of 802.3 LAN',
             '60'=>'ATM Emulation of 802.5 LAN',
             '61'=>'ATM Emulation of a Circuit',
             '62'=>'FastEthernet (100BaseT)',
             '63'=>'ISDN & X.25',
             '64'=>'CCITT V.11/X.21',
             '65'=>'CCITT V.36',
             '66'=>'CCITT G703 at 64Kbps',
             '67'=>'Obsolete G702 see DS1-MIB',
             '68'=>'SNA QLLC',
             '69'=>'Full Duplex Fast Ethernet (100BaseFX)',
             '70'=>'Channel',
             '71'=>'Radio Spread Spectrum (802.11)',
                 '72'=>'IBM System 360/370 OEMI Channel',
                 '73'=>'IBM Enterprise Systems Connection',
                 '74'=>'Data Link Switching',
                 '75'=>'ISDN S/T Interface',
                 '76'=>'ISDN U Interface',
                 '77'=>'Link Access Protocol D (LAPD)',
                 '78'=>'IP Switching Opjects',
                 '79'=>'Remote Source Route Bridging',
                 '80'=>'ATM Logical Port',
                 '81'=>'AT&T DS0 Point (64 Kbps)',
                 '82'=>'AT&T Group of DS0 on a single DS1',
                 '83'=>'BiSync Protocol (BSC)',
                 '84'=>'Asynchronous Protocol',
                 '85'=>'Combat Net Radio',
                 '86'=>'ISO 802.5r DTR',
                 '87'=>'Ext Pos Loc Report Sys',
                 '88'=>'Apple Talk Remote Access Protocol',
                 '89'=>'Proprietary Connectionless Protocol',
                 '90'=>'CCITT-ITU X.29 PAD Protocol',
                 '91'=>'CCITT-ITU X.3 PAD Facility',
                 '92'=>'MultiProtocol Connection over Frame/Relay',
                 '93'=>'CCITT-ITU X213',
                 '94'=>'Asymetric Digitial Subscriber Loop (ADSL)',
                 '95'=>'Rate-Adapt Digital Subscriber Loop (RDSL)',
                 '96'=>'Symetric Digitial Subscriber Loop (SDSL)',
                 '97'=>'Very High Speed Digitial Subscriber Loop (HDSL)',
                 '98'=>'ISO 802.5 CRFP',
                 '99'=>'Myricom Myrinet',
                 '100'=>'Voice recEive and transMit (voiceEM)',
                 '101'=>'Voice Foreign eXchange Office (voiceFXO)',
                 '102'=>'Voice Foreign eXchange Station (voiceFXS)',
                 '103'=>'Voice Encapulation',
                 '104'=>'Voice Over IP Encapulation',
                 '105'=>'ATM DXI',
                 '106'=>'ATM FUNI',
                 '107'=>'ATM IMA',
                 '108'=>'PPP Multilink Bundle',
                 '109'=>'IBM IP over CDLC',
                 '110'=>'IBM Common Link Access to Workstation',
                 '111'=>'IBM Stack to Stack',
                 '112'=>'IBM Virtual IP Address (VIPA)',
                 '113'=>'IBM Multi-Protocol Channel Support',
                 '114'=>'IBM IP over ATM',
                 '115'=>'ISO 802.5j Fiber Token Ring',
                 '116'=>'IBM Twinaxial Data Link Control (TDLC)',
                 '117'=>'Gigabit Ethernet',
                 '118'=>'Higher Data Link Control (HDLC)',
                 '119'=>'Link Access Protocol F (LAPF)',
                 '120'=>'CCITT V.37',
                 '121'=>'CCITT X.25 Multi-Link Protocol',
                 '122'=>'CCITT X.25 Hunt Group',
                 '123'=>'Transp HDLC',
                 '124'=>'Interleave Channel',
                 '125'=>'Fast Channel',
                 '126'=>'IP (for APPN HPR in IP Networks)',
                 '127'=>'CATV MAC Layer',
                 '128'=>'CATV Downstream Interface',
                 '129'=>'CATV Upstream Interface',
                 '130'=>'Avalon Parallel Processor',
                 '131'=>'Encapsulation Interface',
                 '132'=>'Coffee Pot',
                 '133'=>'Circuit Emulation Service',
                 '134'=>'ATM Sub Interface',
                 '135'=>'Layer 2 Virtual LAN using 802.1Q',
                 '136'=>'Layer 3 Virtual LAN using IP',
                 '137'=>'Layer 3 Virtual LAN using IPX',
                 '138'=>'IP Over Power Lines',
                 '139'=>'Multi-Media Mail over IP',
                 '140'=>'Dynamic synchronous Transfer Mode (DTM)',
                 '141'=>'Data Communications Network',
                 '142'=>'IP Forwarding Interface',
                 '162'=>'Cisco Express Forwarding Interface'
                 );

  my($vendor)=0;
#  my($iponly)=0;
  my($workdir)=0;
  my($ip)=0;
  my($community,$router,%defaults);
  my($res);

  # Just need to make sure that all perl installations have the GetOpt module
  #   - fwo@obsidian.co.za
  #
#  $res = GetOptions(\%optctl,"vendor","iponly","workdir=s","options=s","ip=s");
  $res = GetOptions(\%optctl,"vendor","workdir=s","options=s","ip=s");
  if($res == 0 ) {
      print "\nError in arguments. Please run cfgmaker with no arguments for help!\n\n";
      exit 1;
  }

  if($optctl{"vendor"})   { $vendor = 1; }
#  if($optctl{"iponly"})   { $iponly = 1; }
  if($optctl{"workdir"})  { $workdir = $optctl{"workdir"}; }
  if($optctl{"ip"})  { $ip = $optctl{"ip"}; }
  if($optctl{"options"}) { 
      foreach $res(split(',',$optctl{"options"})) {
	  chomp($res);
	  next if($res eq "growright");
	  next if($res eq "bits");
	  next if($res eq "perminute");
	  next if($res eq "perhour");
	  next if($res eq "noinfo");
	  next if($res eq "nopercent");
	  next if($res eq "transparent");
	  next if($res eq "integer");
	  next if($res eq "dorelpercent");
	  next if($res eq "gauge");
	  next if($res eq "absolute");
	  next if($res eq "unknaszero");
	  print "\nERROR:$res is not a valid option for --options, exiting!\n";
	  exit 1;
      }
  }
  $res = 0;
#TODO: check for conflicting info in options - l->r and r->l
#  print STDERR "iponly=$iponly\n" if $DEBUG;
  print STDERR "vendor=$vendor\n" if $DEBUG;
  print STDERR "workdir=$workdir\n" if $DEBUG;

  ($community,$router) = ($1,$2) if $ARGV[0] =~ /(.*)\@(.*)/;
  if(!($community) && !($router)) {
  print <<USAGE;

USAGE: cfgmaker [--vendor] [other options] 'community'\@'router'

use the --vendor option to try and wrestle some better information
    from willing livingston and cisco routers ... (may not work)

[other options] can be one of the following:

#use the --iponly option to force the targets to the ip adress of the router 
#    being queried. Also note that the 'router' option must be the ip address
#    and not the symbolic name.

use the --workdir '/some/path' option to add the WorkDir option to the cfg file 
    being generated.

use the --ip 'IP Address' to use in SNMP requests 

use the --options 'defaults' to set default options for each target. defaults 
    is a comma seperated list and can contain the following :
        growright bits perminute perhour noinfo nopercent transparent
	integer dorelpercent gauge absolute unknaszero

    See the mrtg.cfg doccumentation for descriptions of the above options.
    NOTE: no checking for conflicting options are done at the moment.

EXAMPLE:  cfgmaker public\@ezwf7.ethz.ch >>mrtg.cfg

USAGE
    exit 1;
  }
#  if($iponly) { 
#      # We only want to work with ip numbers and not names
#      # Check to see whether the name is a valid ip address
#      # If not bail - we do not want to deal with reverse dns
#      #    issues - fwo@obsidian.co.za 2000/01/17
#      chomp($router);
#      if(!($router =~ /^[0-9]{1,3}.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/)){
#	  print "\nERROR: when specifying --iponly, please use a valid\n";
#	  print "ip address for the router. Do not use a symbolic name.\n\n";
#	  exit 1;
#      }
#  }
    print "IconDir: /mrtgicons/\n\n";
  if($workdir) {
  	print "WorkDir: $workdir\n\n";
  } else {
  	print "# Add a WorkDir: /html line to this file\n\n";
  }

  my($sysDescr,$sysContact,$sysName,$sysLocation,$ifNumber,$sysObjectID);
  my($sysDescr_orig,$cisco_router_sysid,$livingston_router_sysid,$ciscobox,$portmaster);

  if($optctl{"ip"}) {
     $session = SNMP_Session->open ($ip, $community, 161)
	|| die "Error opening SNMP session to $ip";

     ($sysDescr,$sysContact,$sysName,$sysLocation,$ifNumber,$sysObjectID) = snmpget("$community\@$ip",'sysDescr','sysContact','sysName','sysLocation','ifNumber', 'sysObjectID');

     $sysDescr_orig=$sysDescr;
     $sysDescr_orig =~ s/[\r\n ]+/ /g;
     $sysDescr =~ s/[\r\n]+/<BR>/g;  # Change returns to <BR>
     $cisco_router_sysid = '1\.3\.6\.1\.4\.1\.9';
     $livingston_router_sysid = '1\.3\.6\.1\.4\.1\.307';
     $ciscobox = ($sysObjectID =~ /^$cisco_router_sysid/);
     $portmaster = ($sysObjectID =~ /^$livingston_router_sysid/);
  } else { 
     $session = SNMP_Session->open ($router, $community, 161)
	|| die "Error opening SNMP session to $router";
     ($sysDescr,$sysContact,$sysName,$sysLocation,$ifNumber,$sysObjectID) = snmpget("$community\@$router",'sysDescr','sysContact','sysName','sysLocation','ifNumber', 'sysObjectID');
     $sysDescr_orig=$sysDescr;
     $sysDescr_orig =~ s/[\r\n ]+/ /g;
     $sysDescr =~ s/[\r\n]+/<BR>/g;  # Change returns to <BR>
     $cisco_router_sysid = '1\.3\.6\.1\.4\.1\.9';
     $livingston_router_sysid = '1\.3\.6\.1\.4\.1\.307';
     $ciscobox = ($sysObjectID =~ /^$cisco_router_sysid/);
     $portmaster = ($sysObjectID =~ /^$livingston_router_sysid/);
  } 
  print <<ECHO;


######################################################################
# Description: $sysDescr_orig
#     Contact: $sysContact
# System Name: $sysName
#    Location: $sysLocation
#.....................................................................
ECHO

  $session->map_table ([[1,3,6,1,2,1,4,20,1,1],	# ipAdEntAddr
			[1,3,6,1,2,1,4,20,1,2]], # ipAdEntIf
		       sub ($@) {
			   my ($index, $ipadentaddr, $ipadentif) = @_;
			   grep (defined $_ && ($_=pretty_print $_),
				 ($ipadentif, $ipadentaddr));
			   $ipaddr{$ipadentif} = $ipadentaddr;
			   $iphost{$ipadentif} = 
			       gethostbyaddr(pack('C4',split(/\./,$ipaddr{$ipadentif})), AF_INET);
			   if (!defined $iphost{$ipadentif} || ($iphost{$ipadentif} eq '')){
			       $iphost{$ipadentif} = 'No hostname defined for IP address';
			   }
		       });

  print STDERR "Got Addresses\n" if $DEBUG;
  print STDERR "Got IfTable\n" if $DEBUG;

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

  ### 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 =~ m/Version\s+([\d\.]+)\(\d/o);
    $cisco_descr_oid = ($cisco_ver ge "11.2") ? "ifAlias" : "CiscolocIfDescr";
  }

$session->map_table ([[1,3,6,1,2,1,2,2,1,1], # ifIndex
		      [1,3,6,1,2,1,2,2,1,2], # ifDescr
		      [1,3,6,1,2,1,2,2,1,3], # ifType
		      [1,3,6,1,2,1,2,2,1,5], # ifSpeed
		      [1,3,6,1,2,1,2,2,1,7], # ifAdminStatus
		      [1,3,6,1,2,1,2,2,1,8]], # ifOperStatus
sub ($@) {
    my ($rowindex,$index,$ifdescr,$iftype,$ifspeed,$ifadminstatus,$ifoperstatus) = @_;
    grep (defined $_ && ($_=pretty_print $_),
	  ($index,$ifdescr,$iftype,$ifspeed,$ifadminstatus,$ifoperstatus));
    $sifdesc{$index} = $ifdescr;
    $siftype{$index} = $iftype;
    $sifspeed{$index} = $ifspeed;
    $sifadminstatus{$index} = $ifadminstatus;
    $sifoperstatus{$index} = $ifoperstatus;
    if ($portmaster && $vendor) {
      
      # 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 '23') {
              if ($sifdesc{$index} eq 'ptpW1') {
                      $sifspeed{$index} = 128000;
              } else {
                      $sifspeed{$index} = 76800;
              }
      } elsif ($siftype{$index} eq '28') {
              $sifspeed{$index} = 38400;
      } elsif ($siftype{$index} eq '6') {
              $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
    #
    my($cisco_descr_oid);
    if ($ciscobox && $vendor) {

	my ($enoid, @descr);

	$enoid = $cisco_descr_oid . "." . $index;

	if ( $cisco_ver ge "11.2" or $siftype{$index} != '32' ) {

	  ### 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("$community\@$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 ($cisco_box && $vendor)

    # 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} != 18) {
          $sciscodescr{$index} = "<BR>" . (shift @ciscodescr) if @ciscodescr;
    }
});
  my $index;
  foreach $index ( sort { $a <=> $b } keys %sifdesc) {
    my $c;
    my $speed = int($sifspeed{$index} / 8); # bits to byte
    my $speed_str=&fmi($speed);
    my $name="$iphost{$index}";

#    $name = "$router.int.$index" if not $name or $name =~ /\s/ or $iponly;
    $name = "$router.int.$index";

  my $err_msg;
    
  $err_msg .= "######## - administratively not UP\n" if ($sifadminstatus{$index} != 1);
# this check added by Josh - don't query E1-stack controllers
  $err_msg .= "######## - DS1 type\n" 
	  if ($siftype{$index} == 18);
# i might be mistaken on this one - fwo@obsidian.co.za
  $err_msg .= "######## - E1 type\n" 
	  if ($siftype{$index} == 19);
  $err_msg .= "######## - it is a softwareLoopback interface\n" 
	  if ($siftype{$index} == 24);
  $err_msg .= "######## - it is a a DS3 contorller\n" 
	  if ($siftype{$index} == 30);
  $err_msg .= "######## - it is a ISDN S/T Interface\n" 
	  if ($siftype{$index} == 75);
  $err_msg .= "######## - it is a AT&T DS0 Point (64 Kbps)\n" 
	  if ($siftype{$index} == 81);
  $err_msg .= "######## - it is a CEF Sub-interface\n" 
	  if ($siftype{$index} == 162);
  $err_msg .= "######## - has an unrealistic speed setting\n" 
	  if (($speed == 0 ) || ($speed > 400 * 10**6));  
  $err_msg .= "######## - administratively not UP\n" 
	  if ($sifoperstatus{$index} == 3) ;
  if($err_msg ne "") {
    print <<ECHO;
########
######## This Interface not configured :
$err_msg######## It is commented out for this reason.
########
ECHO
    $c="# ";
  }else {
    $c = '';
  }
    
  print <<ECHO;
${c}
ECHO
if($optctl{"ip"}) {
  print "${c}Target[$name]: $index:$community\@$ip\n";
} else {
  print "${c}Target[$name]: $index:$community\@$router\n";
}
print <<ECHO;
#${c}MaxBytes[$name]: $speed
${c}MaxBytes[$name]: 1250000
${c}YSize[$name]: 300
${c}XSize[$name]: 600
${c}Suppress[$name]: y
${c}Title[$name]: $sysName ($iphost{$index}): $sifdesc{$index}
${c}Options[$name]: bits, growright, nopercent
ECHO
#if($optctl{"options"}) {
#    print "${c}Options[$name]: $optctl{'options'}\n";
#}
print <<ECHO;
${c}PageTop[$name]: <H1>Traffic Analysis for $sifdesc{$index}
${c} $sciscodescr{$index}</H1>
${c} <TABLE>
${c}   <TR><TD>System:</TD><TD>$sysName in $sysLocation</TD></TR>
${c}   <TR><TD>Maintainer:</TD><TD>$sysContact</TD></TR>
${c}   <TR><TD>Interface:</TD><TD>$sifdesc{$index} ($index)</TD></TR>
${c}   <TR><TD>IP:</TD><TD>$iphost{$index} ($ipaddr{$index})</TD></TR>
${c}   <TR><TD>Max Speed:</TD>
${c}       <TD>$speed_str ($ifType_d{$siftype{$index}})</TD></TR>
${c}  </TABLE>
${c}
#---------------------------------------------------------------
ECHO
  }
#
# Frame-Relay
#

  my(%circuits);

  $session->map_table ([[1,3,6,1,2,1,10,32,2,1,1], # Ifindex
                        [1,3,6,1,2,1,10,32,2,1,2]],# DLCI
  sub ($@) {
      my ($rwindex,$crindex,$dlci) = @_;
      grep (defined $_ && ($_=pretty_print $_),
  	  ($rwindex,$crindex,$dlci) );
      my($tmpindex);
      $tmpindex = $crindex.".".$dlci;
      $circuits{$tmpindex} = $tmpindex;
  });

  foreach $index ( sort { $a <=> $b } keys %circuits) {
    my ($tmpname) = $router.".dlci.".$index;
    printf "\n\n";
    printf "Options[%s]: bits, noinfo, growright, nopercent\n",$tmpname;
    printf "YSize[%s]: 300\n",$tmpname;
    printf "XSize[%s]: 600\n",$tmpname;
    printf "YLegend[%s]: Bits per Second\n",$tmpname;
    printf "Suppress[%s]: y\n",$tmpname;
    if($optctl{"ip"}) {
       printf "Target[%s]: .1.3.6.1.2.1.10.32.2.1.9.%s\&.1.3.6.1.2.1.10.32.2.1.7.%s:%s\@%s\n",$tmpname,$index,$index,$community,$ip;
    } else {
       printf "Target[%s]: .1.3.6.1.2.1.10.32.2.1.9.%s\&.1.3.6.1.2.1.10.32.2.1.7.%s:%s\@%s\n",$tmpname,$index,$index,$community,$router;
    }
    printf "MaxBytes[%s]: 1250000\n",$tmpname;
    printf "Title[%s]: Traffic Analysis for DLCI %s\n",$tmpname,$index;
    printf "PageTop[%s]: <H1>Traffic Analysis for DLCI %s</H1>\n",$tmpname,$index;
    printf " <TABLE>";
    printf "  <TR><TD>System:</TD><TD>%s in %s</TD></TR>",$sysName,$sysLocation;
    printf "  <TR><TD>Maintainer:</TD><TD>%s</TD></TR>",$sysContact;
    printf "  <TR><TD>InterfaceID.DLCI:</TD><TD>%s</TD></TR>",$tmpname;
    printf " </TABLE>";
  }
}
  
main;
exit(0);

sub fmi {
  my($number) = $_[0];
  my(@short);
  @short = ("Bytes/s","kBytes/s","MBytes/s","GBytes/s");
  my $digits=length("".$number);
  my $divm=0;
  while ($digits-$divm*3 > 4) { $divm++; }
  my $divnum = $number/10**($divm*3);
  return sprintf("%1.1f %s",$divnum,$short[$divm]);
}