summaryrefslogtreecommitdiff
path: root/agent/mibgroup/ucd-snmp/vmstat_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/ucd-snmp/vmstat_linux.c')
-rw-r--r--agent/mibgroup/ucd-snmp/vmstat_linux.c582
1 files changed, 582 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/vmstat_linux.c b/agent/mibgroup/ucd-snmp/vmstat_linux.c
new file mode 100644
index 0000000..d6eff50
--- /dev/null
+++ b/agent/mibgroup/ucd-snmp/vmstat_linux.c
@@ -0,0 +1,582 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <ctype.h>
+#include <signal.h>
+#if HAVE_MACHINE_PARAM_H
+#include <machine/param.h>
+#endif
+#if HAVE_SYS_VMMETER_H
+#if !defined(bsdi2) && !defined(netbsd1)
+#include <sys/vmmeter.h>
+#endif
+#endif
+#if HAVE_SYS_CONF_H
+#include <sys/conf.h>
+#endif
+#if HAVE_SYS_FS_H
+#include <sys/fs.h>
+#else
+#if HAVE_UFS_FS_H
+#include <ufs/fs.h>
+#else
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_VNODE_H
+#include <sys/vnode.h>
+#endif
+#ifdef HAVE_UFS_UFS_QUOTA_H
+#include <ufs/ufs/quota.h>
+#endif
+#ifdef HAVE_UFS_UFS_INODE_H
+#include <ufs/ufs/inode.h>
+#endif
+#if HAVE_UFS_FFS_FS_H
+#include <ufs/ffs/fs.h>
+#endif
+#endif
+#endif
+#if HAVE_MTAB_H
+#include <mtab.h>
+#endif
+#include <sys/stat.h>
+#include <errno.h>
+#if HAVE_FSTAB_H
+#include <fstab.h>
+#endif
+#if HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+#if HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#if (!defined(HAVE_STATVFS)) && defined(HAVE_STATFS)
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#if HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#define statvfs statfs
+#endif
+#if HAVE_VM_SWAP_PAGER_H
+#include <vm/swap_pager.h>
+#endif
+#if HAVE_SYS_FIXPOINT_H
+#include <sys/fixpoint.h>
+#endif
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <sys/utsname.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/cpu.h>
+
+#include "mibdefs.h"
+#include "struct.h"
+#include "util_funcs/header_generic.h"
+#include "vmstat.h"
+
+netsnmp_feature_require(hardware_cpu_load)
+
+
+FindVarMethod var_extensible_vmstat;
+
+static int has_vmstat = 1;
+static int has_cpu_26 = 1;
+static time_t cache_time;
+#define CACHE_TIMEOUT 5
+#define MAX_INT32 0x7fffffff
+#define MAX_COUNTER 0xffffffff
+
+#define STAT_FILE "/proc/stat"
+#define VMSTAT_FILE "/proc/vmstat"
+
+
+void
+init_vmstat(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}},
+ {RAWSWAPIN, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {RAWSWAPIN}},
+ {RAWSWAPOUT, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {RAWSWAPOUT}},
+ {IOSENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {IOSENT}},
+ {IORECEIVE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {IORECEIVE}},
+ {IORAWSENT, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {IORAWSENT}},
+ {IORAWRECEIVE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {IORAWRECEIVE}},
+ {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}},
+ {CPURAWKERNEL, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {CPURAWKERNEL}},
+ {CPURAWIDLE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {CPURAWIDLE}},
+ {SYSRAWINTERRUPTS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {SYSRAWINTERRUPTS}},
+ {SYSRAWCONTEXT, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {SYSRAWCONTEXT}},
+ {CPURAWWAIT, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {CPURAWWAIT}},
+ {CPURAWINTR, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {CPURAWINTR}},
+ {CPURAWSOFTIRQ, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
+ var_extensible_vmstat, 1, {CPURAWSOFTIRQ}},
+ /*
+ * 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);
+}
+
+
+static void
+getstat(unsigned long *cuse, unsigned long *cice, unsigned long *csys,
+ unsigned long *cide, unsigned *pin, unsigned *pout,
+ unsigned *swpin, unsigned *swpout, unsigned *itot, unsigned *i1,
+ unsigned *ct, unsigned long *ciow, unsigned long *cirq,
+ unsigned long *csoft)
+{
+ int statfd, vmstatfd;
+ static int first = 1;
+ static char *buff = NULL, *vmbuff = NULL;
+ static int bsize = 0, vmbsize = 0;
+ char *b, *c;
+ time_t now;
+ unsigned long long cpunum;
+ unsigned long long cusell = 0, cicell = 0, csysll = 0, cidell = 0,
+ ciowll = 0, cirqll = 0, csoftll = 0, ctll = 0, itotll = 0, i1ll = 0;
+
+ time(&now);
+ if (cache_time + CACHE_TIMEOUT < now) {
+ if ((statfd = open(STAT_FILE, O_RDONLY, 0)) == -1) {
+ snmp_log_perror(STAT_FILE);
+ return;
+ }
+ if (bsize == 0) {
+ bsize = 256;
+ buff = malloc(bsize);
+ }
+ while (read(statfd, buff, bsize) == bsize) {
+ bsize += 256;
+ buff = realloc(buff, bsize);
+ DEBUGMSGTL(("vmstat", "/proc/stat buffer increased to %d\n", bsize));
+ close(statfd);
+ statfd = open(STAT_FILE, O_RDONLY, 0);
+ }
+ close(statfd);
+
+ if (has_vmstat) {
+ vmstatfd = open(VMSTAT_FILE, O_RDONLY, 0);
+ if (vmstatfd == -1) {
+ snmp_log(LOG_ERR, "cannot open %s\n", VMSTAT_FILE);
+ has_vmstat = 0;
+ } else {
+ if (vmbsize == 0) {
+ vmbsize = 256;
+ vmbuff = malloc(vmbsize);
+ }
+ while (read(vmstatfd, vmbuff, vmbsize) == vmbsize) {
+ vmbsize += 256;
+ vmbuff = realloc(vmbuff, vmbsize);
+ close(vmstatfd);
+ vmstatfd = open(VMSTAT_FILE, O_RDONLY, 0);
+ }
+ close(vmstatfd);
+ }
+ }
+ cache_time = now;
+ }
+
+ *itot = 0;
+ *i1 = 1;
+ c = buff;
+ while ((c = strstr(c+1, "cpu")) != NULL)
+ b = c;
+ sscanf(b, "cpu%llu", &cpunum);
+ cpunum++;
+ b = strstr(buff, "cpu ");
+ if (b) {
+ if (!has_cpu_26 ||
+ sscanf(b, "cpu %llu %llu %llu %llu %llu %llu %llu", &cusell,
+ &cicell, &csysll, &cidell, &ciowll, &cirqll, &csoftll) != 7) {
+ has_cpu_26 = 0;
+ sscanf(b, "cpu %llu %llu %llu %llu", &cusell, &cicell, &csysll,
+ &cidell);
+ *ciow = *cirq = *csoft = 0;
+ } else {
+ *ciow = (unsigned long)(ciowll/cpunum);
+ *cirq = (unsigned long)(cirqll/cpunum);
+ *csoft = (unsigned long)(csoftll/cpunum);
+ }
+ *cuse = (unsigned long)(cusell/cpunum);
+ *cice = (unsigned long)(cicell/cpunum);
+ *csys = (unsigned long)(csysll/cpunum);
+ *cide = (unsigned long)(cidell/cpunum);
+
+ }
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No cpu line in %s\n", STAT_FILE);
+ *cuse = *cice = *csys = *cide = *ciow = *cirq = *csoft = 0;
+ }
+ if (has_vmstat) {
+ b = strstr(vmbuff, "pgpgin ");
+ if (b)
+ sscanf(b, "pgpgin %u", pin);
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No pgpgin line in %s\n", VMSTAT_FILE);
+ *pin = 0;
+ }
+ b = strstr(vmbuff, "pgpgout ");
+ if (b)
+ sscanf(b, "pgpgout %u", pout);
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No pgpgout line in %s\n", VMSTAT_FILE);
+ *pout = 0;
+ }
+ b = strstr(vmbuff, "pswpin ");
+ if (b)
+ sscanf(b, "pswpin %u", swpin);
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No pswpin line in %s\n", VMSTAT_FILE);
+ *swpin = 0;
+ }
+ b = strstr(vmbuff, "pswpout ");
+ if (b)
+ sscanf(b, "pswpout %u", swpout);
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No pswpout line in %s\n", VMSTAT_FILE);
+ *swpout = 0;
+ }
+ }
+ else {
+ b = strstr(buff, "page ");
+ if (b)
+ sscanf(b, "page %u %u", pin, pout);
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No page line in %s\n", STAT_FILE);
+ *pin = *pout = 0;
+ }
+ b = strstr(buff, "swap ");
+ if (b)
+ sscanf(b, "swap %u %u", swpin, swpout);
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No swap line in %s\n", STAT_FILE);
+ *swpin = *swpout = 0;
+ }
+ }
+ b = strstr(buff, "intr ");
+ if (b) {
+ sscanf(b, "intr %llu %llu", &itotll, &i1ll);
+ *itot = (unsigned)itotll;
+ *i1 = (unsigned)i1ll;
+ }
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No intr line in %s\n", STAT_FILE);
+ *itot = 0;
+ }
+ b = strstr(buff, "ctxt ");
+ if (b) {
+ sscanf(b, "ctxt %llu", &ctll);
+ *ct = (unsigned long)ctll;
+ }
+ else {
+ if (first)
+ snmp_log(LOG_ERR, "No ctxt line in %s\n", STAT_FILE);
+ *ct = 0;
+ }
+ first = 0;
+}
+
+enum vmstat_index { swapin = 0, swapout,
+ rawswapin, rawswapout,
+ iosent, ioreceive,
+ rawiosent, rawioreceive,
+ sysinterrupts, syscontext,
+ cpuuser, cpusystem, cpuidle,
+ cpurawuser, cpurawnice,
+ cpurawsystem, cpurawidle,
+ cpurawinter, cpurawsoft, cpurawwait,
+ rawinterrupts, rawcontext
+};
+
+static unsigned
+vmstat(int iindex)
+{
+ double duse, dsys, didl, ddiv, divo2;
+ double druse, drnic, drsys, dridl;
+ unsigned int hertz;
+ double ddiv2;
+
+ netsnmp_cpu_info *cpu;
+ netsnmp_cpu_load();
+ cpu = netsnmp_cpu_get_byIdx( -1, 0 );
+
+ duse = cpu->user_ticks + cpu->nice_ticks;
+ dsys = cpu->sys_ticks;
+ didl = cpu->idle_ticks;
+ ddiv = duse + dsys + didl;
+ hertz = sysconf(_SC_CLK_TCK); /* get ticks/s from system */
+ divo2 = ddiv / 2;
+ druse = cpu->user_ticks;
+ drnic = cpu->nice_ticks;
+ drsys = cpu->sys_ticks;
+ dridl = cpu->idle_ticks;
+
+ ddiv2 = ddiv + cpu->wait_ticks
+ + cpu->intrpt_ticks
+ + cpu->sirq_ticks;
+ if (cpu->history) {
+ duse -= (cpu->history[0].user_hist + cpu->history[0].nice_hist);
+ dsys -= cpu->history[0].sys_hist;
+ didl -= cpu->history[0].idle_hist;
+ ddiv2 -= cpu->history[0].total_hist;
+ }
+ if (!ddiv) ddiv=1; /* Protect against division-by-0 */
+
+ switch (iindex) {
+ case swapin:
+ return (cpu->swapIn * 4 * hertz + divo2) / ddiv;
+ case swapout:
+ return (cpu->swapOut * 4 * hertz + divo2) / ddiv;
+ case iosent:
+ return (cpu->pageIn * hertz + divo2) / ddiv;
+ case ioreceive:
+ return (cpu->pageOut * hertz + divo2) / ddiv;
+ case sysinterrupts:
+ return (cpu->nInterrupts * hertz + divo2) / ddiv;
+ case syscontext:
+ return (cpu->nCtxSwitches * hertz + divo2) / ddiv;
+ case cpuuser:
+ return (ddiv2 ? 100 * duse / ddiv2 : 0);
+ case cpusystem:
+ return (ddiv2 ? 100 * dsys / ddiv2 : 0);
+ case cpuidle:
+ return (ddiv2 ? 100 * didl / ddiv2 : 0);
+ case cpurawuser:
+ return druse;
+ case cpurawnice:
+ return drnic;
+ case cpurawsystem:
+ return drsys;
+ case cpurawidle:
+ return dridl;
+ case rawinterrupts:
+ return cpu->nInterrupts;
+ case rawcontext:
+ return cpu->nCtxSwitches;
+ case cpurawwait:
+ return cpu->wait_ticks;
+ case cpurawinter:
+ return cpu->intrpt_ticks;
+ case cpurawsoft:
+ return cpu->sirq_ticks;
+ case rawiosent:
+ return cpu->pageOut*2;
+ case rawioreceive:
+ return cpu->pageIn*2;
+ case rawswapin:
+ return cpu->swapIn;
+ case rawswapout:
+ return cpu->swapOut;
+ default:
+ return -1;
+ }
+}
+
+unsigned char *
+var_extensible_vmstat(struct variable *vp,
+ oid * name,
+ size_t * length,
+ int exact,
+ size_t * var_len, WriteMethod ** write_method)
+{
+
+ static long long_ret;
+ static char errmsg[300];
+
+ long_ret = 0; /* set to 0 as default */
+
+ if (header_generic(vp, name, length, exact, var_len, write_method))
+ return (NULL);
+ 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:
+ long_ret = vmstat(swapin) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case SWAPOUT:
+ long_ret = vmstat(swapout) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case RAWSWAPIN:
+ long_ret = vmstat(rawswapin) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case RAWSWAPOUT:
+ long_ret = vmstat(rawswapout) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case IOSENT:
+ long_ret = vmstat(iosent) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case IORECEIVE:
+ long_ret = vmstat(ioreceive) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case IORAWSENT:
+ long_ret = vmstat(rawiosent) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case IORAWRECEIVE:
+ long_ret = vmstat(rawioreceive) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case SYSINTERRUPTS:
+ long_ret = vmstat(sysinterrupts) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case SYSCONTEXT:
+ long_ret = vmstat(syscontext) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case CPUUSER:
+ long_ret = vmstat(cpuuser) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case CPUSYSTEM:
+ long_ret = vmstat(cpusystem) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case CPUIDLE:
+ long_ret = vmstat(cpuidle) & MAX_INT32;
+ return ((u_char *) (&long_ret));
+ case CPURAWUSER:
+ long_ret = vmstat(cpurawuser) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case CPURAWNICE:
+ long_ret = vmstat(cpurawnice) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case CPURAWSYSTEM:
+ long_ret = (vmstat(cpurawsystem)+vmstat(cpurawinter)+vmstat(cpurawsoft)) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case CPURAWKERNEL:
+ long_ret = vmstat(cpurawsystem) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case CPURAWIDLE:
+ long_ret = vmstat(cpurawidle) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case SYSRAWINTERRUPTS:
+ long_ret = vmstat(rawinterrupts) & MAX_COUNTER;
+ return (u_char *)&long_ret;
+ case SYSRAWCONTEXT:
+ long_ret = vmstat(rawcontext) & MAX_COUNTER;
+ return (u_char *)&long_ret;
+ case CPURAWWAIT:
+ if (!has_cpu_26) return NULL;
+ long_ret = vmstat(cpurawwait) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case CPURAWINTR:
+ if (!has_cpu_26) return NULL;
+ long_ret = vmstat(cpurawinter) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+ case CPURAWSOFTIRQ:
+ if (!has_cpu_26) return NULL;
+ long_ret = vmstat(cpurawsoft) & MAX_COUNTER;
+ return ((u_char *) (&long_ret));
+
+ /*
+ * reserved for future use
+ */
+ /*
+ * case ERRORFLAG:
+ * return((u_char *) (&long_ret));
+ * case ERRORMSG:
+ * return((u_char *) (&long_ret));
+ */
+ default:
+ snmp_log(LOG_ERR, "vmstat.c: don't know how to handle %d request\n",
+ vp->magic);
+ }
+ return NULL;
+}