## ## 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;