diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-12-08 11:34:56 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-12-08 11:34:56 +0000 |
commit | 3a6a7e7922c54721a12118e1135eaf0940d728ec (patch) | |
tree | 7859bb68fe6ab68653bf943278dae14a5274a84c /usr.sbin/snmpd | |
parent | bfc97caf3472bc8f39ea1da77fd452a8dfc90b94 (diff) |
report memory and swap in hrStorage, and implement hrProcessor to report
hrProcessorLoad (where load means the percentage of time the system was
not idle during the last minute). based on HOST-RESOURCES-MIB.
ok dlg@
Diffstat (limited to 'usr.sbin/snmpd')
-rw-r--r-- | usr.sbin/snmpd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/snmpd/mib.c | 217 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpd.h | 8 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpe.c | 3 | ||||
-rw-r--r-- | usr.sbin/snmpd/timer.c | 171 |
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); +} |