The diff below is the next rev of my earlier UCD-SNMP-MIB diff. It fixes some mistakes in the MIB declaration/naming, implements laConfig as a read-write value, and adds the systemState section of the MIB. It does not implement the "cooked" 1-minute-average values in systemState, just the ss*Raw* values, since the cooked values are all marked as being deprecated in the MIB anyway.
I wasn't quite sure of how to implement laConfig's state. If my approach below was wrong, please let me know a better way and I'll fix it. Thanks, Seth Index: mib.c =================================================================== RCS file: /home/seth/code/obsd/cvsync/src/usr.sbin/snmpd/mib.c,v retrieving revision 1.55 diff -u -p -r1.55 mib.c --- mib.c 19 Jun 2012 18:43:27 -0000 1.55 +++ mib.c 24 Jun 2012 05:25:31 -0000 @@ -3364,6 +3364,361 @@ mib_ipfroute(struct oid *oid, struct ber } /* + * Defined in UCD-SNMP-MIB.txt + */ + +int mib_ucdmemory(struct oid *oid, struct ber_oid *o, struct ber_element **elm); +int mib_ucdloadTable(struct oid *oid, struct ber_oid *o, struct ber_element **elm); +int mib_setlaconfig(struct oid *oid, struct ber_oid *o, struct ber_element **elm); +int mib_ucdsystemStats(struct oid *oid, struct ber_oid *o, struct ber_element **elm); + +static struct oid ucdsnmp_mib[] = { + { MIB(ucDavis), OID_MIB }, + { MIB(memIndex), OID_RD, mib_ucdmemory }, + { MIB(memErrorName), OID_RD, mib_ucdmemory }, + { MIB(memTotalSwap), OID_RD, mib_ucdmemory }, + { MIB(memAvailSwap), OID_RD, mib_ucdmemory }, + { MIB(memTotalReal), OID_RD, mib_ucdmemory }, + { MIB(memAvailReal), OID_RD, mib_ucdmemory }, + { MIB(memTotalFree), OID_RD, mib_ucdmemory }, + { MIB(memMinimumSwap), OID_RD, mib_ucdmemory }, + { MIB(memShared), OID_RD, mib_ucdmemory }, + { MIB(memBuffer), OID_RD, mib_ucdmemory }, + { MIB(memCached), OID_RD, mib_ucdmemory }, + { MIB(memSwapError), OID_RD, mib_ucdmemory }, + { MIB(memSwapErrorMsg), OID_RD, mib_ucdmemory }, + { MIB(laIndex), OID_TRD, mib_ucdloadTable }, + { MIB(laNames), OID_TRD, mib_ucdloadTable }, + { MIB(laLoad), OID_TRD, mib_ucdloadTable }, + { MIB(laConfig), OID_TRW, mib_ucdloadTable, + mib_setlaconfig }, + { MIB(laLoadInt), OID_TRD, mib_ucdloadTable }, + { MIB(laErrorFlag), OID_TRD, mib_ucdloadTable }, + { MIB(laErrMessage), OID_TRD, mib_ucdloadTable }, + { MIB(ssIndex), OID_RD, mib_ucdsystemStats }, + { MIB(ssErrorName), OID_RD, mib_ucdsystemStats }, + { MIB(ssCpuRawUser), OID_RD, mib_ucdsystemStats }, + { MIB(ssCpuRawNice), OID_RD, mib_ucdsystemStats }, + { MIB(ssCpuRawSystem), OID_RD, mib_ucdsystemStats }, + { MIB(ssCpuRawIdle), OID_RD, mib_ucdsystemStats }, + { MIB(ssCpuRawKernel), OID_RD, mib_ucdsystemStats }, + { MIB(ssCpuRawInterrupt), OID_RD, mib_ucdsystemStats }, + { MIB(ssIORawSent), OID_RD, mib_ucdsystemStats }, + { MIB(ssIORawReceived), OID_RD, mib_ucdsystemStats }, + { MIB(ssRawInterrupts), OID_RD, mib_ucdsystemStats }, + { MIB(ssRawContexts), OID_RD, mib_ucdsystemStats }, + { MIB(ssRawSwapIn), OID_RD, mib_ucdsystemStats }, + { MIB(ssRawSwapOut), OID_RD, mib_ucdsystemStats }, + { MIBEND } +}; + +/* Taken from net-snmp */ +#define DEFAULTMINIMUMSWAP 16000 +#define ptok(p) ((p) * (uvm.pagesize >> 10)) + +int +mib_ucdmemory(struct oid *oid, struct ber_oid *o, struct ber_element **elm) +{ + struct ber_element *ber = *elm; + struct bcachestats bcstats; + struct uvmexp uvm; + struct vmtotal vmmeter; + u_int64_t physmem; + size_t len; + int mib[] = { CTL_VM, VM_UVMEXP }; + int bcstats_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT }; + int size, inuse, total; + + len = sizeof(uvm); + if (sysctl(mib, sizeofa(mib), &uvm, &len, NULL, 0) == -1) + return (-1); + + mib[1] = VM_METER; + len = sizeof(vmmeter); + if (sysctl(mib, sizeofa(mib), &vmmeter, &len, NULL, 0) == -1) + return (-1); + + mib[0] = CTL_HW; + mib[1] = HW_PHYSMEM64; + len = sizeof(physmem); + if (sysctl(mib, sizeofa(mib), &physmem, &len, NULL, 0) == -1) + return (-1); + + len = sizeof(bcstats); + if (sysctl(bcstats_mib, sizeofa(bcstats_mib), &bcstats, &len, NULL, 0) == -1) + return (-1); + + switch (o->bo_id[OIDIDX_memory]) { + case 1: /* memIndex */ + ber = ber_add_integer(ber, 0); + break; + case 2: /* memErrorName */ + ber = ber_add_string(ber, "swap"); + break; + case 3: /* memTotalSwap */ + size = ptok(uvm.swpages); + ber = ber_add_integer(ber, size); + break; + case 4: /* memAvailSwap */ + inuse = ptok(uvm.swpginuse); + total = ptok(uvm.swpages); + ber = ber_add_integer(ber, total - inuse); + break; + case 5: /* memTotalReal */ + size = physmem >> 10; + ber = ber_add_integer(ber, size); + break; + case 6: /* memAvailReal */ + ber = ber_add_integer(ber, ptok(uvm.free)); + break; + case 11: /* memTotalFree */ + total = ptok(uvm.free + uvm.swpages - uvm.swpginuse); + ber = ber_add_integer(ber, total); + break; + case 12: /* memMinimumSwap */ + ber = ber_add_integer(ber, DEFAULTMINIMUMSWAP); + break; + case 13: /* memShared */ + total = ptok(vmmeter.t_vmshr + vmmeter.t_avmshr + + vmmeter.t_rmshr + vmmeter.t_armshr); + ber = ber_add_integer(ber, total); + break; + case 14: /* memBuffer */ + ber = ber_add_integer(ber, ptok(uvm.vnodepages)); + break; + case 15: /* memCached */ + ber = ber_add_integer(ber, ptok(bcstats.numbufpages)); + break; + case 100: /* memSwapError */ + inuse = ptok(uvm.swpginuse); + total = ptok(uvm.swpages); + if ((total - inuse) < DEFAULTMINIMUMSWAP) + ber = ber_add_integer(ber, 1); + else + ber = ber_add_integer(ber, 0); + break; + case 101: /* memSwapErrorMsg */ + inuse = ptok(uvm.swpginuse); + total = ptok(uvm.swpages); + if ((total - inuse) < DEFAULTMINIMUMSWAP) + ber = ber_add_string(ber, "Running out of swap space"); + else + ber = ber_add_string(ber, ""); + break; + default: + return (-1); + } + + return (0); +} + +/* values taken from net-snmp's default config */ +static double laconfig[3] = { 12.0, 10.0, 5.0 }; + +int +mib_ucdloadTable(struct oid *oid, struct ber_oid *o, struct ber_element **elm) +{ + struct ber_element *ber = *elm; + double avg[3]; + u_int32_t idx; + int samples, ret; + char *str; + + if ((samples = getloadavg(avg, 3)) == -1) + return (-1); + + /* Get and verify the current row index */ + idx = o->bo_id[OIDIDX_laTableEntry]; + if (idx > (u_int32_t)samples) + return (1); + + /* Tables need to prepend the OID on their own */ + o->bo_id[OIDIDX_laTableEntry] = idx; + ber = ber_add_oid(ber, o); + + switch (o->bo_id[OIDIDX_laTable]) { + case 1: /* laIndex */ + ber = ber_add_integer(ber, idx); + break; + case 2: /* laNames */ + if (idx == 1) + ret = asprintf(&str, "Load-1"); + else if (idx == 2) + ret = asprintf(&str, "Load-5"); + else + ret = asprintf(&str, "Load-15"); + + if (ret == -1) + return (-1); + ber = ber_add_string(ber, str); + break; + case 3: /* laLoad */ + if ((asprintf(&str, "%.2f", avg[idx - 1])) == -1) + return (-1); + ber = ber_add_string(ber, str); + break; + case 4: /* laConfig */ + if ((asprintf(&str, "%.2f", laconfig[idx - 1])) == -1) + return (-1); + ber = ber_add_string(ber, str); + break; + case 5: /* laLoadInt */ + ber = ber_add_integer(ber, (int)(avg[idx - 1] * 100)); + break; + case 100: /* laErrorFlag */ + if (avg[idx - 1] > laconfig[idx - 1]) + ber = ber_add_integer(ber, 1); + else + ber = ber_add_integer(ber, 0); + break; + case 101: /* laErrMessage */ + if (avg[idx - 1] > laconfig[idx - 1]) + ber = ber_add_string(ber, "Load Average too high"); + else + ber = ber_add_string(ber, ""); + break; + default: + return (-1); + } + + return (0); +} + +int +mib_setlaconfig(struct oid *oid, struct ber_oid *o, struct ber_element **elm) +{ + char *str; + u_int32_t idx; + double t; + + /* Get and verify the current row index */ + idx = o->bo_id[OIDIDX_laTableEntry]; + + if (idx < 1 || idx > sizeofa(laconfig)) + return (1); + + if (ber_get_string(*elm, &str) == -1) + return (-1); + + if ((t = atof(str)) <= 0) + return (-1); + + laconfig[idx - 1] = t; + return (0); +} + +int +mib_ucdsystemStats(struct oid *oid, struct ber_oid *o, struct ber_element **elm) +{ + struct ber_element *ber = *elm; + struct diskstats *stats; + struct uvmexp uvm; + u_int64_t blocks; + long cp_time[CPUSTATES]; + size_t len; + int diskcount, i; + int mib[] = { CTL_KERN, KERN_CPTIME }; + + len = sizeof(cp_time); + if (sysctl(mib, sizeofa(mib), &cp_time, &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[0] = CTL_HW; + mib[1] = HW_DISKCOUNT; + len = sizeof(diskcount); + if (sysctl(mib, sizeofa(mib), &diskcount, &len, NULL, 0) == -1) + return (-1); + + stats = calloc(diskcount, sizeof(*stats)); + if (stats == NULL) + return (-1); + /* We know len won't overflow, otherwise calloc() would have failed. */ + len = diskcount * sizeof(*stats); + mib[1] = HW_DISKSTATS; + if (sysctl(mib, sizeofa(mib), stats, &len, NULL, 0) == -1) { + free(stats); + return (-1); + } + + switch (o->bo_id[OIDIDX_systemStats]) { + case 1: /* ssIndex */ + ber = ber_add_integer(ber, 1); + break; + case 2: /* ssErrorName */ + ber = ber_add_string(ber, "systemStats"); + break; + case 50: /* ssCpuRawUser */ + ber = ber_add_integer(ber, cp_time[CP_USER]); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 51: /* ssCpuRawNice */ + ber = ber_add_integer(ber, cp_time[CP_NICE]); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 52: /* ssCpuRawSystem */ + ber = ber_add_integer(ber, cp_time[CP_SYS] + cp_time[CP_INTR]); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 53: /* ssCpuRawIdle */ + ber = ber_add_integer(ber, cp_time[CP_IDLE]); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 55: /* ssCpuRawKernel */ + ber = ber_add_integer(ber, cp_time[CP_SYS]); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 56: /* ssCpuRawInterrupt */ + ber = ber_add_integer(ber, cp_time[CP_INTR]); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 57: /* ssIORawSent */ + blocks = 0; + for (i = 0; i < diskcount; i++) + blocks += stats[i].ds_wbytes; + blocks /= MAXBSIZE; + ber = ber_add_integer(ber, (u_int32_t)blocks); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 58: /* ssIORawReceived */ + blocks = 0; + for (i = 0; i < diskcount; i++) + blocks += stats[i].ds_rbytes; + blocks /= MAXBSIZE; + ber = ber_add_integer(ber, (u_int32_t)blocks); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 59: /* ssRawInterrupts */ + ber = ber_add_integer(ber, uvm.intrs); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 60: /* ssRawContexts */ + ber = ber_add_integer(ber, uvm.swtch); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 62: /* ssRawSwapIn */ + ber = ber_add_integer(ber, ptok(uvm.pgswapin)); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + case 63: /* ssRawSwapOut */ + ber = ber_add_integer(ber, ptok(uvm.pgswapout)); + ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); + break; + default: + free(stats); + return (-1); + } + + free(stats); + return (0); +} + +/* * Defined in UCD-DISKIO-MIB.txt. */ @@ -3547,6 +3902,9 @@ mib_init(void) /* BRIDGE-MIB */ smi_mibtree(bridge_mib); + + /* UCD-SNMP-MIB */ + smi_mibtree(ucdsnmp_mib); /* UCD-DISKIO-MIB */ smi_mibtree(diskio_mib); Index: mib.h =================================================================== RCS file: /home/seth/code/obsd/cvsync/src/usr.sbin/snmpd/mib.h,v retrieving revision 1.26 diff -u -p -r1.26 mib.h --- mib.h 14 Jun 2012 17:31:32 -0000 1.26 +++ mib.h 24 Jun 2012 03:19:27 -0000 @@ -397,6 +397,51 @@ #define MIB_vantronix MIB_enterprises, 26766 #define MIB_openBSD MIB_enterprises, 30155 +/* UCD-SNMP-MIB */ +#define MIB_memory MIB_ucDavis, 4 +#define OIDIDX_memory 8 +#define MIB_memIndex MIB_memory, 1 +#define MIB_memErrorName MIB_memory, 2 +#define MIB_memTotalSwap MIB_memory, 3 +#define MIB_memAvailSwap MIB_memory, 4 +#define MIB_memTotalReal MIB_memory, 5 +#define MIB_memAvailReal MIB_memory, 6 +#define MIB_memTotalFree MIB_memory, 11 +#define MIB_memMinimumSwap MIB_memory, 12 +#define MIB_memShared MIB_memory, 13 +#define MIB_memBuffer MIB_memory, 14 +#define MIB_memCached MIB_memory, 15 +#define MIB_memSwapError MIB_memory, 100 +#define MIB_memSwapErrorMsg MIB_memory, 101 +#define MIB_laTable MIB_ucDavis, 10 +#define MIB_laEntry MIB_laTable, 1 +#define OIDIDX_laTable 9 +#define OIDIDX_laTableEntry 10 +#define MIB_laIndex MIB_laEntry, 1 +#define MIB_laNames MIB_laEntry, 2 +#define MIB_laLoad MIB_laEntry, 3 +#define MIB_laConfig MIB_laEntry, 4 +#define MIB_laLoadInt MIB_laEntry, 5 +#define MIB_laErrorFlag MIB_laEntry, 100 +#define MIB_laErrMessage MIB_laEntry, 101 +#define MIB_systemStats MIB_ucDavis, 11 +#define OIDIDX_systemStats 8 +#define MIB_ssIndex MIB_systemStats, 1 +#define MIB_ssErrorName MIB_systemStats, 2 +#define MIB_ssCpuRawUser MIB_systemStats, 50 +#define MIB_ssCpuRawNice MIB_systemStats, 51 +#define MIB_ssCpuRawSystem MIB_systemStats, 52 +#define MIB_ssCpuRawIdle MIB_systemStats, 53 +#define MIB_ssCpuRawKernel MIB_systemStats, 55 +#define MIB_ssCpuRawInterrupt MIB_systemStats, 56 +#define MIB_ssIORawSent MIB_systemStats, 57 +#define MIB_ssIORawReceived MIB_systemStats, 58 +#define MIB_ssRawInterrupts MIB_systemStats, 59 +#define MIB_ssRawContexts MIB_systemStats, 60 +#define MIB_ssRawSwapIn MIB_systemStats, 62 +#define MIB_ssRawSwapOut MIB_systemStats, 63 + + /* UCD-DISKIO-MIB */ #define MIB_ucdExperimental MIB_ucDavis, 13 #define MIB_ucdDiskIOMIB MIB_ucdExperimental, 15 @@ -908,6 +953,45 @@ { MIBDECL(microSystems) }, \ { MIBDECL(vantronix) }, \ { MIBDECL(openBSD) }, \ + \ + { MIBDECL(memory) }, \ + { MIBDECL(memIndex) }, \ + { MIBDECL(memErrorName) }, \ + { MIBDECL(memTotalSwap) }, \ + { MIBDECL(memAvailSwap) }, \ + { MIBDECL(memTotalReal) }, \ + { MIBDECL(memAvailReal) }, \ + { MIBDECL(memTotalFree) }, \ + { MIBDECL(memMinimumSwap) }, \ + { MIBDECL(memShared) }, \ + { MIBDECL(memBuffer) }, \ + { MIBDECL(memCached) }, \ + { MIBDECL(memSwapError) }, \ + { MIBDECL(memSwapErrorMsg) }, \ + { MIBDECL(laTable) }, \ + { MIBDECL(laEntry) }, \ + { MIBDECL(laIndex) }, \ + { MIBDECL(laNames) }, \ + { MIBDECL(laLoad) }, \ + { MIBDECL(laConfig) }, \ + { MIBDECL(laLoadInt) }, \ + { MIBDECL(laErrorFlag) }, \ + { MIBDECL(laErrMessage) }, \ + { MIBDECL(systemStats) }, \ + { MIBDECL(ssIndex) }, \ + { MIBDECL(ssErrorName) }, \ + { MIBDECL(ssCpuRawUser) }, \ + { MIBDECL(ssCpuRawNice) }, \ + { MIBDECL(ssCpuRawSystem) }, \ + { MIBDECL(ssCpuRawIdle) }, \ + { MIBDECL(ssCpuRawKernel) }, \ + { MIBDECL(ssCpuRawInterrupt) }, \ + { MIBDECL(ssIORawSent) }, \ + { MIBDECL(ssIORawReceived) }, \ + { MIBDECL(ssRawInterrupts) }, \ + { MIBDECL(ssRawContexts) }, \ + { MIBDECL(ssRawSwapIn) }, \ + { MIBDECL(ssRawSwapOut) }, \ \ { MIBDECL(ucdExperimental) }, \ { MIBDECL(ucdDiskIOMIB) }, \