I'd like to monitor disk IO on my workstation, but snmpd doesn't
currently export hw.diskstats as far as I can tell. I found net-snmp
supports UCD-DISKIO-MIB and it's not too complex, so I went ahead and
coded up an implementation.
It's been a while since I've touched SNMP and/or snmpd, but it seems
to work correctly:
$ snmpwalk -m UCD-DISKIO-MIB -v1 -c public 127.0.0.1 diskIOTable
UCD-DISKIO-MIB::diskIOIndex.1 = INTEGER: 1
UCD-DISKIO-MIB::diskIOIndex.2 = INTEGER: 2
UCD-DISKIO-MIB::diskIOIndex.3 = INTEGER: 3
UCD-DISKIO-MIB::diskIODevice.1 = STRING: sd0
UCD-DISKIO-MIB::diskIODevice.2 = STRING: sd1
UCD-DISKIO-MIB::diskIODevice.3 = STRING: cd0
UCD-DISKIO-MIB::diskIONRead.1 = Counter32: 3584
UCD-DISKIO-MIB::diskIONRead.2 = Counter32: 3128056320
UCD-DISKIO-MIB::diskIONRead.3 = Counter32: 0
UCD-DISKIO-MIB::diskIONWritten.1 = Counter32: 0
UCD-DISKIO-MIB::diskIONWritten.2 = Counter32: 1418602496
UCD-DISKIO-MIB::diskIONWritten.3 = Counter32: 0
UCD-DISKIO-MIB::diskIOReads.1 = Counter32: 7
UCD-DISKIO-MIB::diskIOReads.2 = Counter32: 18550342
UCD-DISKIO-MIB::diskIOReads.3 = Counter32: 0
UCD-DISKIO-MIB::diskIOWrites.1 = Counter32: 0
UCD-DISKIO-MIB::diskIOWrites.2 = Counter32: 19485959
UCD-DISKIO-MIB::diskIOWrites.3 = Counter32: 0
UCD-DISKIO-MIB::diskIONReadX.1 = Counter64: 3584
UCD-DISKIO-MIB::diskIONReadX.2 = Counter64: 539998968320
UCD-DISKIO-MIB::diskIONReadX.3 = Counter64: 0
UCD-DISKIO-MIB::diskIONWrittenX.1 = Counter64: 0
UCD-DISKIO-MIB::diskIONWrittenX.2 = Counter64: 357900888064
UCD-DISKIO-MIB::diskIONWrittenX.3 = Counter64: 0
Test reports from regular SNMP users would be great.
ok?
Index: mib.h
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/usr.sbin/snmpd/mib.h,v
retrieving revision 1.25
diff -u -p -r1.25 mib.h
--- mib.h 20 Mar 2012 03:01:26 -0000 1.25
+++ mib.h 13 Jun 2012 19:19:23 -0000
@@ -397,6 +397,22 @@
#define MIB_vantronix MIB_enterprises, 26766
#define MIB_openBSD MIB_enterprises, 30155
+/* UCD-DISKIO-MIB */
+#define MIB_ucdExperimental MIB_ucDavis, 13
+#define MIB_ucdDiskIOMIB MIB_ucdExperimental, 15
+#define MIB_diskIOTable MIB_ucdDiskIOMIB, 1
+#define MIB_diskIOEntry MIB_diskIOTable, 1
+#define OIDIDX_diskIO 11
+#define OIDIDX_diskIOEntry 12
+#define MIB_diskIOIndex MIB_diskIOEntry, 1
+#define MIB_diskIODevice MIB_diskIOEntry, 2
+#define MIB_diskIONRead MIB_diskIOEntry, 3
+#define MIB_diskIONWritten MIB_diskIOEntry, 4
+#define MIB_diskIOReads MIB_diskIOEntry, 5
+#define MIB_diskIOWrites MIB_diskIOEntry, 6
+#define MIB_diskIONReadX MIB_diskIOEntry, 12
+#define MIB_diskIONWrittenX MIB_diskIOEntry, 13
+
/* OPENBSD-MIB */
#define MIB_pfMIBObjects MIB_openBSD, 1
#define MIB_pfInfo MIB_pfMIBObjects, 1
@@ -892,6 +908,19 @@
{ MIBDECL(microSystems) }, \
{ MIBDECL(vantronix) }, \
{ MIBDECL(openBSD) }, \
+ \
+ { MIBDECL(ucdExperimental) }, \
+ { MIBDECL(ucdDiskIOMIB) }, \
+ { MIBDECL(diskIOTable) }, \
+ { MIBDECL(diskIOEntry) }, \
+ { MIBDECL(diskIOIndex) }, \
+ { MIBDECL(diskIODevice) }, \
+ { MIBDECL(diskIONRead) }, \
+ { MIBDECL(diskIONWritten) }, \
+ { MIBDECL(diskIOReads) }, \
+ { MIBDECL(diskIOWrites) }, \
+ { MIBDECL(diskIONReadX) }, \
+ { MIBDECL(diskIONWrittenX) }, \
\
{ MIBDECL(pfMIBObjects) }, \
{ MIBDECL(pfInfo) }, \
Index: mib.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/usr.sbin/snmpd/mib.c,v
retrieving revision 1.52
diff -u -p -r1.52 mib.c
--- mib.c 20 Mar 2012 03:01:26 -0000 1.52
+++ mib.c 13 Jun 2012 19:19:09 -0000
@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/ioctl.h>
+#include <sys/disk.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -3362,6 +3363,99 @@ mib_ipfroute(struct oid *oid, struct ber
}
/*
+ * Defined in UCD-DISKIO-MIB.txt.
+ */
+
+int mib_diskio(struct oid *oid, struct ber_oid *o, struct ber_element
**elm);
+
+static struct oid diskio_mib[] = {
+ { MIB(ucdDiskIOMIB), OID_MIB },
+ { MIB(diskIOIndex), OID_TRD, mib_diskio },
+ { MIB(diskIODevice), OID_TRD, mib_diskio },
+ { MIB(diskIONRead), OID_TRD, mib_diskio },
+ { MIB(diskIONWritten), OID_TRD, mib_diskio },
+ { MIB(diskIOReads), OID_TRD, mib_diskio },
+ { MIB(diskIOWrites), OID_TRD, mib_diskio },
+ { MIB(diskIONReadX), OID_TRD, mib_diskio },
+ { MIB(diskIONWrittenX), OID_TRD, mib_diskio },
+ { MIBEND }
+};
+
+int
+mib_diskio(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
+{
+ struct ber_element *ber = *elm;
+ u_int32_t idx;
+ int mib[] = { CTL_HW, 0 };
+ unsigned int diskcount;
+ struct diskstats *stats;
+ size_t len;
+
+ len = sizeof(diskcount);
+ mib[1] = HW_DISKCOUNT;
+ if (sysctl(mib, sizeofa(mib), &diskcount, &len, NULL, 0) == -1)
+ return (-1);
+
+ /* Get and verify the current row index */
+ idx = o->bo_id[OIDIDX_diskIOEntry];
+ if (idx > diskcount)
+ return (1);
+
+ /* Tables need to prepend the OID on their own */
+ o->bo_id[OIDIDX_diskIOEntry] = idx;
+ ber = ber_add_oid(ber, o);
+
+ len = diskcount * sizeof(*stats); /* XXX: Overflow? */
+ stats = malloc(len);
+ if (stats == NULL)
+ return (-1);
+ mib[1] = HW_DISKSTATS;
+ if (sysctl(mib, sizeofa(mib), stats, &len, NULL, 0) == -1) {
+ free(stats);
+ return (-1);
+ }
+
+ switch (o->bo_id[OIDIDX_diskIO]) {
+ case 1: /* diskIOIndex */
+ ber = ber_add_integer(ber, idx);
+ break;
+ case 2: /* diskIODevice */
+ ber = ber_add_string(ber, stats[idx - 1].ds_name); /* XXX: NUL
terminated? */
+ break;
+ case 3: /* diskIONRead */
+ ber = ber_add_integer(ber, (u_int32_t)stats[idx - 1].ds_rbytes);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
+ break;
+ case 4: /* diskIONWritten */
+ ber = ber_add_integer(ber, (u_int32_t)stats[idx - 1].ds_wbytes);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
+ break;
+ case 5: /* diskIOReads */
+ ber = ber_add_integer(ber, (u_int32_t)stats[idx - 1].ds_rxfer);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
+ break;
+ case 6: /* diskIOWrites */
+ ber = ber_add_integer(ber, (u_int32_t)stats[idx - 1].ds_wxfer);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
+ break;
+ case 12: /* diskIONReadX */
+ ber = ber_add_integer(ber, stats[idx - 1].ds_rbytes);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER64);
+ break;
+ case 13: /* diskIONWrittenX */
+ ber = ber_add_integer(ber, stats[idx - 1].ds_wbytes);
+ ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER64);
+ break;
+ default:
+ free(stats);
+ return (-1);
+ }
+
+ free(stats);
+ return (0);
+}
+
+/*
* Defined in BRIDGE-MIB.txt (rfc1493)
*
* This MIB is required by some NMS to accept the device because
@@ -3451,6 +3545,9 @@ mib_init(void)
/* BRIDGE-MIB */
smi_mibtree(bridge_mib);
+
+ /* UCD-DISKIO-MIB */
+ smi_mibtree(diskio_mib);
/* OPENBSD-MIB */
smi_mibtree(openbsd_mib);