#! /usr/bin/perl # # # use RRDs; use GDBM_File; $ddir='/home/wleiden/stats/rrd/data'; $com='public'; $snmpget="/usr/local/bin/snmpget -m all -c $com"; $snmpwalk="/usr/local/bin/snmpwalk -m all -c $com"; $MIB80211='enterprises.wirelessLeiden.wirelessLeidenMIB.light80211MIB.light80211'; $arptable="/home/wleiden/stats/arptable.gdbm"; $maxloadavg=200; local $SIG{ALRM} = sub { die "Alarm; been waiting for too long: 180 sec. Exiting now.\n" }; alarm(180); $start=time(); $node=shift(@ARGV); $0=$PROGRAM_NAME="RRD_FETCH_${node}"; open (PID,">$ddir/${node}/fetch.pl.pid");print PID "$$\n"; close(PID); if ($ARGV[0] eq 'DEBUG') {$DEBUG=1;} do_it($node); unlink "$ddir/${node}/fetch.pl.pid"; sub do_it { local($node)=@_; local(%IF); $snmpversion=snmpget($node,'system.sysObjectID.0'); if ($snmpversion eq '') {print "No snmp answer. Skipped $node: [$snmpversion]\n";return} if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: Doing $node ($snmpversion)\n",$elapsed/60; } # if ($DEBUG) #{ # traffic($node); # routes($node); #} #else { memory($node); storage($node); snmp_system($node); if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: icmp:\n",$elapsed/60; } icmp($node); if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: traf:\n",$elapsed/60; } traffic($node); if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: routes:\n",$elapsed/60; } routes($node); if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: arp_table:\n",$elapsed/60; } arp_table($node); if ($snmpversion=~/enterprises.8072.3.2.255/i) { if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: channels:\n",$elapsed/60; } channels($node); if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: wifi:\n",$elapsed/60; } wifi_links($node); } } do_rrupdate(); if ($DEBUG) { $unow=time(); $elapsed=$unow-$start; printf "%.1f min: DONE.\n",$elapsed/60; } } sub wifi_links { local($host)=@_; local($tpl,$data,$file); local(%A,%MAC); local($ip,$first,$last,$node,$interf,$nick,$link,$local); tie %A,'GDBM_File',"$arptable", &GDBM_READER, 0640 || die "Could not create file: $arptable\n"; open (LINKS,"$snmpwalk $host ${MIB80211}.l80211StaTable.l80211StaEntry 2> /dev/null|"); while() { #print $_; chomp(); s/\s+Counter\d+:\s+//; if (/l80211StaMAC\.([0-9.]+)\.([0-9.]+)\s*=\s*(\S+)/) { $if=$IF{$1}; $counter=$2; @mac=split(/:/,lc($3)); $MAC=sprintf("%02s:%02s:%02s:%02s:%02s:%02s",@mac); if ($MAC!~/^[0-9a-f:]{17}$/) {next;} if ($MAC=~/ff:ff:ff:ff:ff:ff/) {next;} $MAC{"$if:$counter"}=$MAC; #print "MAC[$if.$counter]=$MAC\n"; } elsif(/( l80211Sta(In|Out)Bytes| l80211StaAvg(In|Out)Bandwidth| l80211StaDev(In|Out)Bandwidth| l80211StaAvgSignal| l80211StaAvgNoise| l80211StaAvgQuality )\.([0-9.]+)\.([0-9.]+)\s*=\s*(.*)/x) { $name=$1; $if=$IF{$5}; $counter=$6; $value=$7; if ($name=~/(In|Out)/) {$dir=$1;} else {$dir='';} $MAC=$MAC{"$if:$counter"}; s/$MIB80211//; #print "$_\n"; # print "802.11:$name:if=$if:counter=$counter:val=$value:$MAC:[$dir]\n"; if (exists($A{$MAC})) { ($ip,$first,$last,$node,$interf,$nick,$link,$local) =split(/\|/,$A{$MAC}); } else {$ip=$first=$last=$node=$interf=$nick=$link=$local='';} if ($link) { # print "LINK: $MAC =$ip\n"; $file="$ddir/$host/link-$ip.rrd"; if (! -e $file) {next;} # Toevallige ontvangst. $name=~s/^l80211Sta//i; $data=$value; $tpl=$name; rrupdate($file,$tpl,$data); } } } untie(%A); close(LINKS); } sub arp_table { local($host)=@_; local($tpl,$data,$file); local(%LOCALIP,%A); local($ip,$first,$last,$node,$interf,$nick,$link,$local); open (ARP,"$snmpwalk $host ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex 2> /dev/null|"); while() { chomp(); s/\s+Counter\d+:\s+//; if (/ipAdEntIfIndex\.([0-9.]+)\s*=\s*(\d+)/) { $ip=$1; $ifnum=$2; $LOCALIP{$ip}=$if=$IF{$ifnum}; #print "LOCALIP: $ip=$if ($ifnum)\n"; } } close(ARP); tie %A,'GDBM_File',"$arptable", &GDBM_WRCREAT, 0640 || die "Could not create file: $arptable\n"; open (ARP,"$snmpwalk $host at.atTable.atEntry.atPhysAddress 2> /dev/null|"); while() { #print $_; chomp(); s/\s+Counter\d+:\s+//; if (/atEntry\.([^.]+)\.(\d+)\.(\d+)\.([0-9.]+)\s*=\s*(.*)/) { $name=$1; $ifnumber=$2; $counter=$3; $ip=$4; $value=$5; $if=$IF{$ifnumber}; if ($name=~/atPhysAddress/i) { $MAC=lc($value); $MAC=~s/hex: //i;$MAC=~s/\s/:/gi;$MAC=~s/:$//; if ($MAC=~/ff:ff:ff:ff:ff:ff/) {#print "FFFFFF:$MAC\n"; next;} if ($MAC!~/^[0-9a-f:]{17}$/i) {#print "ALPHA:$MAC\n"; next;} if (exists($A{$MAC})) { ($old_ip,$old_first,$old_last,$old_node,$old_if,$old_nick,$old_link,$old_local) =split(/\|/,$A{$MAC}); if ((! exists($LOCALIP{$ip})) && ($old_local >0) && ($old_node ne $node)) {#print "Keeping local info from other node ($old_node): $ip\n"; next;} #print "OLD[$MAC]=$old_ip,$old_first,$old_last,$old_node,$old_if\n"; } $last=time(); if ($old_first >0) {$first=$old_first;} else {$first=$last;} if ($ip=~/^172\.16\./) {$link=1;} else {$link=0;} if (exists($LOCALIP{$ip})) {$localip=1;} else {$localip=0;} $nickname=''; $A{$MAC}="$ip|$first|$last|$node|$if|$nickname|$link|$localip|"; #print "$MAC=$ip|$first|$last|$node|$if|$nickname|$link|$localip|\n"; } #print "${name}:$ifnumber=$if:$counter:$ip = [$MAC]\n"; } } untie(%A); close(ARP); } sub channels { local($host)=@_; local($tpl,$data,$file); local(%LOCALIP); open (CHAN,"$snmpwalk $host ${MIB80211}.l80211IfaceTable.l80211IfaceEntry.l80211IfaceChannel 2> /dev/null|"); while() { #print $_; chomp(); s/\s+Counter\d+:\s+//; if (/l80211IfaceChannel\.([0-9.]+)\s*=\s*(\d+)/) { $if=$IF{$1}; $channel=$2; #print "CHAN[$if]=$channel;"; $data=$channel; $tpl='channel'; $file="$ddir/$host/int-$if.rrd"; rrupdate($file,$tpl,$data); } } close(CHAN); } sub storage { local($host)=@_; local($tpl,$data,$file); local(%DESC,%SIZE,%USED); open (MEM,"$snmpwalk $host enterprises.ucdavis.dskTable.dskEntry 2> /dev/null|"); while() { chomp(); s/\s+Counter\d+:\s+//; if (/([^.]+)\.(\d+)\s*=\s*(\S+)/) { $name=$1; $number=$2; $value=$3;$value=~s/(^"|"$)//gi; if ($name=~/dskPath/) {$DESC{$number}=$value;} elsif ($name=~/dskTotal/) {$SIZE{$number}=$value;} elsif ($name=~/dskUsed/) {$USED{$number}=$value;} # else {print "$name.$number = $value\n";} } } close(MEM); foreach $number (keys %DESC) { $mountpoint=$DESC{$number}; if ($mountpoint=~/^(Real|Swap|Memory|\/dev|\/proc)/) {next;} $size=int($SIZE{$number}*1024);if ($size eq 0) {$size=1;} $used=int($USED{$number}*1024); #printf "STORAGE: $mountpoint: $used/$size=%.1f\%\n",100*$used/$size; $mountpoint=~s/^\///; $tpl.="${mountpoint}_size:${mountpoint}_used:"; $data.="$size:$used:"; } $file="$ddir/$host/system.rrd"; rrupdate($file,$tpl,$data); } sub memory { local($host)=@_; local($tpl,$data,$file); local($memTotalSwap,$memAvailSwap,$memTotalReal,$memAvailReal,$memTotalFree, $memMinimumSwap,$memShared,$memBuffer,$memCached,$memSwapError); $memTotalSwap=$memAvailSwap=$memTotalReal=$memAvailReal=$memTotalFree= $memMinimumSwap=$memShared=$memBuffer=$memCached=$memSwapError='U'; open (MEM,"$snmpwalk $host enterprises.ucdavis.memory 2> /dev/null|"); while() { chomp(); s/\s+Counter\d+:\s+//; if (/([^.]+)\.0\s*=\s*(\d+)/) { $name=$1;$value=$2; if ($name=~/^(memTotalSwap|memAvailSwap|memTotalReal|memAvailReal |memTotalFree|memMinimumSwap|memShared|memBuffer| memCached|memSwapError)$/x) { if ($name!~/memSwapError/) {$value=1024*$value;} $tpl.="$name:"; $data.="$value:"; } #else {print "MEM: $name=$value\n";} } } close(MEM); $file="$ddir/$host/system.rrd"; rrupdate($file,$tpl,$data); } sub traffic { local($host)=@_; local(%D,%DOWN); local($tpl,$data,$file); $D=$IF=(); open (INT,"$snmpwalk $host interfaces.ifTable.ifEntry 2> /dev/null|"); while() { #print $_; chomp(); s/\s+Counter\d+:\s+//; if (/([^.]+)\.(\d+)\s*=\s*(.*)/) { $name=$1;$num=$2;$value=$3;$value=~s/(^"|"$)//gi; $D{"$num|$name"}=$value; if ($name=~/ifDescr/) {$IF{$num}=$value; #print "$IF $num=$value\n"; } if ($name=~/ifOperStatus/) {$DOWN{$num}=$value;} } } foreach $key (sort keys %D) { ($num,$name)=split(/\|/,$key); $if=$IF{$num}; if ($if=~/^lo/) {next;} if ($DOWN{$num}=~/down/i) {next;} $data=$D{$key}; # print "$if=$num: $name = $value\n"; if ($name=~/if(in|out)Octets/i) {$tpl="bytes_" . lc($1);} elsif ($name=~/if(in|out)Errors/i) {$tpl="errors_" . lc($1);} elsif ($name=~/if(in|out)UcastPkts/i) {$tpl="Ucast_" . lc($1);} elsif ($name=~/if(in|out)NUcastPkts/i) {$tpl="NUcast_" . lc($1);} else {next;} $file="$ddir/$host/int-$if.rrd"; rrupdate($file,$tpl,$data); } return(1); } sub routes { local($host)=@_; local($tpl,$data,$file); local(%ROUTES,%INDIRECT); %ROUTES=%INDIRECT=(); open (ROUTES,"$snmpwalk $host ip.ipRouteTable.ipRouteEntry.ipRouteType 2> /dev/null|"); while() { chomp(); s/\s+Counter\d+:\s+//; if (/ipRouteType\.(\S+)\s+=\sindirect/) {$INDIRECT{$1}=1;} } close(ROUTES); open (ROUTES,"$snmpwalk $host ip.ipRouteTable.ipRouteEntry.ipRouteIfIndex 2> /dev/null|"); while() { chomp(); s/\s+Counter\d+:\s+//; if (/ipRouteIfIndex\.(\S+)\s+=\s+(\d+)/) { $route=$1; $if=$IF{$2}; if ($if=~/lo/) {next;} if (($INDIRECT{$route}) && ($route=~/^172\.[123]\d\./)) { $ROUTES{$if}++; #print "ROUTES:$1:[$if]:$ROUTES{$if}\n"; } } } close (ROUTES); foreach $if (sort keys %ROUTES) { $file="$ddir/$host/int-$if.rrd"; $data=$ROUTES{$if}; $tpl="routes"; rrupdate($file,$tpl,$data); # print "R:$file:$if:$data\n"; } } sub snmp_system { local($host)=@_; local($file,$data,$tpl); $file="$ddir/$host/system.rrd"; $uptime=snmpget($host,'system.sysUpTime.0'); if ($uptime=~/\((\d+)\)/) { $data.=$1/(100*86400) . ':'; $tpl.="uptime:"; } # $users=snmpget($host,'host.hrSystem.hrSystemNumUsers.0');$users=~s/^.*?(\d+).*?$/$1/; # $processes=snmpget($host,'host.hrSystem.hrSystemProcesses.0');$processes=~s/^.*?(\d+).*?$/$1/; # $tpl.="users:processes:"; # $data.="$users:$processes:"; $IRQs=snmpget($host,'enterprises.ucdavis.systemStats.ssSysInterrupts.0');$IRQs=~s/^.*?(\d+).*?$/$1/; $idle=snmpget($host,'enterprises.ucdavis.systemStats.ssCpuIdle.0');$idle=~s/^.*?(\d+).*?$/$1/;$idle/=100; $tpl.="IRQs:idle:"; $data.="$IRQs:$idle:"; $five=snmpget($host,'enterprises.ucdavis.laTable.laEntry.laLoad.1'); $ten=snmpget($host,'enterprises.ucdavis.laTable.laEntry.laLoad.2'); $fifteen=snmpget($host,'enterprises.ucdavis.laTable.laEntry.laLoad.3'); $tpl.="five:ten:fifteen"; $data.="$five:$ten:$fifteen"; rrupdate($file,$tpl,$data); } sub icmp { local($host)=@_; local($file,$data,$tpl); $file="$ddir/$host/icmp.rrd"; open (ICMP,"$snmpwalk $host icmp 2> /dev/null|"); while() { #print $_; chomp(); s/\s+Counter\d+:\s+//; if (/^icmp\.([^.]+)\.\d+\s+=\s+(\d+)/) { $name=$1;$value=$2; #print "ICMP: $name = $value\n"; if ($name=~/(icmpInMsgs|icmpInErrors|icmpInDestUnreachs|icmpInTimeExcds|icmpInRedirects|icmpInEchos|icmpInEchoReps)/) { $tpl.="$name:"; $data.="$value:"; } } } close (ICMP); rrupdate($file,$tpl,$data); } sub rrupdate { local($file,$tpl,$data)=@_; local($ERR); if (($data ne '') && ($tpl ne '')) { $tpl=~s/([^:])$/$1:/; $data=~s/([^:])$/$1:/; $TPL{$file}.=$tpl; $DATA{$file}.=$data; # if ($DEBUG) {print "RRU: $file $tpl=$data\n";} } elsif ($DEBUG) {print "RRU=EMPTY: [$tpl]=[$data]\n";} if (! $DEBUG) {sleep(1);} } sub do_rrupdate { foreach $file (sort keys %TPL) { if ( ! -e $file) { print "File does not exist: $file.\n"; next; } $tpl=$TPL{$file}; $data=$DATA{$file}; $tpl=~s/:$//; $data=~s/:$//; #print "Filing: $file:[$tpl]:[$data]\n"; if (($data ne '') && ($tpl ne '')) { $data="N:$data"; if ($DEBUG) {print "DRRU: $file $tpl=$data\n";} RRDs::update ($file,"--template",$tpl,$data); $ERR=RRDs::error; if ($ERR) {print STDERR "ERROR while updating $file: $ERR\n"} } $TPL{$file}=''; $DATA{$file}=''; delete($TPL{$file}); delete($DATA{$file}); if (! $DEBUG) {sleep(1);} } } sub snmpget { local($host,$query)=@_; local($doit)="$snmpget $host $query 2> /dev/null"; print "DOIT: [$doit]\n"; local($result)=`$doit`; print "RESULT: [$result]\n"; chomp($result); $result=~s/^.*=\s+(.*)$/$1/; #print "RESULT2: [$result]\n"; if (! $DEBUG) {sleep(1);} return($result); }