The tiny daemon that creates the server graph(s) for mirror.csclub. Will add document...
authorPeter Barfuss <pbarfuss@sodium-benzoate.csclub.uwaterloo.ca>
Wed, 14 Mar 2012 21:11:42 +0000 (17:11 -0400)
committerPeter Barfuss <pbarfuss@sodium-benzoate.csclub.uwaterloo.ca>
Wed, 14 Mar 2012 21:11:42 +0000 (17:11 -0400)
rrdtool/mirror-nl-glue.c [new file with mode: 0644]
rrdtool/mirror-nl-glue.h [new file with mode: 0644]
rrdtool/mirror-rrd.c [new file with mode: 0644]
rrdtool/rrdgraph-monthly.sh [new file with mode: 0755]
rrdtool/rrdgraph-yearly.sh [new file with mode: 0755]
rrdtool/rrdgraph.sh [new file with mode: 0755]

diff --git a/rrdtool/mirror-nl-glue.c b/rrdtool/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/rrdtool/mirror-nl-glue.h b/rrdtool/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/rrdtool/mirror-rrd.c b/rrdtool/mirror-rrd.c
new file mode 100644 (file)
index 0000000..24c46aa
--- /dev/null
@@ -0,0 +1,37 @@
+#include "mirror-nl-glue.h"
+#include <rrd.h>
+
+int main(void) {
+       char *argv[3];
+       unsigned long packet_count;
+
+       switch(fork()) {
+               case -1:
+                       return -1;
+               case 0:
+                       break;
+               default:
+                       _exit(0);
+       }       
+
+    mirror_stats_initialize();
+    argv[0] = malloc(1024);    
+    for (;;) {
+        packet_count = get_class_byte_count(&cogent_class);
+       snprintf(argv[0], 1024, "N:%lu", packet_count);
+       rrd_update_r("/var/rrdtool/cogent.rrd", NULL, 1, argv);
+        packet_count = get_class_byte_count(&orion_class);
+       snprintf(argv[0], 1024, "N:%lu", packet_count);
+       rrd_update_r("/var/rrdtool/orion.rrd", NULL, 1, argv);
+        packet_count = get_class_byte_count(&campus_class);
+       snprintf(argv[0], 1024, "N:%lu", packet_count);
+       rrd_update_r("/var/rrdtool/campus.rrd", NULL, 1, argv);
+       if (rrd_test_error()) {
+               fprintf(stderr, "ERROR: %s\n", rrd_get_error());
+               rrd_clear_error();
+       }
+        sleep(5);
+        mirror_stats_refresh();
+    }
+}
+
diff --git a/rrdtool/rrdgraph-monthly.sh b/rrdtool/rrdgraph-monthly.sh
new file mode 100755 (executable)
index 0000000..4aeff09
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+/usr/bin/rrdtool graph /mirror/root/stats_monthly.png \
+-s -1m \
+--imgformat=PNG \
+--title='Mirror Traffic' \
+--base=1000 \
+--height=120 \
+--width=600 \
+--alt-autoscale-max \
+--lower-limit=0 \
+--vertical-label='bits per second' \
+--slope-mode \
+--font TITLE:10: \
+--font AXIS:8: \
+--font LEGEND:8: \
+--font UNIT:8: \
+DEF:a="/var/rrdtool/cogent.rrd":snmp_oid:AVERAGE \
+DEF:b="/var/rrdtool/orion.rrd":snmp_oid:AVERAGE \
+DEF:c="/var/rrdtool/campus.rrd":snmp_oid:AVERAGE \
+CDEF:cdefa=a,8,* \
+CDEF:cdefe=b,8,* \
+CDEF:cdefi=c,8,* \
+CDEF:cdefbc=TIME,1318318854,GT,a,a,UN,0,a,IF,IF,TIME,1318318854,GT,b,b,UN,0,b,IF,IF,TIME,1318318854,GT,c,c,UN,0,c,IF,IF,+,+,8,* \
+AREA:cdefa#157419FF:"Cogent"  \
+GPRINT:cdefa:LAST:"Current\:%8.2lf%s"  \
+GPRINT:cdefa:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefa:MAX:"Maximum\:%8.2lf%s\n"  \
+AREA:cdefe#00CF00FF:"Orion":STACK \
+GPRINT:cdefe:LAST:" Current\:%8.2lf%s"  \
+GPRINT:cdefe:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefe:MAX:"Maximum\:%8.2lf%s\n"  \
+AREA:cdefi#EE5019FF:"Campus":STACK \
+GPRINT:cdefi:LAST:"Current\:%8.2lf%s"  \
+GPRINT:cdefi:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefi:MAX:"Maximum\:%8.2lf%s\n"  \
+LINE1:cdefbc#000000FF:"Total"  \
+GPRINT:cdefbc:LAST:" Current\:%8.2lf%s"  \
+GPRINT:cdefbc:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefbc:MAX:"Maximum\:%8.2lf%s\n" >/dev/null 2>/dev/null
diff --git a/rrdtool/rrdgraph-yearly.sh b/rrdtool/rrdgraph-yearly.sh
new file mode 100755 (executable)
index 0000000..86b556b
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+/usr/bin/rrdtool graph /mirror/root/stats_yearly.png \
+-s -1y \
+--imgformat=PNG \
+--title='Mirror Traffic' \
+--base=1000 \
+--height=120 \
+--width=600 \
+--alt-autoscale-max \
+--lower-limit=0 \
+--vertical-label='bits per second' \
+--slope-mode \
+--font TITLE:10: \
+--font AXIS:8: \
+--font LEGEND:8: \
+--font UNIT:8: \
+DEF:a="/var/rrdtool/cogent.rrd":snmp_oid:AVERAGE \
+DEF:b="/var/rrdtool/orion.rrd":snmp_oid:AVERAGE \
+DEF:c="/var/rrdtool/campus.rrd":snmp_oid:AVERAGE \
+CDEF:cdefa=a,8,* \
+CDEF:cdefe=b,8,* \
+CDEF:cdefi=c,8,* \
+CDEF:cdefbc=TIME,1318318854,GT,a,a,UN,0,a,IF,IF,TIME,1318318854,GT,b,b,UN,0,b,IF,IF,TIME,1318318854,GT,c,c,UN,0,c,IF,IF,+,+,8,* \
+AREA:cdefa#157419FF:"Cogent"  \
+GPRINT:cdefa:LAST:"Current\:%8.2lf%s"  \
+GPRINT:cdefa:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefa:MAX:"Maximum\:%8.2lf%s\n"  \
+AREA:cdefe#00CF00FF:"Orion":STACK \
+GPRINT:cdefe:LAST:" Current\:%8.2lf%s"  \
+GPRINT:cdefe:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefe:MAX:"Maximum\:%8.2lf%s\n"  \
+AREA:cdefi#EE5019FF:"Campus":STACK \
+GPRINT:cdefi:LAST:"Current\:%8.2lf%s"  \
+GPRINT:cdefi:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefi:MAX:"Maximum\:%8.2lf%s\n"  \
+LINE1:cdefbc#000000FF:"Total"  \
+GPRINT:cdefbc:LAST:" Current\:%8.2lf%s"  \
+GPRINT:cdefbc:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefbc:MAX:"Maximum\:%8.2lf%s\n" >/dev/null 2>/dev/null
diff --git a/rrdtool/rrdgraph.sh b/rrdtool/rrdgraph.sh
new file mode 100755 (executable)
index 0000000..72c4a73
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+/usr/bin/rrdtool graph /mirror/root/stats.png \
+--imgformat=PNG \
+--title='Mirror Traffic' \
+--base=1000 \
+--height=120 \
+--width=600 \
+--alt-autoscale-max \
+--lower-limit=0 \
+--vertical-label='bits per second' \
+--slope-mode \
+--font TITLE:10: \
+--font AXIS:8: \
+--font LEGEND:8: \
+--font UNIT:8: \
+DEF:a="/var/rrdtool/cogent.rrd":snmp_oid:AVERAGE \
+DEF:b="/var/rrdtool/orion.rrd":snmp_oid:AVERAGE \
+DEF:c="/var/rrdtool/campus.rrd":snmp_oid:AVERAGE \
+CDEF:cdefa=a,8,* \
+CDEF:cdefe=b,8,* \
+CDEF:cdefi=c,8,* \
+CDEF:cdefbc=TIME,1318318854,GT,a,a,UN,0,a,IF,IF,TIME,1318318854,GT,b,b,UN,0,b,IF,IF,TIME,1318318854,GT,c,c,UN,0,c,IF,IF,+,+,8,* \
+AREA:cdefa#157419FF:"Cogent"  \
+GPRINT:cdefa:LAST:"Current\:%8.2lf%s"  \
+GPRINT:cdefa:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefa:MAX:"Maximum\:%8.2lf%s\n"  \
+AREA:cdefe#00CF00FF:"Orion":STACK \
+GPRINT:cdefe:LAST:" Current\:%8.2lf%s"  \
+GPRINT:cdefe:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefe:MAX:"Maximum\:%8.2lf%s\n"  \
+AREA:cdefi#EE5019FF:"Campus":STACK \
+GPRINT:cdefi:LAST:"Current\:%8.2lf%s"  \
+GPRINT:cdefi:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefi:MAX:"Maximum\:%8.2lf%s\n"  \
+LINE1:cdefbc#000000FF:"Total"  \
+GPRINT:cdefbc:LAST:" Current\:%8.2lf%s"  \
+GPRINT:cdefbc:AVERAGE:"Average\:%8.2lf%s"  \
+GPRINT:cdefbc:MAX:"Maximum\:%8.2lf%s\n" >/dev/null 2>/dev/null