##
## OSSP snmpdx - SNMP Daemon Extension
## Copyright (c) 2003-2007 The OSSP Project
## Copyright (c) 2003-2007 Ralf S. Engelschall
## Copyright (c) 2003-2005 Cable & Wireless
##
## This file is part of OSSP snmpdx, a SNMP daemon extension which
## can be found at http://www.ossp.org/pkg/tool/snmpdx/.
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version
## 2.0 of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this file; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
## USA, or contact Ralf S. Engelschall .
##
## sysVM.pm: probe for System Virtual Memory
##
package My::Probe::sysVM;
our @ISA = qw(My::Probe);
sub oids ($) {
my ($self) = @_;
return $self->{-ctx}->{-mib}->oids("*.snmpdx.host.system.sysVM.*");
}
sub probe ($$) {
my ($self, $obj) = @_;
if ($self->{-ctx}->{-platform}->id() =~ m/FreeBSD/i) {
##
## FreeBSD 4/5
##
## sysVMRamMax "/sbin/sysctl -a", "hw.physmem", convert bytes to MB
## sysVMRamUsed sysVMRamMax - sysVMRamFree
## sysVMRamFree "/sbin/sysctl -a", "vm.stats.vm.*", convert pages to MB
## sysVMSwapMax "/usr/sbin/swapinfo -k", 1K-blocks, last line, convert KB to MB
## sysVMSwapUsed "/usr/sbin/swapinfo -k", Used, last line, convert KB to MB
## sysVMSwapFree sysVMSwapMax - sysVMSwapUsed
## sysVMActivity "/usr/bin/vmstat", add pi and po column
##
if ($obj->{-name} =~ m/\.sysVMRam(Max|Used|Free)$/) {
my $sysVMRamMax;
my $sysVMRamUsed;
my $sysVMRamFree;
# query system for sysctl(8) variables
my $out = $self->{-ctx}->{-sys}->run("/sbin/sysctl -a", "1m");
my $sysctl = {};
foreach my $line (split(/\n/, $out->{-stdout})) {
$sysctl->{$1} = $2 if ($line =~ m/^([^:]+):\s+(.+)\s*$/s);
}
# determine sysVMRamMax
$sysVMRamMax = int(&mem_rounded($sysctl->{"hw.physmem"}) / (1024*1024));
# determine sysVMRamFree
$sysVMRamFree =
int(( $sysctl->{"hw.pagesize"}
* ( $sysctl->{"vm.stats.vm.v_inactive_count"}
+ $sysctl->{"vm.stats.vm.v_cache_count"}
+ $sysctl->{"vm.stats.vm.v_free_count"} )) / (1024*1024));
# determine sysVMRamUsed
if (defined($sysVMRamMax) and defined($sysVMRamFree)) {
$sysVMRamUsed = ($sysVMRamMax - $sysVMRamFree);
}
# provide result
$obj->{-value} = $sysVMRamMax if ($obj->{-name} =~ m/\.sysVMRamMax$/);
$obj->{-value} = $sysVMRamUsed if ($obj->{-name} =~ m/\.sysVMRamUsed$/);
$obj->{-value} = $sysVMRamFree if ($obj->{-name} =~ m/\.sysVMRamFree$/);
}
elsif ($obj->{-name} =~ m/\.sysVMSwap(Max|Used|Free)$/) {
my $sysVMSwapMax;
my $sysVMSwapUsed;
my $sysVMSwapFree;
# determine sysVMSwapMax and sysVMSwapUsed
my $out = $self->{-ctx}->{-sys}->run("/usr/sbin/swapinfo -k", "1m");
my $raw = $out->{-stdout};
my $n2i = {};
if ($raw =~ m/^\s*([^\n]*\b1K-blocks[^\n]*\bUsed[^\n]*).*\n([^\n]+)$/s) {
$n2i = &mkn2i(split(/\s+/, $1));
}
my @dat = split(/\s+/, $2);
if (defined($n2i->{_1K_blocks})) {
$sysVMSwapMax = int(@dat[$n2i->{_1K_blocks}] / 1024)
}
if (defined($n2i->{Used})) {
$sysVMSwapUsed = int(@dat[$n2i->{Used}] / 1024)
}
# determine sysVMSwapFree
if (defined($sysVMSwapMax) and defined($sysVMSwapUsed)) {
$sysVMSwapFree = $sysVMSwapMax - $sysVMSwapUsed;
}
# provide result
$obj->{-value} = $sysVMSwapMax if ($obj->{-name} =~ m/\.sysVMSwapMax$/);
$obj->{-value} = $sysVMSwapUsed if ($obj->{-name} =~ m/\.sysVMSwapUsed$/);
$obj->{-value} = $sysVMSwapFree if ($obj->{-name} =~ m/\.sysVMSwapFree$/);
}
elsif ($obj->{-name} =~ m/\.sysVMActivity$/) {
my $sysVMActivity;
my $out = $self->{-ctx}->{-sys}->run("/usr/bin/vmstat", "1m");
my $raw = $out->{-stdout};
my $n2i = {};
if ($raw =~ m/^[^\n]*\n *([^\n]*(\bp[io]\b[^\n]*){2})\n *([^\n]*)\n$/s) {
$n2i = &mkn2i(split / +/, $1);
}
if (defined($n2i->{pi}) and defined($n2i->{po})) {
my @dat = split(/ +/, $3);
$sysVMActivity = @dat[$n2i->{pi}] + @dat[$n2i->{po}];
}
$obj->{-value} = $sysVMActivity;
}
}
elsif ($self->{-ctx}->{-platform}->id() =~ m/Linux/i) {
##
## Linux 2.2/2.4
##
## sysVMRamMax "/bin/cat /proc/meminfo", MemTotal, convert KB to MB
## sysVMRamUsed "/bin/cat /proc/meminfo", MemTotal-Buffers-Cached-MemFree, convert KB to MB
## sysVMRamFree sysVMRamMax - sysVMRamUsed
## sysVMSwapMax "/bin/cat /proc/meminfo", SwapTotal, convert KB to MB
## sysVMSwapUsed sysVMSwapMax - sysVMSwapFree
## sysVMSwapFree "/bin/cat /proc/meminfo", SwapFree, convert KB to MB
## sysVMActivity "/usr/bin/vmstat", add si and so column
##
## FIXME: sysVMRamMax does not include the kernel and some of
## its structures so it is not pyhsical RAM, see dmesg | egrep
## '^Memory:'. Additionally, /bin/cat is used here but could be
## replaced by native Perl code to improve performance...
##
if ($obj->{-name} =~ m/\.sysVMRam(Max|Used|Free)$/) {
my $sysVMRamMax;
my $sysVMRamUsed;
my $sysVMRamFree;
# determine sysVMRamMax and sysVMRamUsed
my $out = $self->{-ctx}->{-sys}->run("/bin/cat /proc/meminfo", "1m");
my $raw = $out->{-stdout};
my $tmp = {};
$tmp->{MemTotal} = $1 if ($raw =~ m/\nMemTotal:[^\n]*\b(\d+)\b[^\n]*kB\n/s);
$tmp->{Buffers} = $1 if ($raw =~ m/\nBuffers:[^\n]*\b(\d+)\b[^\n]*kB\n/s);
$tmp->{Cached} = $1 if ($raw =~ m/\nCached:[^\n]*\b(\d+)\b[^\n]*kB\n/s);
$tmp->{MemFree} = $1 if ($raw =~ m/\nMemFree:[^\n]*\b(\d+)\b[^\n]*kB\n/s);
if (defined($tmp->{MemTotal})) {
$sysVMRamMax = int($tmp->{MemTotal} / 1024);
}
if ( defined($tmp->{MemTotal})
and defined($tmp->{Buffers})
and defined($tmp->{Cached})
and defined($tmp->{MemFree}) ) {
$sysVMRamUsed = int (( $tmp->{MemTotal}
- $tmp->{Buffers}
- $tmp->{Cached}
- $tmp->{MemFree} ) / 1024 );
}
# determine sysVMRamFree
if (defined $sysVMRamMax and defined $sysVMRamUsed) {
$sysVMRamFree = $sysVMRamMax - $sysVMRamUsed;
}
# provide result
$obj->{-value} = $sysVMRamMax if ($obj->{-name} =~ m/\.sysVMRamMax$/);
$obj->{-value} = $sysVMRamUsed if ($obj->{-name} =~ m/\.sysVMRamUsed$/);
$obj->{-value} = $sysVMRamFree if ($obj->{-name} =~ m/\.sysVMRamFree$/);
}
elsif ($obj->{-name} =~ m/\.sysVMSwap(Max|Used|Free)$/) {
my $sysVMSwapMax;
my $sysVMSwapUsed;
my $sysVMSwapFree;
# determine sysVMSwapMax and sysVMSwapFree
my $out = $self->{-ctx}->{-sys}->run("/bin/cat /proc/meminfo", "1m");
my $raw = $out->{-stdout};
if ($raw =~ m/\nSwapTotal:[^\n]*\b(\d+)\b[^\n]*kB\n/s) {
$sysVMSwapMax = int($1 / 1024);
}
if ($raw =~ m/\nSwapFree:[^\n]*\b(\d+)\b[^\n]*kB\n/s) {
$sysVMSwapFree = int($1 / 1024);
}
# determine sysVMSwapUsed
if (defined($sysVMSwapMax) and defined($sysVMSwapFree)) {
$sysVMSwapUsed = $sysVMSwapMax - $sysVMSwapFree;
}
# provide result
$obj->{-value} = $sysVMSwapMax if ($obj->{-name} =~ m/\.sysVMSwapMax$/);
$obj->{-value} = $sysVMSwapUsed if ($obj->{-name} =~ m/\.sysVMSwapUsed$/);
$obj->{-value} = $sysVMSwapFree if ($obj->{-name} =~ m/\.sysVMSwapFree$/);
}
elsif ($obj->{-name} =~ m/\.sysVMActivity$/) {
my $sysVMActivity;
my $out = $self->{-ctx}->{-sys}->run("/usr/bin/vmstat", "1m");
my $raw = $out->{-stdout};
my $n2i = {};
if ($raw =~ m/^[^\n]*\n *([^\n]*(\bs[io]\b[^\n]*){2})\n *([^\n]*)\n$/s) {
$n2i = &mkn2i(split(/\s+/, $1)) if (not defined($n2i->{sr}));
}
if (defined($n2i->{si}) and defined($n2i->{so})) {
my @dat = split(/\s+/, $3);
$sysVMActivity = @dat[$n2i->{si}] + @dat[$n2i->{so}];
}
$obj->{-value} = $sysVMActivity;
}
}
elsif ($self->{-ctx}->{-platform}->id() =~ m/SunOS/i) {
##
## Sun Solaris 2.x (SunOS 5.x)
##
## sysVMRamMax "/usr/platform/$arch/sbin/prtdiag", Memory size
## sysVMRamUsed sysVMRamMax - sysVMRamFree
## sysVMRamFree "/bin/pagesize" * "/bin/sar -r 1 1", freemem, convert bytes to MB
## sysVMSwapMax "swap -l", egrep ^/ and accumulate, convert 512byte blocks to MB
## sysVMSwapUsed sysVMSwapMax - sysVMSwapFree
## sysVMSwapFree "swap -l", egrep ^/ and accumulate, convert 512byte blocks to MB
## sysVMActivity "/bin/vmstat", sr column
##
if ($obj->{-name} =~ m/\.sysVMRam(Max|Used|Free)$/) {
my $sysVMRamMax;
my $sysVMRamUsed;
my $sysVMRamFree;
# determine architecture
my $arch = $self->{-ctx}->{-platform}->arch();
# determine page size
my $out = $self->{-ctx}->{-sys}->run("/bin/pagesize", "forever");
my $raw = $out->{-stdout};
my $pagesize = 4096;
if ($raw =~ m/^(\d+)$/) {
$pagesize = $1;
}
# determine sysVMRamMax
$out = $self->{-ctx}->{-sys}->run("/usr/platform/$arch/sbin/prtdiag -v", "1m");
$raw = $out->{-stdout};
if ($raw =~ m/\nMemory size: (\d+) Megabytes/s) {
$sysVMRamMax = $1;
}
# determine sysVMRamFree
$out = $self->{-ctx}->{-sys}->run("/bin/sar -r 1 1", "1m");
$raw = $out->{-stdout};
my $n2i = {};
if ($raw =~ m/^.*\n([^\n]*\bfreemem[^\n]*)\n(.*)$/s) {
$n2i = &mkn2i(split(/\s+/, $1));
}
my @dat = split(/\s+/, $2);
if (defined($n2i->{freemem})) {
$tmp = @dat[$n2i->{freemem}];
}
$sysVMRamFree = int($tmp * $pagesize / (1024*1024)) if (defined($tmp));
# determine sysVMRamUsed
if (defined($sysVMRamMax) and defined($sysVMRamFree)) {
$sysVMRamUsed = $sysVMRamMax - $sysVMRamFree;
}
# provide result
$obj->{-value} = $sysVMRamMax if ($obj->{-name} =~ m/\.sysVMRamMax$/);
$obj->{-value} = $sysVMRamUsed if ($obj->{-name} =~ m/\.sysVMRamUsed$/);
$obj->{-value} = $sysVMRamFree if ($obj->{-name} =~ m/\.sysVMRamFree$/);
}
elsif ($obj->{-name} =~ m/\.sysVMSwap(Max|Used|Free)$/) {
my $sysVMSwapMax;
my $sysVMSwapUsed;
my $sysVMSwapFree;
# determine sysVMSwapMax, sysVMSwapFree
my $out = $self->{-ctx}->{-sys}->run("/usr/sbin/swap -l", "1m");
my $raw = $out->{-stdout};
my $n2i = {};
if ($raw =~ m/^\s*([^\n]*\bblocks[^\n]*\bfree[^\n]*)\n(.*)$/s) {
$n2i = &mkn2i(split(/\s+/, $1)) if (scalar(keys(%{$n2i})) == 0);
}
my $tmpMax;
my $tmpFree;
foreach my $r (split(/\n/, $2)) {
if ($r =~ m/^\//) {
my @dat = split(/\s+/, $r);
if (defined($n2i->{blocks})) {
$tmpMax = 0 if (not defined($tmpMax));
$tmpMax += @dat[$n2i->{blocks}];
}
if (defined($n2i->{free})) {
$tmpFree = 0 if (not defined($tmpFree));
$tmpFree += @dat[$n2i->{free}];
}
}
}
$sysVMSwapMax = int($tmpMax * 512 / 1024 / 1024) if (defined($tmpMax));
$sysVMSwapFree = int($tmpFree * 512 / 1024 / 1024) if (defined($tmpFree));
# determine sysVMSwapUsed
if (defined($sysVMSwapMax) and defined($sysVMSwapFree)) {
$sysVMSwapUsed = $sysVMSwapMax - $sysVMSwapFree;
}
# provide result
$obj->{-value} = $sysVMSwapMax if ($obj->{-name} =~ m/\.sysVMSwapMax$/);
$obj->{-value} = $sysVMSwapUsed if ($obj->{-name} =~ m/\.sysVMSwapUsed$/);
$obj->{-value} = $sysVMSwapFree if ($obj->{-name} =~ m/\.sysVMSwapFree$/);
}
elsif ($obj->{-name} =~ m/\.sysVMActivity$/) {
my $sysVMActivity;
my $out = $self->{-ctx}->{-sys}->run("/bin/vmstat", "1m");
my $raw = $out->{-stdout};
my $n2i = {};
if ($raw =~ m/^[^\n]*\n *([^\n]*\bsr\b[^\n]*)\n *([^\n]*)\n$/s) {
$n2i = &mkn2i(split(/\s+/, $1)) if (not defined($n2i->{sr}));
}
if (defined $n2i->{sr}) {
my @dat = split(/\s+/, $2);
$sysVMActivity = @dat[$n2i->{sr}];
}
$obj->{-value} = $sysVMActivity;
}
}
return;
}
# table row name to index mapping
sub mkn2i ($) {
my (@name) = @_;
my $rc = {};
my $i = 0;
foreach my $f (@name) {
$f =~ s/[^\w]/_/;
$f =~ s/^([^a-zA-Z_])/_$1/;
$rc->{$f} = $i++;
};
return $rc;
}
# round the physical memory size to the next power of two which is
# reasonable for memory cards. We do this by first determining the
# guessed memory card size under the assumption that usual computer
# hardware has an average of a maximally eight memory cards installed
# and those are usually of equal size.
sub mem_rounded {
my ($mem_size) = @_;
my $chip_size = 1;
my $chip_guess = ($mem_size / 8) - 1;
while ($chip_guess != 0) {
$chip_guess >>= 1;
$chip_size <<= 1;
}
my $mem_round = (int($mem_size / $chip_size) + 1) * $chip_size;
return $mem_round;
}
1;