Updates to snmp
authorMichael Spang <mspang@uwaterloo.ca>
Sat, 9 May 2009 05:34:53 +0000 (01:34 -0400)
committerMichael Spang <mspang@uwaterloo.ca>
Sat, 9 May 2009 05:34:53 +0000 (01:34 -0400)
13 files changed:
.gitignore
Makefile
csc-snmp-subagent.c [new file with mode: 0644]
cscMIB.c [deleted file]
cscMIB.h [deleted file]
mib-tc-stats.c [deleted file]
mib-tc-stats.h [deleted file]
mib-tc-test.c [deleted file]
mirror-mib.c [new file with mode: 0644]
mirror-mib.h [new file with mode: 0644]
mirror-nl-glue.c [new file with mode: 0644]
mirror-nl-glue.h [new file with mode: 0644]
mirror-stats.c [new file with mode: 0644]

index 32a6f77..1792b04 100644 (file)
@@ -1,2 +1,3 @@
-/mib-tc-stats
+/csc-snmp-subagent
+/mirror-stats
 *.o
index 450ea3e..ae0ec1d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,11 @@
-LDFLAGS := -lnl
+LDFLAGS := -lnl $(shell net-snmp-config --base-agent-libs)
 CFLAGS := -g3 -O2 -Wall
 
-all: mib-tc-stats
+all: mirror-stats csc-snmp-subagent
+
+mirror-stats: mirror-stats.o mirror-nl-glue.o
+
+csc-snmp-subagent: csc-snmp-subagent.o mirror-mib.o mirror-nl-glue.o
 
 clean:
-       rm -f mib-tc-stats
+       rm -f *.o mirror-stats csc-snmp-subagent
diff --git a/csc-snmp-subagent.c b/csc-snmp-subagent.c
new file mode 100644 (file)
index 0000000..103760b
--- /dev/null
@@ -0,0 +1,221 @@
+/* generated from net-snmp-config */
+#include <net-snmp/net-snmp-config.h>
+#ifdef HAVE_SIGNAL
+#include <signal.h>
+#endif /* HAVE_SIGNAL */
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+  #include "mirror-mib.h"
+const char *app_name = "cscMIB";
+
+extern int netsnmp_running;
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+RETSIGTYPE
+stop_server(UNUSED int a) {
+    netsnmp_running = 0;
+}
+
+static void
+usage(const char *prog)
+{
+    fprintf(stderr,
+            "USAGE: %s [OPTIONS]\n"
+            "\n"
+            "OPTIONS:\n", prog);
+
+    fprintf(stderr,
+            "  -d\t\t\tdump all traffic\n"
+            "  -D TOKEN[,...]\tturn on debugging output for the specified "
+            "TOKENs\n"
+            "\t\t\t   (ALL gives extremely verbose debugging output)\n"
+            "  -f\t\t\tDo not fork() from the calling shell.\n"
+            "  -h\t\t\tdisplay this help message\n"
+            "  -H\t\t\tdisplay a list of configuration file directives\n"
+            "  -L LOGOPTS\t\tToggle various defaults controlling logging:\n");
+    snmp_log_options_usage("\t\t\t  ", stderr);
+#ifndef DISABLE_MIB_LOADING
+    fprintf(stderr,
+            "  -m MIB[:...]\t\tload given list of MIBs (ALL loads "
+            "everything)\n"
+            "  -M DIR[:...]\t\tlook in given list of directories for MIBs\n");
+#endif /* DISABLE_MIB_LOADING */
+#ifndef DISABLE_MIB_LOADING
+    fprintf(stderr,
+            "  -P MIBOPTS\t\tToggle various defaults controlling mib "
+            "parsing:\n");
+    snmp_mib_toggle_options_usage("\t\t\t  ", stderr);
+#endif /* DISABLE_MIB_LOADING */
+    fprintf(stderr,
+            "  -v\t\t\tdisplay package version number\n"
+            "  -x TRANSPORT\tconnect to master agent using TRANSPORT\n");
+    exit(1);
+}
+
+static void
+version(void)
+{
+    fprintf(stderr, "NET-SNMP version: %s\n", netsnmp_get_version());
+    exit(0);
+}
+
+int
+main (int argc, char **argv)
+{
+  int arg;
+  char* cp = NULL;
+  int dont_fork = 0, do_help = 0;
+
+  while ((arg = getopt(argc, argv, "dD:fhHL:"
+#ifndef DISABLE_MIB_LOADING
+                       "m:M:"
+#endif /* DISABLE_MIB_LOADING */
+                       "n:"
+#ifndef DISABLE_MIB_LOADING
+                       "P:"
+#endif /* DISABLE_MIB_LOADING */
+                       "vx:")) != EOF) {
+    switch (arg) {
+    case 'd':
+      netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+                             NETSNMP_DS_LIB_DUMP_PACKET, 1);
+      break;
+
+    case 'D':
+      debug_register_tokens(optarg);
+      snmp_set_do_debugging(1);
+      break;
+
+    case 'f':
+      dont_fork = 1;
+      break;
+
+    case 'h':
+      usage(argv[0]);
+      break;
+
+    case 'H':
+      do_help = 1;
+      break;
+
+    case 'L':
+      if (snmp_log_options(optarg, argc, argv) < 0) {
+        exit(1);
+      }
+      break;
+
+#ifndef DISABLE_MIB_LOADING
+    case 'm':
+      if (optarg != NULL) {
+        setenv("MIBS", optarg, 1);
+      } else {
+        usage(argv[0]);
+      }
+      break;
+
+    case 'M':
+      if (optarg != NULL) {
+        setenv("MIBDIRS", optarg, 1);
+      } else {
+        usage(argv[0]);
+      }
+      break;
+#endif /* DISABLE_MIB_LOADING */
+
+    case 'n':
+      if (optarg != NULL) {
+        app_name = optarg;
+        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
+                              NETSNMP_DS_LIB_APPTYPE, app_name);
+      } else {
+        usage(argv[0]);
+      }
+      break;
+
+#ifndef DISABLE_MIB_LOADING
+    case 'P':
+      cp = snmp_mib_toggle_options(optarg);
+      if (cp != NULL) {
+        fprintf(stderr, "Unknown parser option to -P: %c.\n", *cp);
+        usage(argv[0]);
+      }
+      break;
+#endif /* DISABLE_MIB_LOADING */
+
+    case 'v':
+      version();
+      break;
+
+    case 'x':
+      if (optarg != NULL) {
+        netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
+                              NETSNMP_DS_AGENT_X_SOCKET, optarg);
+      } else {
+        usage(argv[0]);
+      }
+      break;
+
+    default:
+      fprintf(stderr, "invalid option: -%c\n", arg);
+      usage(argv[0]);
+      break;
+    }
+  }
+
+  if (do_help) {
+    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
+                           NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
+  } else {
+    /* we are a subagent */
+    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
+                           NETSNMP_DS_AGENT_ROLE, 1);
+
+    if (!dont_fork) {
+      if (netsnmp_daemonize(1, snmp_stderrlog_status()) != 0)
+        exit(1);
+    }
+
+    /* initialize tcpip, if necessary */
+    SOCK_STARTUP;
+  }
+
+  /* initialize the agent library */
+  init_agent(app_name);
+
+  /* initialize your mib code here */
+  init_mirror_mib();
+
+  /* cscMIB will be used to read cscMIB.conf files. */
+  init_snmp("cscMIB");
+
+  if (do_help) {
+    fprintf(stderr, "Configuration directives understood:\n");
+    read_config_print_usage("  ");
+    exit(0);
+  }
+
+  /* In case we received a request to stop (kill -TERM or kill -INT) */
+  netsnmp_running = 1;
+#ifdef SIGTERM
+  signal(SIGTERM, stop_server);
+#endif
+#ifdef SIGINT
+  signal(SIGINT, stop_server);
+#endif
+
+  /* main loop here... */
+  while(netsnmp_running) {
+    agent_check_and_process(1);
+  }
+
+  /* at shutdown time */
+  snmp_shutdown(app_name);
+  SOCK_CLEANUP;
+  exit(0);
+}
+
diff --git a/cscMIB.c b/cscMIB.c
deleted file mode 100644 (file)
index 663ed84..0000000
--- a/cscMIB.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Note: this file originally auto-generated by mib2c using
- *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
- */
-
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-#include "cscMIB.h"
-#include "mib-tc-stats.h"
-
-/** Initializes the cscMIB module */
-void
-init_cscMIB(void)
-{
-    static oid      cogentBytes_oid[] =
-        { 1, 3, 6, 1, 4, 1, 27934, 2, 2, 1 };
-    static oid      orionBytes_oid[] =
-        { 1, 3, 6, 1, 4, 1, 27934, 2, 2, 2 };
-    static oid      campusBytes_oid[] =
-        { 1, 3, 6, 1, 4, 1, 27934, 2, 2, 3 };
-
-    DEBUGMSGTL(("cscMIB", "Initializing\n"));
-
-    netsnmp_register_scalar(netsnmp_create_handler_registration
-                            ("cogentBytes", handle_cogentBytes,
-                             cogentBytes_oid, OID_LENGTH(cogentBytes_oid),
-                             HANDLER_CAN_RONLY));
-    netsnmp_register_scalar(netsnmp_create_handler_registration
-                            ("orionBytes", handle_orionBytes,
-                             orionBytes_oid, OID_LENGTH(orionBytes_oid),
-                             HANDLER_CAN_RONLY));
-    netsnmp_register_scalar(netsnmp_create_handler_registration
-                            ("campusBytes", handle_campusBytes,
-                             campusBytes_oid, OID_LENGTH(campusBytes_oid),
-                             HANDLER_CAN_RONLY));
-}
-
-int
-handle_cogentBytes(netsnmp_mib_handler *handler,
-                   netsnmp_handler_registration *reginfo,
-                   netsnmp_agent_request_info *reqinfo,
-                   netsnmp_request_info *requests)
-{
-    uint64_t bytes;
-    mirror_stats_refresh();
-    bytes = get_class_byte_count(&cogent_class);
-
-    switch (reqinfo->mode) {
-        case MODE_GET:
-            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER64,
-                    (u_char *)&bytes, sizeof(bytes));
-            break;
-        default:
-            die("unknown mode");
-    }
-
-    return SNMP_ERR_NOERROR;
-}
-
-int
-handle_orionBytes(netsnmp_mib_handler *handler,
-                  netsnmp_handler_registration *reginfo,
-                  netsnmp_agent_request_info *reqinfo,
-                  netsnmp_request_info *requests)
-{
-    uint64_t bytes;
-    mirror_stats_refresh();
-    bytes = get_class_byte_count(&orion_class);
-
-    switch (reqinfo->mode) {
-        case MODE_GET:
-            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER64,
-                    (u_char *)&bytes, sizeof(bytes));
-            break;
-        default:
-            die("unknown mode");
-    }
-
-    return SNMP_ERR_NOERROR;
-}
-
-int
-handle_campusBytes(netsnmp_mib_handler *handler,
-                   netsnmp_handler_registration *reginfo,
-                   netsnmp_agent_request_info *reqinfo,
-                   netsnmp_request_info *requests)
-{
-    uint64_t bytes;
-    mirror_stats_refresh();
-    bytes = get_class_byte_count(&campus_class);
-
-    switch (reqinfo->mode) {
-        case MODE_GET:
-            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER64,
-                    (u_char *)&bytes, sizeof(bytes));
-            break;
-        default:
-            die("unknown mode");
-    }
-
-    return SNMP_ERR_NOERROR;
-}
diff --git a/cscMIB.h b/cscMIB.h
deleted file mode 100644 (file)
index 63a036c..0000000
--- a/cscMIB.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Note: this file originally auto-generated by mib2c using
- *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
- */
-#ifndef CSCMIB_H
-#define CSCMIB_H
-
-/*
- * function declarations 
- */
-void            init_cscMIB(void);
-Netsnmp_Node_Handler handle_cogentBytes;
-Netsnmp_Node_Handler handle_orionBytes;
-Netsnmp_Node_Handler handle_campusBytes;
-
-#endif                          /* CSCMIB_H */
diff --git a/mib-tc-stats.c b/mib-tc-stats.c
deleted file mode 100644 (file)
index b01a98e..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <netlink/route/class.h>
-#include <netlink/route/link.h>
-#include <netlink/cache-api.h>
-#include <netlink/object.h>
-#include "mib-tc-stats.h"
-
-static struct nl_cache *link_cache, *class_cache;
-static struct rtnl_link *eth;
-static int ifindex;
-
-struct class_info cogent_class = { "cogent", "01:02", };
-struct class_info orion_class  = { "orion",  "01:03", };
-struct class_info campus_class = { "campus", "01:04", };
-
-static struct nl_handle *nl_handle;
-
-void die(const char *message) {
-    fprintf(stderr, "fatal: %s\n", message);
-    exit(1);
-}
-
-static void match_obj(struct nl_object *obj, void *arg) {
-    struct nl_object *needle = *(struct nl_object **)arg;
-    struct nl_object **ret = (struct nl_object **)arg + 1;
-
-    if (!*ret && nl_object_identical(obj, needle)) {
-        nl_object_get(obj);
-        *ret = obj;
-    }
-}
-
-static struct rtnl_class *get_class_by_id(char *id, int ifindex) {
-    uint32_t handle;
-    struct rtnl_class *needle;
-    struct nl_object *magic[2];
-
-    if (rtnl_tc_str2handle(id, &handle))
-        die("invalid id");
-
-    needle = rtnl_class_alloc();
-    rtnl_class_set_ifindex(needle, ifindex);
-    rtnl_class_set_handle(needle, handle);
-
-    magic[0] = (struct nl_object *)needle;
-    magic[1] = (struct nl_object *)NULL;
-
-    nl_cache_foreach(class_cache, match_obj, magic);
-
-    rtnl_class_put(needle);
-    return (struct rtnl_class *)magic[1];
-}
-
-uint64_t get_class_byte_count(struct class_info *info) {
-    struct rtnl_class *class = get_class_by_id(info->id, ifindex);
-    uint64_t bytes;
-    if (!class)
-        die("class not found");
-    bytes = rtnl_class_get_stat(class, RTNL_TC_BYTES);
-    rtnl_class_put(class);
-    return bytes;
-}
-
-void mirror_stats_refresh(void) {
-    nl_cache_refill(nl_handle, class_cache);
-}
-
-void mirror_stats_initialize(void) {
-    nl_handle = nl_handle_alloc();
-    if (!nl_handle)
-        die("unable to allocate handle");
-
-    if (nl_connect(nl_handle, NETLINK_ROUTE) < 0)
-        die("unable to connect to netlink");
-
-    link_cache = rtnl_link_alloc_cache(nl_handle);
-    if (!link_cache)
-        die("unable to allocate link cache");
-
-    eth = rtnl_link_get_by_name(link_cache, "eth0");
-    if (!eth)
-        die("unable to acquire eth0");
-    ifindex = rtnl_link_get_ifindex(eth);
-
-    class_cache = rtnl_class_alloc_cache(nl_handle, ifindex);
-    if (!class_cache)
-        die("unable to allocate class cache");
-}
-
-void mirror_stats_cleanup(void) {
-    rtnl_link_put(eth);
-    nl_cache_free(class_cache);
-    nl_cache_free(link_cache);
-    nl_close(nl_handle);
-    nl_handle_destroy(nl_handle);
-}
-
diff --git a/mib-tc-stats.h b/mib-tc-stats.h
deleted file mode 100644 (file)
index 53add1a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <netlink/route/class.h>
-#include <netlink/route/link.h>
-#include <netlink/cache-api.h>
-#include <netlink/object.h>
-
-struct class_info {
-    char *name;
-    char *id;
-};
-
-extern struct class_info cogent_class;
-extern struct class_info orion_class;
-extern struct class_info campus_class;
-
-void mirror_stats_refresh(void);
-void mirror_stats_initialize(void);
-void mirror_stats_cleanup(void);
-void die(const char *);
-uint64_t get_class_byte_count(struct class_info *);
diff --git a/mib-tc-test.c b/mib-tc-test.c
deleted file mode 100644 (file)
index aeaa2e8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "mib-tc-stats.h"
-
-int main(int argc, char *argv[]) {
-    mirror_stats_initialize();
-    for (;;) {
-        printf("%s %"PRIu64"\n", cogent_class.id, get_class_byte_count(&cogent_class));
-        printf("%s %"PRIu64"\n", orion_class.id, get_class_byte_count(&orion_class));
-        printf("%s %"PRIu64"\n", campus_class.id, get_class_byte_count(&campus_class));
-        sleep(1);
-        mirror_stats_refresh();
-    }
-}
diff --git a/mirror-mib.c b/mirror-mib.c
new file mode 100644 (file)
index 0000000..4cd7e87
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        : mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "mirror-mib.h"
+#include "mirror-nl-glue.h"
+
+void
+init_mirror_mib(void)
+{
+    static oid      cogentBytes_oid[] =
+        { 1, 3, 6, 1, 4, 1, 27934, 2, 2, 1 };
+    static oid      orionBytes_oid[] =
+        { 1, 3, 6, 1, 4, 1, 27934, 2, 2, 2 };
+    static oid      campusBytes_oid[] =
+        { 1, 3, 6, 1, 4, 1, 27934, 2, 2, 3 };
+
+    DEBUGMSGTL(("mirror_mib", "Initializing\n"));
+
+    mirror_stats_initialize();
+
+    netsnmp_register_scalar(netsnmp_create_handler_registration
+                            ("cogentBytes", handle_cogentBytes,
+                             cogentBytes_oid, OID_LENGTH(cogentBytes_oid),
+                             HANDLER_CAN_RONLY));
+    netsnmp_register_scalar(netsnmp_create_handler_registration
+                            ("orionBytes", handle_orionBytes,
+                             orionBytes_oid, OID_LENGTH(orionBytes_oid),
+                             HANDLER_CAN_RONLY));
+    netsnmp_register_scalar(netsnmp_create_handler_registration
+                            ("campusBytes", handle_campusBytes,
+                             campusBytes_oid, OID_LENGTH(campusBytes_oid),
+                             HANDLER_CAN_RONLY));
+}
+
+void explode_counter64(uint64_t num, struct counter64 *counter) {
+    counter->low = num & 0xFFFFFFFF;
+    counter->high = (num >> 32) & 0xFFFFFFFF;
+}
+
+int
+handle_cogentBytes(netsnmp_mib_handler *handler,
+                   netsnmp_handler_registration *reginfo,
+                   netsnmp_agent_request_info *reqinfo,
+                   netsnmp_request_info *requests)
+{
+    struct counter64 counter;
+    mirror_stats_refresh();
+    explode_counter64(get_class_byte_count(&cogent_class), &counter);
+
+    switch (reqinfo->mode) {
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER64,
+                    (u_char *)&counter, sizeof(counter));
+            break;
+        default:
+            die("unknown mode");
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_orionBytes(netsnmp_mib_handler *handler,
+                  netsnmp_handler_registration *reginfo,
+                  netsnmp_agent_request_info *reqinfo,
+                  netsnmp_request_info *requests)
+{
+    struct counter64 counter;
+    mirror_stats_refresh();
+    explode_counter64(get_class_byte_count(&orion_class), &counter);
+
+    switch (reqinfo->mode) {
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER64,
+                    (u_char *)&counter, sizeof(counter));
+            break;
+        default:
+            die("unknown mode");
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_campusBytes(netsnmp_mib_handler *handler,
+                   netsnmp_handler_registration *reginfo,
+                   netsnmp_agent_request_info *reqinfo,
+                   netsnmp_request_info *requests)
+{
+    struct counter64 counter;
+    mirror_stats_refresh();
+    explode_counter64(get_class_byte_count(&campus_class), &counter);
+
+    switch (reqinfo->mode) {
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER64,
+                    (u_char *)&counter, sizeof(counter));
+            break;
+        default:
+            die("unknown mode");
+    }
+
+    return SNMP_ERR_NOERROR;
+}
diff --git a/mirror-mib.h b/mirror-mib.h
new file mode 100644 (file)
index 0000000..f707f97
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef MIRRORMIB_H
+#define MIRRORMIB_H
+
+void            init_mirror_mib(void);
+Netsnmp_Node_Handler handle_cogentBytes;
+Netsnmp_Node_Handler handle_orionBytes;
+Netsnmp_Node_Handler handle_campusBytes;
+
+#endif
diff --git a/mirror-nl-glue.c b/mirror-nl-glue.c
new file mode 100644 (file)
index 0000000..720ac6a
--- /dev/null
@@ -0,0 +1,102 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/cache-api.h>
+#include <netlink/object.h>
+#include "mirror-nl-glue.h"
+
+static struct nl_cache *link_cache, *class_cache;
+static struct rtnl_link *eth;
+static int ifindex;
+
+struct class_info cogent_class = { "cogent", "01:02", };
+struct class_info orion_class  = { "orion",  "01:03", };
+struct class_info campus_class = { "campus", "01:04", };
+
+static struct nl_handle *nl_handle;
+
+void die(const char *message) {
+    fprintf(stderr, "fatal: %s\n", message);
+    exit(1);
+}
+
+static void match_obj(struct nl_object *obj, void *arg) {
+    struct nl_object *needle = *(struct nl_object **)arg;
+    struct nl_object **ret = (struct nl_object **)arg + 1;
+
+    if (!*ret && nl_object_identical(obj, needle)) {
+        nl_object_get(obj);
+        *ret = obj;
+    }
+}
+
+static struct rtnl_class *get_class_by_id(char *id, int ifindex) {
+    uint32_t handle;
+    struct rtnl_class *needle;
+    struct nl_object *magic[2];
+
+    if (rtnl_tc_str2handle(id, &handle))
+        die("invalid id");
+
+    needle = rtnl_class_alloc();
+    rtnl_class_set_ifindex(needle, ifindex);
+    rtnl_class_set_handle(needle, handle);
+
+    magic[0] = (struct nl_object *)needle;
+    magic[1] = (struct nl_object *)NULL;
+
+    nl_cache_foreach(class_cache, match_obj, magic);
+
+    rtnl_class_put(needle);
+    return (struct rtnl_class *)magic[1];
+}
+
+uint64_t get_class_byte_count(struct class_info *info) {
+    struct rtnl_class *class = get_class_by_id(info->id, ifindex);
+    uint64_t bytes;
+    if (!class)
+        die("class not found");
+    bytes = rtnl_class_get_stat(class, RTNL_TC_BYTES);
+    rtnl_class_put(class);
+    return bytes;
+}
+
+void mirror_stats_refresh(void) {
+    nl_cache_refill(nl_handle, class_cache);
+}
+
+void mirror_stats_initialize(void) {
+    nl_handle = nl_handle_alloc();
+    if (!nl_handle)
+        die("unable to allocate handle");
+
+    if (nl_connect(nl_handle, NETLINK_ROUTE) < 0)
+        die("unable to connect to netlink");
+
+    link_cache = rtnl_link_alloc_cache(nl_handle);
+    if (!link_cache)
+        die("unable to allocate link cache");
+
+    eth = rtnl_link_get_by_name(link_cache, "eth0");
+    if (!eth)
+        die("unable to acquire eth0");
+    ifindex = rtnl_link_get_ifindex(eth);
+
+    class_cache = rtnl_class_alloc_cache(nl_handle, ifindex);
+    if (!class_cache)
+        die("unable to allocate class cache");
+}
+
+void mirror_stats_cleanup(void) {
+    rtnl_link_put(eth);
+    nl_cache_free(class_cache);
+    nl_cache_free(link_cache);
+    nl_close(nl_handle);
+    nl_handle_destroy(nl_handle);
+}
+
diff --git a/mirror-nl-glue.h b/mirror-nl-glue.h
new file mode 100644 (file)
index 0000000..53add1a
--- /dev/null
@@ -0,0 +1,25 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/cache-api.h>
+#include <netlink/object.h>
+
+struct class_info {
+    char *name;
+    char *id;
+};
+
+extern struct class_info cogent_class;
+extern struct class_info orion_class;
+extern struct class_info campus_class;
+
+void mirror_stats_refresh(void);
+void mirror_stats_initialize(void);
+void mirror_stats_cleanup(void);
+void die(const char *);
+uint64_t get_class_byte_count(struct class_info *);
diff --git a/mirror-stats.c b/mirror-stats.c
new file mode 100644 (file)
index 0000000..44bade4
--- /dev/null
@@ -0,0 +1,12 @@
+#include "mirror-nl-glue.h"
+
+int main(int argc, char *argv[]) {
+    mirror_stats_initialize();
+    for (;;) {
+        printf("%s %"PRIu64"\n", cogent_class.id, get_class_byte_count(&cogent_class));
+        printf("%s %"PRIu64"\n", orion_class.id, get_class_byte_count(&orion_class));
+        printf("%s %"PRIu64"\n", campus_class.id, get_class_byte_count(&campus_class));
+        sleep(1);
+        mirror_stats_refresh();
+    }
+}