blob: 8d18698e55a113a66d5e164557f960cd24c6bce0 [file] [log] [blame]
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/auto_nlist.h>
#include <net-snmp/agent/hardware/memory.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/fcntl.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <kvm.h>
#if HAVE_SYS_VMPARAM_H
#include <sys/vmparam.h>
#else
#include <vm/vm_param.h>
#endif
#define SUM_SYMBOL "cnt"
#define BUFSPACE_SYMBOL "bufspace"
quad_t swapTotal;
quad_t swapUsed;
quad_t swapFree;
static int swapmode(long);
/*
* Load the latest memory usage statistics
*/
int netsnmp_mem_arch_load( netsnmp_cache *cache, void *magic ) {
netsnmp_memory_info *mem;
long pagesize;
int nswap;
#if !defined(VM_TOTAL)
unsigned int free_mem;
size_t free_size = sizeof(free_mem);
unsigned int mem_pages;
#else
struct vmtotal total;
size_t total_size = sizeof(total);
int total_mib[] = { CTL_VM, VM_TOTAL };
#endif
u_long phys_mem;
u_long user_mem;
unsigned int cache_count;
unsigned int cache_max;
unsigned int bufspace;
unsigned int maxbufspace;
unsigned int inact_count;
size_t mem_size = sizeof(phys_mem);
size_t cache_size = sizeof(cache_count);
size_t buf_size = sizeof(bufspace);
size_t inact_size = sizeof(inact_count);
int phys_mem_mib[] = { CTL_HW, HW_PHYSMEM };
int user_mem_mib[] = { CTL_HW, HW_USERMEM };
/*
* Retrieve the memory information from the underlying O/S...
*/
#if !defined(VM_TOTAL)
sysctlbyname("vm.stats.vm.v_free_count", &free_mem, &free_size, NULL, 0);
sysctlbyname("vm.stats.vm.v_page_count", &mem_pages, &free_size, NULL, 0);
#else
sysctl(total_mib, 2, &total, &total_size, NULL, 0);
#endif
sysctl(phys_mem_mib, 2, &phys_mem, &mem_size, NULL, 0);
sysctl(user_mem_mib, 2, &user_mem, &mem_size, NULL, 0);
sysctlbyname("vm.stats.vm.v_cache_count", &cache_count, &cache_size, NULL, 0);
sysctlbyname("vm.stats.vm.v_cache_max", &cache_max, &cache_size, NULL, 0);
sysctlbyname("vm.stats.vm.v_inactive_count", &inact_count, &inact_size, NULL, 0);
sysctlbyname("vfs.bufspace", &bufspace, &buf_size, NULL, 0);
sysctlbyname("vfs.maxbufspace", &maxbufspace, &buf_size, NULL, 0);
#ifndef freebsd4
pagesize = 1024;
#else
pagesize = getpagesize();
#endif
/*
* ... and save this in a standard form.
*/
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_PHYSMEM, 1 );
if (!mem) {
snmp_log_perror("No Physical Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Physical memory");
mem->units = pagesize;
mem->size = phys_mem/pagesize;
#if !defined(VM_TOTAL)
mem->free = free_mem;
#else
mem->free = total.t_free;
#endif
}
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_USERMEM, 1 );
if (!mem) {
snmp_log_perror("No (user) Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Real memory");
mem->units = pagesize;
#if !defined(VM_TOTAL)
mem->size = user_mem/pagesize;
mem->free = free_mem;
#else
mem->size = total.t_rm;
mem->free = total.t_rm - total.t_arm;
#endif
}
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_VIRTMEM, 1 );
if (!mem) {
snmp_log_perror("No Virtual Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Virtual memory");
mem->units = pagesize;
#if !defined(VM_TOTAL)
mem->size = mem_pages+swapTotal;
mem->free = free_mem+swapFree;
#else
mem->size = total.t_vm;
mem->free = total.t_vm - total.t_avm;
#endif
}
#if defined(VM_TOTAL)
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SHARED, 1 );
if (!mem) {
snmp_log_perror("No Shared Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Shared virtual memory");
mem->units = pagesize;
mem->size = total.t_vmshr;
mem->free = total.t_vmshr - total.t_avmshr;
}
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SHARED2, 1 );
if (!mem) {
snmp_log_perror("No Shared2 Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Shared real memory");
mem->units = pagesize;
mem->size = total.t_rmshr;
mem->free = total.t_rmshr - total.t_armshr;
}
#endif
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_CACHED, 1 );
if (!mem) {
snmp_log_perror("No Cached Memory info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Cached memory");
mem->units = pagesize;
mem->size = cache_count;
mem->free = 0;
}
nswap = swapmode(pagesize);
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP, 1 );
if (!mem) {
snmp_log_perror("No Swap info entry");
} else {
if (!mem->descr)
mem->descr = strdup( (nswap>1) ? "Swap space (total)"
: "Swap space");
mem->units = pagesize;
mem->size = swapTotal;
mem->free = swapFree;
}
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_MBUF, 1 );
if (!mem) {
snmp_log_perror("No Buffer, etc info entry");
} else {
if (!mem->descr)
mem->descr = strdup("Memory buffers");
mem->units = 1024;
mem->size = maxbufspace / 1024;
mem->free = (maxbufspace - bufspace)/1024;
}
return 0;
}
/*
* Retained from UCD implementation
*/
#ifndef freebsd4
/*
* Executes swapinfo and parses last line
* This is just way too ugly ;)
*/
static int
swapmode(long pagesize)
{
struct extensible ext;
int fd;
FILE *file;
strcpy(ext.command, "/usr/sbin/swapinfo -k");
if ((fd = get_exec_output(&ext)) != -1) {
file = fdopen(fd, "r");
while (fgets(ext.output, sizeof(ext.output), file) != NULL);
fclose(file);
wait_on_exec(&ext);
sscanf(ext.output, "%*s%*d%qd%qd", &swapUsed, &swapFree);
swapTotal = swapUsed + swapFree;
}
return 1;
}
#else
/*
* swapmode is based on a program called swapinfo written
* by Kevin Lahey <kml@rokkaku.atl.ga.us>.
*/
#include <sys/conf.h>
extern kvm_t *kd;
static int
swapmode(long pagesize)
{
int i, n;
struct kvm_swap kswap[16];
netsnmp_memory_info *mem;
char buf[1024];
n = kvm_getswapinfo(kd, kswap, sizeof(kswap) / sizeof(kswap[0]), 0);
swapUsed = swapTotal = swapFree = 0;
if ( n > 0 ) {
/*
* If there are multiple swap devices, then record
* the statistics for each one separately...
*/
for (i = 0; i < n; ++i) {
mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP+1+i, 1 );
if (!mem)
continue;
if (!mem->descr) {
sprintf(buf, "swap %s", kswap[i].ksw_devname);
mem->descr = strdup( buf );
}
mem->units = pagesize;
mem->size = kswap[i].ksw_total;
mem->free = kswap[i].ksw_total - kswap[i].ksw_used;
/*
* ... and keep a running total for the overall swap stats
*/
swapTotal += kswap[i].ksw_total;
swapUsed += kswap[i].ksw_used;
}
} else {
/*
* If there's only one swap device, then don't bother
* with individual statistics.
*/
swapTotal += kswap[0].ksw_total;
swapUsed += kswap[0].ksw_used;
}
swapFree = swapTotal - swapUsed;
return n;
}
#endif