summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/snmpd/Makefile4
-rw-r--r--usr.sbin/snmpd/mib.c217
-rw-r--r--usr.sbin/snmpd/snmpd.h8
-rw-r--r--usr.sbin/snmpd/snmpe.c3
-rw-r--r--usr.sbin/snmpd/timer.c171
5 files changed, 381 insertions, 22 deletions
diff --git a/usr.sbin/snmpd/Makefile b/usr.sbin/snmpd/Makefile
index b09519cfb13..78a89b6efa0 100644
--- a/usr.sbin/snmpd/Makefile
+++ b/usr.sbin/snmpd/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.4 2008/01/16 09:42:29 reyk Exp $
+# $OpenBSD: Makefile,v 1.5 2008/12/08 11:34:55 reyk Exp $
PROG= snmpd
MAN= snmpd.8 snmpd.conf.5
SRCS= parse.y ber.c log.c control.c buffer.c imsg.c snmpe.c \
- mps.c trap.c mib.c smi.c kroute.c snmpd.c
+ mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c
LDADD= -levent
DPADD= ${LIBEVENT}
diff --git a/usr.sbin/snmpd/mib.c b/usr.sbin/snmpd/mib.c
index dc7ab8b1d8f..ab754351388 100644
--- a/usr.sbin/snmpd/mib.c
+++ b/usr.sbin/snmpd/mib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mib.c,v 1.27 2008/03/18 16:57:58 reyk Exp $ */
+/* $OpenBSD: mib.c,v 1.28 2008/12/08 11:34:55 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net>
@@ -26,6 +26,7 @@
#include <sys/utsname.h>
#include <sys/sysctl.h>
#include <sys/sensors.h>
+#include <sys/sched.h>
#include <sys/mount.h>
#include <net/if.h>
@@ -323,6 +324,8 @@ mib_setsnmp(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
int mib_hrmemory(struct oid *, struct ber_oid *, struct ber_element **);
int mib_hrstorage(struct oid *, struct ber_oid *, struct ber_element **);
+int mib_hrdevice(struct oid *, struct ber_oid *, struct ber_element **);
+int mib_hrprocessor(struct oid *, struct ber_oid *, struct ber_element **);
int mib_hrswrun(struct oid *, struct ber_oid *, struct ber_element **);
int kinfo_proc_comp(const void *, const void *);
@@ -331,7 +334,6 @@ int kinfo_args(struct kinfo_proc2 *, char **);
static struct oid hr_mib[] = {
{ MIB(host), OID_MIB },
- { MIB(hrStorage), OID_MIB },
{ MIB(hrMemorySize), OID_RD, mib_hrmemory },
{ MIB(hrStorageIndex), OID_TRD, mib_hrstorage },
{ MIB(hrStorageType), OID_TRD, mib_hrstorage },
@@ -340,7 +342,14 @@ static struct oid hr_mib[] = {
{ MIB(hrStorageSize), OID_TRD, mib_hrstorage },
{ MIB(hrStorageUsed), OID_TRD, mib_hrstorage },
{ MIB(hrStorageAllocationFailures), OID_TRD, mib_hrstorage },
- { MIB(hrSWRun), OID_MIB },
+ { MIB(hrDeviceIndex), OID_TRD, mib_hrdevice },
+ { MIB(hrDeviceType), OID_TRD, mib_hrdevice },
+ { MIB(hrDeviceDescr), OID_TRD, mib_hrdevice },
+ { MIB(hrDeviceID), OID_TRD, mib_hrdevice },
+ { MIB(hrDeviceStatus), OID_TRD, mib_hrdevice },
+ { MIB(hrDeviceErrors), OID_TRD, mib_hrdevice },
+ { MIB(hrProcessorFrwID), OID_TRD, mib_hrprocessor },
+ { MIB(hrProcessorLoad), OID_TRD, mib_hrprocessor },
{ MIB(hrSWRunIndex), OID_TRD, mib_hrswrun },
{ MIB(hrSWRunName), OID_TRD, mib_hrswrun },
{ MIB(hrSWRunID), OID_TRD, mib_hrswrun },
@@ -371,48 +380,179 @@ int
mib_hrstorage(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
{
struct ber_element *ber = *elm;
- static struct ber_oid so = { { MIB_hrStorageFixedDisk } };
u_int32_t idx;
struct statfs *mntbuf, *mnt;
- int mntsize;
+ int mntsize, maxsize;
+ u_int32_t units, size, used, fail = 0;
+ const char *descr = NULL;
+ int mib[] = { CTL_HW, 0 };
+ u_int64_t physmem, realmem;
+ struct uvmexp uvm;
+ struct vmtotal vm;
+ size_t len;
+ static struct ber_oid *sop, so[] = {
+ { { MIB_hrStorageOther } },
+ { { MIB_hrStorageRam } },
+ { { MIB_hrStorageVirtualMemory } },
+ { { MIB_hrStorageFixedDisk } }
+ };
- mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
- if (mntsize == 0)
+ /* Physical memory, real memory, swap */
+ mib[1] = HW_PHYSMEM64;
+ len = sizeof(physmem);
+ if (sysctl(mib, sizeofa(mib), &physmem, &len, NULL, 0) == -1)
+ return (-1);
+ mib[1] = HW_USERMEM64;
+ len = sizeof(realmem);
+ if (sysctl(mib, sizeofa(mib), &realmem, &len, NULL, 0) == -1)
return (-1);
+ mib[0] = CTL_VM;
+ mib[1] = VM_UVMEXP;
+ len = sizeof(uvm);
+ if (sysctl(mib, sizeofa(mib), &uvm, &len, NULL, 0) == -1)
+ return (-1);
+ mib[1] = VM_METER;
+ len = sizeof(vm);
+ if (sysctl(mib, sizeofa(mib), &vm, &len, NULL, 0) == -1)
+ return (-1);
+ maxsize = 10;
- /* Get and verify the current row index */
+ /* Disks */
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ if (mntsize)
+ maxsize = 30 + mntsize;
+
+ /*
+ * Get and verify the current row index.
+ *
+ * We use a special mapping here that is inspired by other SNMP
+ * agents: index 1 + 2 for RAM, index 10 for swap, index 31 and
+ * higher for disk storage.
+ */
idx = o->bo_id[OIDIDX_hrStorageEntry];
- if ((int)idx > mntsize)
+ if (idx > (u_int)maxsize)
return (1);
+ else if (idx > 2 && idx < 10)
+ idx = 10;
+ else if (idx > 10 && idx < 31)
+ idx = 31;
+
+ sop = &so[0];
+ switch (idx) {
+ case 1:
+ descr = "Physical memory";
+ units = uvm.pagesize;
+ size = physmem / uvm.pagesize;
+ used = size - vm.t_free;
+ sop = &so[1];
+ break;
+ case 2:
+ descr = "Real memory";
+ units = uvm.pagesize;
+ size = realmem / uvm.pagesize;
+ used = size - uvm.free;
+ sop = &so[1];
+ break;
+ case 10:
+ descr = "Swap space";
+ units = uvm.pagesize;
+ size = uvm.swpages;
+ used = uvm.swpginuse;
+ sop = &so[2];
+ break;
+ default:
+ mnt = &mntbuf[idx - 31];
+ descr = mnt->f_mntonname;
+ units = mnt->f_bsize;
+ size = mnt->f_blocks;
+ used = mnt->f_blocks - mnt->f_bfree;
+ sop = &so[3];
+ break;
+ }
/* Tables need to prepend the OID on their own */
o->bo_id[OIDIDX_hrStorageEntry] = idx;
ber = ber_add_oid(ber, o);
- mnt = &mntbuf[idx - 1];
-
switch (o->bo_id[OIDIDX_hrStorage]) {
case 1: /* hrStorageIndex */
ber = ber_add_integer(ber, idx);
break;
case 2: /* hrStorageType */
- smi_oidlen(&so);
- ber = ber_add_oid(ber, &so);
+ smi_oidlen(sop);
+ ber = ber_add_oid(ber, sop);
break;
case 3: /* hrStorageDescr */
- ber = ber_add_string(ber, mnt->f_mntonname);
+ ber = ber_add_string(ber, descr);
break;
case 4: /* hrStorageAllocationUnits */
- ber = ber_add_integer(ber, mnt->f_bsize);
+ ber = ber_add_integer(ber, units);
break;
case 5: /* hrStorageSize */
- ber = ber_add_integer(ber, mnt->f_blocks);
+ ber = ber_add_integer(ber, size);
break;
case 6: /* hrStorageUsed */
- ber = ber_add_integer(ber, mnt->f_blocks - mnt->f_bfree);
+ ber = ber_add_integer(ber, used);
break;
case 7: /* hrStorageAllocationFailures */
- ber = ber_add_integer(ber, 0);
+ ber = ber_add_integer(ber, fail);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+mib_hrdevice(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
+{
+ struct ber_element *ber = *elm;
+ u_int32_t idx, fail = 0;
+ int status;
+ int mib[] = { CTL_HW, HW_MODEL };
+ size_t len;
+ char descr[BUFSIZ];
+ static struct ber_oid *sop, so[] = {
+ { { MIB_hrDeviceProcessor } },
+ };
+
+ /* Get and verify the current row index */
+ idx = o->bo_id[OIDIDX_hrDeviceEntry];
+ if (idx > (u_int)env->sc_ncpu)
+ return (1);
+
+ /* Tables need to prepend the OID on their own */
+ o->bo_id[OIDIDX_hrDeviceEntry] = idx;
+ ber = ber_add_oid(ber, o);
+
+ len = sizeof(descr);
+ if (sysctl(mib, sizeofa(mib), &descr, &len, NULL, 0) == -1)
+ return (-1);
+ /* unknown(1), running(2), warning(3), testing(4), down(5) */
+ status = 2;
+ sop = &so[0];
+
+ switch (o->bo_id[OIDIDX_hrDevice]) {
+ case 1: /* hrDeviceIndex */
+ ber = ber_add_integer(ber, idx);
+ break;
+ case 2: /* hrDeviceType */
+ smi_oidlen(sop);
+ ber = ber_add_oid(ber, sop);
+ break;
+ case 3: /* hrDeviceDescr */
+ ber = ber_add_string(ber, descr);
+ break;
+ case 4: /* hrDeviceID */
+ ber = ber_add_oid(ber, &zerodotzero);
+ break;
+ case 5: /* hrDeviceStatus */
+ ber = ber_add_integer(ber, status);
+ break;
+ case 6: /* hrDeviceErrors */
+ ber = ber_add_integer(ber, fail);
ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
break;
default:
@@ -423,6 +563,47 @@ mib_hrstorage(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
}
int
+mib_hrprocessor(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
+{
+ struct ber_element *ber = *elm;
+ u_int32_t idx;
+ int64_t *cptime2, val;
+
+ /* Get and verify the current row index */
+ idx = o->bo_id[OIDIDX_hrDeviceEntry];
+ if (idx > (u_int)env->sc_ncpu)
+ return (1);
+ else if (idx < 1)
+ idx = 1;
+
+ /* Tables need to prepend the OID on their own */
+ o->bo_id[OIDIDX_hrDeviceEntry] = idx;
+ ber = ber_add_oid(ber, o);
+
+ switch (o->bo_id[OIDIDX_hrDevice]) {
+ case 1: /* hrProcessorFrwID */
+ ber = ber_add_oid(ber, &zerodotzero);
+ break;
+ case 2: /* hrProcessorLoad */
+ /*
+ * The percentage of time that the system was not
+ * idle during the last minute.
+ */
+ if (env->sc_cpustates == NULL)
+ return (-1);
+ cptime2 = env->sc_cpustates + (CPUSTATES * (idx - 1));
+ val = 100 -
+ (cptime2[CP_IDLE] > 1000 ? 1000 : (cptime2[CP_IDLE] / 10));
+ ber = ber_add_integer(ber, val);
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
mib_hrswrun(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
{
struct ber_element *ber = *elm;
diff --git a/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h
index 36960ba50a3..6e2b7a8b4d8 100644
--- a/usr.sbin/snmpd/snmpd.h
+++ b/usr.sbin/snmpd/snmpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpd.h,v 1.21 2008/09/26 15:19:55 reyk Exp $ */
+/* $OpenBSD: snmpd.h,v 1.22 2008/12/08 11:34:55 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net>
@@ -334,6 +334,9 @@ struct snmpd {
struct snmp_stats sc_stats;
struct addresslist sc_trapreceivers;
+
+ int sc_ncpu;
+ int64_t *sc_cpustates;
};
/* control.c */
@@ -441,6 +444,9 @@ void smi_delete(struct oid *);
void smi_insert(struct oid *);
int smi_oid_cmp(struct oid *, struct oid *);
+/* timer.c */
+void timer_init(void);
+
/* snmpd.c */
int snmpd_socket_af(struct sockaddr_storage *, in_port_t);
diff --git a/usr.sbin/snmpd/snmpe.c b/usr.sbin/snmpd/snmpe.c
index 8ffb32b5575..2b671a6a162 100644
--- a/usr.sbin/snmpd/snmpe.c
+++ b/usr.sbin/snmpd/snmpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpe.c,v 1.22 2008/12/05 12:34:01 reyk Exp $ */
+/* $OpenBSD: snmpe.c,v 1.23 2008/12/08 11:34:55 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net>
@@ -160,6 +160,7 @@ snmpe(struct snmpd *x_env, int pipe_parent2snmpe[2])
kr_init();
trap_init();
+ timer_init();
event_dispatch();
diff --git a/usr.sbin/snmpd/timer.c b/usr.sbin/snmpd/timer.c
new file mode 100644
index 00000000000..605ca92ba49
--- /dev/null
+++ b/usr.sbin/snmpd/timer.c
@@ -0,0 +1,171 @@
+/* $OpenBSD: timer.c,v 1.1 2008/12/08 11:34:55 reyk Exp $ */
+
+/*
+ * Copyright (c) 2008 Reyk Floeter <reyk@vantronix.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sched.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "snmpd.h"
+#include "mib.h"
+
+extern struct snmpd *env;
+
+void timer_cpu(int, short, void *);
+int percentages(int, int64_t *, int64_t *, int64_t *, int64_t *);
+
+static int64_t **cp_time;
+static int64_t **cp_old;
+static int64_t **cp_diff;
+struct event cpu_ev;
+
+void
+timer_cpu(int fd, short event, void *arg)
+{
+ struct event *ev = (struct event *)arg;
+ struct timeval tv = { 60, 0 }; /* every 60 seconds */
+ int mib[3] = { CTL_KERN, KERN_CPTIME2, 0 }, n;
+ size_t len;
+ int64_t *cptime2;
+
+ len = CPUSTATES * sizeof(int64_t);
+ for (n = 0; n < env->sc_ncpu; n++) {
+ mib[2] = n;
+ cptime2 = env->sc_cpustates + (CPUSTATES * n);
+ if (sysctl(mib, 3, cp_time[n], &len, NULL, 0) == -1)
+ continue;
+ (void)percentages(CPUSTATES, cptime2, cp_time[n],
+ cp_old[n], cp_diff[n]);
+#ifdef DEBUG
+ log_debug("timer_cpu: cpu%d %d%% idle in %ds", n,
+ (cptime2[CP_IDLE] > 1000 ?
+ 1000 : (cptime2[CP_IDLE] / 10)), tv.tv_sec);
+#endif
+ }
+
+ evtimer_add(ev, &tv);
+}
+
+void
+timer_init(void)
+{
+ int mib[] = { CTL_HW, HW_NCPU }, i;
+ size_t len;
+
+ len = sizeof(env->sc_ncpu);
+ if (sysctl(mib, 2, &env->sc_ncpu, &len, NULL, 0) == -1)
+ fatal("sysctl");
+
+ env->sc_cpustates = calloc(env->sc_ncpu, CPUSTATES * sizeof(int64_t));
+ cp_time = calloc(env->sc_ncpu, sizeof(int64_t *));
+ cp_old = calloc(env->sc_ncpu, sizeof(int64_t *));
+ cp_diff = calloc(env->sc_ncpu, sizeof(int64_t *));
+ if (env->sc_cpustates == NULL ||
+ cp_time == NULL || cp_old == NULL || cp_diff == NULL)
+ fatal("calloc");
+ for (i = 0; i < env->sc_ncpu; i++) {
+ cp_time[i] = calloc(CPUSTATES, sizeof(int64_t));
+ cp_old[i] = calloc(CPUSTATES, sizeof(int64_t));
+ cp_diff[i] = calloc(CPUSTATES, sizeof(int64_t));
+ if (cp_time[i] == NULL || cp_old[i] == NULL ||
+ cp_diff[i] == NULL)
+ fatal("calloc");
+ }
+
+ evtimer_set(&cpu_ev, timer_cpu, &cpu_ev);
+ timer_cpu(0, EV_TIMEOUT, &cpu_ev);
+}
+
+/*
+ * percentages() function to calculate CPU utilization.
+ * Source code derived from the top(1) utility:
+ *
+ * Copyright (c) 1984, 1989, William LeFebvre, Rice University
+ * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+int
+percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs)
+{
+ int64_t change, total_change, *dp, half_total;
+ int i;
+
+ /* initialization */
+ total_change = 0;
+ dp = diffs;
+
+ /* calculate changes for each state and the overall change */
+ for (i = 0; i < cnt; i++) {
+ if ((change = *new - *old) < 0) {
+ /* this only happens when the counter wraps */
+ change = (*new - *old);
+ }
+ total_change += (*dp++ = change);
+ *old++ = *new++;
+ }
+
+ /* avoid divide by zero potential */
+ if (total_change == 0)
+ total_change = 1;
+
+ /* calculate percentages based on overall change, rounding up */
+ half_total = total_change / 2l;
+ for (i = 0; i < cnt; i++)
+ *out++ = ((*diffs++ * 1000 + half_total) / total_change);
+
+ /* return the total in case the caller wants to use it */
+ return (total_change);
+}