401 lines
11 KiB
C
401 lines
11 KiB
C
|
/*
|
||
|
* vmstat_freebsd2.c
|
||
|
*/
|
||
|
|
||
|
#include <net-snmp/net-snmp-config.h>
|
||
|
|
||
|
/*
|
||
|
* Ripped from /usr/scr/usr.bin/vmstat/vmstat.c (covering all bases)
|
||
|
*/
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/time.h>
|
||
|
#if defined(dragonfly)
|
||
|
#include <sys/user.h>
|
||
|
#else
|
||
|
#include <sys/proc.h>
|
||
|
#endif
|
||
|
#if defined(freebsd5) && __FreeBSD_version >= 500101
|
||
|
#include <sys/resource.h>
|
||
|
#elif defined(dragonfly)
|
||
|
#include <kinfo.h>
|
||
|
#else
|
||
|
#include <sys/dkstat.h>
|
||
|
#endif
|
||
|
#ifdef freebsd5
|
||
|
#include <sys/bio.h>
|
||
|
#endif
|
||
|
#include <sys/buf.h>
|
||
|
#include <sys/uio.h>
|
||
|
#include <sys/namei.h>
|
||
|
#include <sys/malloc.h>
|
||
|
#include <sys/signal.h>
|
||
|
#include <sys/fcntl.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/sysctl.h>
|
||
|
#include <sys/vmmeter.h>
|
||
|
|
||
|
#if HAVE_SYS_VMPARAM_H
|
||
|
#include <sys/vmparam.h>
|
||
|
#else
|
||
|
#include <vm/vm_param.h>
|
||
|
#endif
|
||
|
|
||
|
#include <time.h>
|
||
|
#include <nlist.h>
|
||
|
#include <kvm.h>
|
||
|
#include <errno.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdio.h>
|
||
|
#include <ctype.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <paths.h>
|
||
|
#include <limits.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 "util_funcs/header_generic.h"
|
||
|
#include "vmstat.h"
|
||
|
#include "vmstat_freebsd2.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* nlist symbols
|
||
|
*/
|
||
|
#define CPTIME_SYMBOL "cp_time"
|
||
|
#define SUM_SYMBOL "cnt"
|
||
|
#define INTRCNT_SYMBOL "intrcnt"
|
||
|
#define EINTRCNT_SYMBOL "eintrcnt"
|
||
|
#define BOOTTIME_SYMBOL "boottime"
|
||
|
|
||
|
/*
|
||
|
* Number of interrupts
|
||
|
*/
|
||
|
#define INT_COUNT 10
|
||
|
|
||
|
/*
|
||
|
* CPU percentage
|
||
|
*/
|
||
|
#define CPU_PRC 100
|
||
|
|
||
|
FindVarMethod var_extensible_vmstat;
|
||
|
|
||
|
void
|
||
|
init_vmstat_freebsd2(void)
|
||
|
{
|
||
|
|
||
|
struct variable2 extensible_vmstat_variables[] = {
|
||
|
{MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {MIBINDEX}},
|
||
|
{ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {ERRORNAME}},
|
||
|
{SWAPIN, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {SWAPIN}},
|
||
|
{SWAPOUT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {SWAPOUT}},
|
||
|
{IOSENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {IOSENT}},
|
||
|
{IORECEIVE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {IORECEIVE}},
|
||
|
{SYSINTERRUPTS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {SYSINTERRUPTS}},
|
||
|
{SYSCONTEXT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {SYSCONTEXT}},
|
||
|
{CPUUSER, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPUUSER}},
|
||
|
{CPUSYSTEM, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPUSYSTEM}},
|
||
|
{CPUIDLE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPUIDLE}},
|
||
|
{CPURAWUSER, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPURAWUSER}},
|
||
|
{CPURAWNICE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPURAWNICE}},
|
||
|
{CPURAWSYSTEM, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPURAWSYSTEM}},
|
||
|
{CPURAWIDLE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPURAWIDLE}},
|
||
|
{CPURAWKERNEL, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPURAWKERNEL}},
|
||
|
{CPURAWINTR, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {CPURAWINTR}},
|
||
|
{SYSRAWINTERRUPTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {SYSRAWINTERRUPTS}},
|
||
|
{SYSRAWCONTEXT, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
|
||
|
var_extensible_vmstat, 1, {SYSRAWCONTEXT}},
|
||
|
/*
|
||
|
* Future use:
|
||
|
*/
|
||
|
/*
|
||
|
* {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
|
||
|
* var_extensible_vmstat, 1, {ERRORFLAG }},
|
||
|
* {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
|
||
|
* var_extensible_vmstat, 1, {ERRORMSG }}
|
||
|
*/
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Define the OID pointer to the top of the mib tree that we're
|
||
|
* registering underneath
|
||
|
*/
|
||
|
oid vmstat_variables_oid[] = { NETSNMP_UCDAVIS_MIB, 11 };
|
||
|
|
||
|
/*
|
||
|
* register ourselves with the agent to handle our mib tree
|
||
|
*/
|
||
|
REGISTER_MIB("ucd-snmp/vmstat", extensible_vmstat_variables, variable2,
|
||
|
vmstat_variables_oid);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
long
|
||
|
getuptime(void)
|
||
|
{
|
||
|
static time_t now, boottime;
|
||
|
time_t uptime;
|
||
|
|
||
|
if (boottime == 0)
|
||
|
auto_nlist(BOOTTIME_SYMBOL, (char *) &boottime, sizeof(boottime));
|
||
|
|
||
|
time(&now);
|
||
|
uptime = now - boottime;
|
||
|
|
||
|
return (uptime);
|
||
|
}
|
||
|
|
||
|
unsigned char *
|
||
|
var_extensible_vmstat(struct variable *vp,
|
||
|
oid * name,
|
||
|
size_t * length,
|
||
|
int exact,
|
||
|
size_t * var_len, WriteMethod ** write_method)
|
||
|
{
|
||
|
|
||
|
int loop;
|
||
|
|
||
|
time_t time_new = getuptime();
|
||
|
static time_t time_old;
|
||
|
static time_t time_diff;
|
||
|
|
||
|
#if defined(dragonfly)
|
||
|
static struct kinfo_cputime cpu_old, cpu_new, cpu_diff;
|
||
|
static uint64_t cpu_total;
|
||
|
uint64_t cpu_sum;
|
||
|
static int pagesize;
|
||
|
#else
|
||
|
static long cpu_old[CPUSTATES];
|
||
|
static long cpu_new[CPUSTATES];
|
||
|
static long cpu_diff[CPUSTATES];
|
||
|
static long cpu_total;
|
||
|
long cpu_sum;
|
||
|
#endif
|
||
|
double cpu_prc;
|
||
|
|
||
|
static struct vmmeter mem_old, mem_new;
|
||
|
|
||
|
static long long_ret;
|
||
|
static char errmsg[300];
|
||
|
|
||
|
#if defined(dragonfly)
|
||
|
if (pagesize == 0)
|
||
|
pagesize = getpagesize() >> 10;
|
||
|
#endif
|
||
|
|
||
|
long_ret = 0; /* set to 0 as default */
|
||
|
|
||
|
if (header_generic(vp, name, length, exact, var_len, write_method))
|
||
|
return (NULL);
|
||
|
|
||
|
/*
|
||
|
* Update structures (only if time has passed)
|
||
|
*/
|
||
|
if (time_new != time_old) {
|
||
|
time_diff = time_new - time_old;
|
||
|
time_old = time_new;
|
||
|
|
||
|
/*
|
||
|
* CPU usage
|
||
|
*/
|
||
|
|
||
|
cpu_total = 0;
|
||
|
|
||
|
#if defined(dragonfly)
|
||
|
kinfo_get_sched_cputime(&cpu_new);
|
||
|
#define CP_UPDATE(field) cpu_diff.field = cpu_new.field - cpu_old.field; cpu_total += cpu_diff.field;
|
||
|
CP_UPDATE(cp_user);
|
||
|
CP_UPDATE(cp_nice);
|
||
|
CP_UPDATE(cp_sys);
|
||
|
CP_UPDATE(cp_intr);
|
||
|
CP_UPDATE(cp_idle);
|
||
|
cpu_old = cpu_new;
|
||
|
#undef CP_UPDATE
|
||
|
#else
|
||
|
auto_nlist(CPTIME_SYMBOL, (char *) cpu_new, sizeof(cpu_new));
|
||
|
|
||
|
for (loop = 0; loop < CPUSTATES; loop++) {
|
||
|
cpu_diff[loop] = cpu_new[loop] - cpu_old[loop];
|
||
|
cpu_old[loop] = cpu_new[loop];
|
||
|
cpu_total += cpu_diff[loop];
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (cpu_total == 0)
|
||
|
cpu_total = 1;
|
||
|
|
||
|
/*
|
||
|
* Memory info
|
||
|
*/
|
||
|
mem_old = mem_new;
|
||
|
auto_nlist(SUM_SYMBOL, (char *) &mem_new, sizeof(mem_new));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Rate macro
|
||
|
*/
|
||
|
#define rate(x) (((x)+ time_diff/2) / time_diff)
|
||
|
|
||
|
/*
|
||
|
* Page-to-kb macro
|
||
|
*/
|
||
|
#if defined(dragonfly)
|
||
|
#define ptok(p) ((p) * pagesize)
|
||
|
#else
|
||
|
#define ptok(p) ((p) * (mem_new.v_page_size >> 10))
|
||
|
#endif
|
||
|
|
||
|
switch (vp->magic) {
|
||
|
case MIBINDEX:
|
||
|
long_ret = 1;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case ERRORNAME: /* dummy name */
|
||
|
sprintf(errmsg, "systemStats");
|
||
|
*var_len = strlen(errmsg);
|
||
|
return ((u_char *) (errmsg));
|
||
|
case SWAPIN:
|
||
|
#if defined(openbsd2) || defined(darwin)
|
||
|
long_ret = ptok(mem_new.v_swpin - mem_old.v_swpin);
|
||
|
#else
|
||
|
long_ret = ptok(mem_new.v_swappgsin - mem_old.v_swappgsin +
|
||
|
mem_new.v_vnodepgsin - mem_old.v_vnodepgsin);
|
||
|
#endif
|
||
|
long_ret = rate(long_ret);
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case SWAPOUT:
|
||
|
#if defined(openbsd2) || defined(darwin)
|
||
|
long_ret = ptok(mem_new.v_swpout - mem_old.v_swpout);
|
||
|
#else
|
||
|
long_ret = ptok(mem_new.v_swappgsout - mem_old.v_swappgsout +
|
||
|
mem_new.v_vnodepgsout - mem_old.v_vnodepgsout);
|
||
|
#endif
|
||
|
long_ret = rate(long_ret);
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case IOSENT:
|
||
|
#if NETSNMP_NO_DUMMY_VALUES
|
||
|
return NULL;
|
||
|
#endif
|
||
|
long_ret = -1;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case IORECEIVE:
|
||
|
#if NETSNMP_NO_DUMMY_VALUES
|
||
|
return NULL;
|
||
|
#endif
|
||
|
long_ret = -1;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case SYSINTERRUPTS:
|
||
|
long_ret = rate(mem_new.v_intr - mem_old.v_intr);
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case SYSCONTEXT:
|
||
|
long_ret = rate(mem_new.v_swtch - mem_old.v_swtch);
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPUUSER:
|
||
|
#if defined(dragonfly)
|
||
|
cpu_sum = cpu_diff.cp_user + cpu_diff.cp_nice;
|
||
|
#else
|
||
|
cpu_sum = cpu_diff[CP_USER] + cpu_diff[CP_NICE];
|
||
|
#endif
|
||
|
cpu_prc = (float) cpu_sum / (float) cpu_total;
|
||
|
long_ret = cpu_prc * CPU_PRC;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPUSYSTEM:
|
||
|
#if defined(dragonfly)
|
||
|
cpu_sum = cpu_diff.cp_sys + cpu_diff.cp_intr;
|
||
|
#else
|
||
|
cpu_sum = cpu_diff[CP_SYS] + cpu_diff[CP_INTR];
|
||
|
#endif
|
||
|
cpu_prc = (float) cpu_sum / (float) cpu_total;
|
||
|
long_ret = cpu_prc * CPU_PRC;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPUIDLE:
|
||
|
#if defined(dragonfly)
|
||
|
cpu_sum = cpu_diff.cp_idle;
|
||
|
#else
|
||
|
cpu_sum = cpu_diff[CP_IDLE];
|
||
|
#endif
|
||
|
cpu_prc = (float) cpu_sum / (float) cpu_total;
|
||
|
long_ret = cpu_prc * CPU_PRC;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPURAWUSER:
|
||
|
#if defined(dragonfly)
|
||
|
long_ret = cpu_new.cp_user;
|
||
|
#else
|
||
|
long_ret = cpu_new[CP_USER];
|
||
|
#endif
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPURAWNICE:
|
||
|
#if defined(dragonfly)
|
||
|
long_ret = cpu_new.cp_nice;
|
||
|
#else
|
||
|
long_ret = cpu_new[CP_NICE];
|
||
|
#endif
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPURAWSYSTEM:
|
||
|
#if defined(dragonfly)
|
||
|
long_ret = cpu_new.cp_sys + cpu_new.cp_nice;
|
||
|
#else
|
||
|
long_ret = cpu_new[CP_SYS] + cpu_new[CP_INTR];
|
||
|
#endif
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPURAWIDLE:
|
||
|
#if defined(dragonfly)
|
||
|
long_ret = cpu_new.cp_idle;
|
||
|
#else
|
||
|
long_ret = cpu_new[CP_IDLE];
|
||
|
#endif
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPURAWKERNEL:
|
||
|
#if defined(dragonfly)
|
||
|
long_ret = cpu_new.cp_sys;
|
||
|
#else
|
||
|
long_ret = cpu_new[CP_SYS];
|
||
|
#endif
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case CPURAWINTR:
|
||
|
#if defined(dragonfly)
|
||
|
long_ret = cpu_new.cp_intr;
|
||
|
#else
|
||
|
long_ret = cpu_new[CP_INTR];
|
||
|
#endif
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case SYSRAWINTERRUPTS:
|
||
|
long_ret = mem_new.v_intr;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
case SYSRAWCONTEXT:
|
||
|
long_ret = mem_new.v_swtch;
|
||
|
return ((u_char *) (&long_ret));
|
||
|
/*
|
||
|
* reserved for future use
|
||
|
*/
|
||
|
/*
|
||
|
* case ERRORFLAG:
|
||
|
* return((u_char *) (&long_ret));
|
||
|
* case ERRORMSG:
|
||
|
* return((u_char *) (&long_ret));
|
||
|
*/
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|