diff options
| -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); +} |
