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);

Reply via email to