#!/usr/local/bin/wish8.4
#
#  TkIfUtil.tcl (c) vfom    13.05.2002
#  Need UCD-SNMP paclage installed
#
#  Usage: ./TkIfUtil.tcl cisco public 4 
#  Shows utilisation of interface with index 4.
#
package require BLT 
#
set 	tmpSnmp		""
set 	errSnmp		""
set	inBytes		0
set	outBytes	0
set	inCounter	0
set	outCounter	0
set	prevInCounter	0
set	prevOutCounter	0
set	flagFirst	0
#
set cycleTime	20
set stepSize	[expr  20 * $cycleTime ]
set viewTime	[expr  6 * 60 * $cycleTime ]
set totalTime	0
set host 	[lindex $argv 0 ]
set community	[lindex $argv 1 ]
set portIndex	[lindex $argv 2 ]
set ifAlias     ""
#
set ::snmpget_prog "/usr/local/bin/snmpget -OQu -v2c -c "
#
#  Max if speed = 1Gbit/sec 
#
set maxBytesPerCycle [expr wide(128*1024*1024)*$cycleTime ]
#
if { $host =="" || $community=="" || $portIndex =="" } {
    puts "Some parameters missed."
    exit
}
#
proc CheckHiCounters { ifind } {
    # check is  High Capacity Counter objects availiable
    catch { eval  blt::bgexec ::snmp_exitFlag -output ::tmpSnmp -error ::errSnmp \
	$::snmpget_prog  $::community $::host  IF-MIB::ifXTable.ifXEntry.ifAlias.$ifind
    }
    if { ![string match $::tmpSnmp "" ] && ![regexp -- {No Such Object} $::tmpSnmp]  } { 
	set ::ifAlias [lrange $::tmpSnmp  2 end ]  
	return 1
    } 
    return 0
}
#
proc GetIfNameByIndex { ifind } {
    set x3 ""
    catch { eval  blt::bgexec ::snmp_exitFlag -output ::tmpSnmp -error ::errSnmp \
	$::snmpget_prog  $::community $::host  interfaces.ifTable.ifEntry.ifDescr.$ifind
    }
    if { [string match $::tmpSnmp "" ] } {
	tk_dialog .snmpError "SNMPget Error" \
	    "Can't retriev SNMP data from \"$::host\": $::errSnmp" \
	    error 0 "Approve" 
    } else {
	return  [lrange $::tmpSnmp  2 end ] 
    }
    return
}

#
proc cycleStep {  } {
 uplevel \#0 { 

    set prevInCounter  [expr wide($inCounter)]
    set prevOutCounter [expr wide($outCounter)]

    catch { eval  blt::bgexec snmp_exitFlag -output tmpSnmp -error errSnmp	\
    	 $snmpget_prog $community $host $in_mask.$portIndex $out_mask.$portIndex
    }	
        
    if { [string equal $tmpSnmp "" ] } {
	tk_dialog .snmpErr "SNMPget Error" $errSnmp \
	  error 0 Cancel
	set step  [expr $cycleTime * 1000 ]
	after $step  cycleStep
	return
    }
    set str [ split $tmpSnmp "\n"]
    set inCounter  [expr wide([lindex [lindex $str 0] end ])]
    set outCounter [expr wide([lindex [lindex $str 1] end ])]
    if  { $flagFirst != 0 } {
	if { $inCounter < $prevInCounter } {
	    set inBytes  [ expr wide($inCounter -  $prevInCounter)  ]
	} else {
	    # counter overrun
	    set inBytes [ expr wide($inCounter  + ($maxCounter-$prevInCounter)) ]
	}
	if { $inBytes > $maxBytesPerCycle } {
	    # looks like counters reset
	    set inBytes [expr wide($inCounter)]
	}
	
	if { $outCounter < $prevOutCounter } {
	    set outBytes [ expr wide($outCounter - $prevOutCounter) ]
	} else {
	    # counter overrun
	    set outBytes [ expr wide($outCounter  + ($maxCounter-$prevOutCounter)) ]
	}
	if { $outBytes >  $maxBytesPerCycle } {
	    # looks like counters reset
	    set outBytes [expr wide($outCounter)]
	}
    } else {
	set inBytes  0
	set outBytes 0
	set flagFirst 1
    }

    #
    set maxSp [ expr wide($inBytes/$cycleTime)  ]
    set maxOut [ expr wide($outBytes/$cycleTime)  ]
    if { $maxOut > $maxSp } { set maxSp [expr wide($maxOut)] }
    set yaxTitle "Bytes/sec"
    if { $maxSp > 1024 } {
	set yaxTitle "KBytes/sec"
	set ::multiplayer 1024
    }
    #  1024*1024 = 1048576 
    if { $maxSp > 1048576 } {
	set yaxTitle "MBytes/sec"
	set ::multiplayer 1048576
    }
    .graph yaxis configure   -title $yaxTitle
    
    #
    timeVector append  [ clock seconds ]    
    inBytesVector append  $inBytes
    outBytesVector append $outBytes
    if { $totalTime < $viewTime } {
	set totalTime [ expr $totalTime + $cycleTime]
    } else {
	timeVector	delete 0    
	inBytesVector	delete 0
	outBytesVector	delete 0
    }
    set step  [expr $cycleTime * 1000 ]
    
    after $step  cycleStep
  }
}
#
proc fTime { w val } {
    return [ clock format [expr int($val)] -format "%H:%M:%S" ]
}    
proc fTraffic { w val } {
#    global cycleTime multiplayer
    return [expr ($val/$::multiplayer)/$::cycleTime ]
}
#
blt::vector create timeVector inBytesVector outBytesVector
timeVector append [ clock seconds ]
inBytesVector append 	0.0
outBytesVector append	0.0

blt::graph .graph -width 1024  -fg black \
    -plotbackground black -title [join [join [lrange $argv 3 end]]]
pack .graph -fill both -expand on -padx 5
    

.graph element create line1 \
	-label "inBytes"  -color red -fill green  -xdata timeVector -ydata inBytesVector  \
	-symbol ""
.graph element create line2 \
	-label "outBytes" -color blue -fill orange -xdata timeVector -ydata outBytesVector \
	-symbol ""
    
.graph legend configure -position plotarea -anchor nw  -fg white -relief flat
.graph marker configure -hide yes

#.graph xaxis configure -command fTime  -stepsize $stepSize
.graph xaxis configure -command fTime 
.graph yaxis configure -command fTraffic -min 0.0 
.graph grid configure -hide no -color grey48 -dashes { 2 4 2 }

set ::multiplayer 1
.graph yaxis configure   -title "bytes/sec"

bind . <Alt-F4> "destroy ."

if { [CheckHiCounters $portIndex ] } {
    #
    #   Expecting counters are 64bit
    #        2^64-1   
    set maxCounter 18446744073709551615
    set in_mask "IF-MIB::ifXTable.ifXEntry.ifHCInOctets"
    set out_mask "IF-MIB::ifXTable.ifXEntry.ifHCOutOctets"
} else {
    #
    #   Expecting counters are 32bit
    #        2^32-1   
    set maxCounter 4294967295 
    set in_mask "interfaces.ifTable.ifEntry.ifInOctets"
    set out_mask "interfaces.ifTable.ifEntry.ifOutOctets"
    set snmpget_prog "/usr/local/bin/snmpget -OQu -v1 -c "
}
wm title . "HOST: $host INTERFACE: [GetIfNameByIndex $portIndex ] ($::ifAlias)"


after 10 cycleStep

#