Merge snmp stuff into mirror.git
authorMichael Spang <mspang@csclub.uwaterloo.ca>
Mon, 8 Mar 2010 00:29:49 +0000 (19:29 -0500)
committerMichael Spang <mspang@csclub.uwaterloo.ca>
Mon, 8 Mar 2010 00:30:25 +0000 (19:30 -0500)
snmp/.gitignore [new file with mode: 0644]
snmp/CSC-MIB.txt [new file with mode: 0644]
snmp/Makefile [new file with mode: 0644]
snmp/csc-snmp-subagent.c [new file with mode: 0644]
snmp/mirror-mib.c [new file with mode: 0644]
snmp/mirror-mib.h [new file with mode: 0644]
snmp/mirror-nl-glue.c [new file with mode: 0644]
snmp/mirror-nl-glue.h [new file with mode: 0644]
snmp/mirror-stats.c [new file with mode: 0644]

diff --git a/snmp/.gitignore b/snmp/.gitignore
new file mode 100644 (file)
index 0000000..1792b04
--- /dev/null
@@ -0,0 +1,3 @@
+/csc-snmp-subagent
+/mirror-stats
+*.o
diff --git a/snmp/CSC-MIB.txt b/snmp/CSC-MIB.txt
new file mode 100644 (file)
index 0000000..97a314d
--- /dev/null
@@ -0,0 +1,46 @@
+CSC-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+    MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, Counter64,
+    Integer32, TimeTicks, mib-2, enterprises,
+    NOTIFICATION-TYPE                        FROM SNMPv2-SMI
+    TEXTUAL-CONVENTION, DisplayString,
+    PhysAddress, TruthValue, RowStatus,
+    TimeStamp, AutonomousType, TestAndIncr   FROM SNMPv2-TC
+    MODULE-COMPLIANCE, OBJECT-GROUP,
+    NOTIFICATION-GROUP                       FROM SNMPv2-CONF
+    snmpTraps                                FROM SNMPv2-MIB
+    IANAifType                               FROM IANAifType-MIB;
+
+csclub OBJECT IDENTIFIER ::= { enterprises 27934 }
+
+cscMIB MODULE-IDENTITY
+    LAST-UPDATED "200905080000Z"
+    ORGANIZATION "University of Waterloo Computer Science Club"
+    CONTACT-INFO "systems-committee@csclub.uwaterloo.ca"
+    DESCRIPTION  "Computer Science Club Local MIBs"
+    REVISION     "200905080000Z"
+    DESCRIPTION  "Initial revision"
+    ::= { csclub 2 }
+
+mirror OBJECT IDENTIFIER ::= { cscMIB 2 }
+
+cogentBytes OBJECT-TYPE
+    SYNTAX      Counter64
+    MAX-ACCESS  read-only
+    STATUS      current
+    ::= { mirror 1 }
+
+orionBytes OBJECT-TYPE
+    SYNTAX      Counter64
+    MAX-ACCESS  read-only
+    STATUS      current
+    ::= { mirror 2 }
+
+campusBytes OBJECT-TYPE
+    SYNTAX      Counter64
+    MAX-ACCESS  read-only
+    STATUS      current
+    ::= { mirror 3 }
+
+END
diff --git a/snmp/Makefile b/snmp/Makefile
new file mode 100644 (file)
index 0000000..ae0ec1d
--- /dev/null
@@ -0,0 +1,11 @@
+LDFLAGS := -lnl $(shell net-snmp-config --base-agent-libs)
+CFLAGS := -g3 -O2 -Wall
+
+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 *.o mirror-stats csc-snmp-subagent
diff --git a/snmp/csc-snmp-subagent.c b/snmp/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/snmp/mirror-mib.c b/snmp/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/snmp/mirror-mib.h b/snmp/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/snmp/mirror-nl-glue.c b/snmp/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/snmp/mirror-nl-glue.h b/snmp/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/snmp/mirror-stats.c b/snmp/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();
+    }
+}