--- /dev/null
+#!/usr/bin/python
+
+import sys
+sys.path.append('/usr/lib/xen-default/lib/python/')
+from xen.lowlevel import xs
+from collections import defaultdict
+import os
+import re
+
+xsc = xs.xs()
+
+def live_vms():
+ domids = set(xsc.ls('', '/local/domain'))
+
+ vms = dict()
+
+ for domid in domids:
+ try:
+ uuid, data = get_dom(int(domid))
+ except (xs.Error, TypeError, AttributeError):
+ continue # went down since we started
+ vms[uuid] = data
+ return vms
+
+def get_dom(domid):
+ data = dict(domid=domid)
+ data['name'] = xsc.read('', '/local/domain/%d/name' % domid)
+ data['uuid'] = xsc.read('', '/local/domain/%d/vm' % domid)[4:]
+ if data['name'][0:2] == 'd_':
+ data['munin_name'] = 'db domid %d' % domid
+ else:
+ data['munin_name'] = data['name']
+ data['munin_var'] = 'uuid_'+data['uuid'].replace('-', '_')
+ return data['munin_var'], data
+
+def parse_net_dev():
+ """Parse /proc/net/dev to determine down/up counters for each interface.
+
+ N.B. Note that "down" and "up" are with respect to the host.
+ """
+ usage = {}
+ for line in open('/proc/net/dev', 'r'):
+ if ':' not in line:
+ continue # skip header lines
+ iface, fields = line.split(':')
+ iface = iface.strip()
+ fields = fields.split()
+ usage[iface] = {'down': int(fields[0]),
+ 'up': int(fields[8])}
+ return usage
+
+IFACE_NAME_RE = re.compile(r'^(vif|tap)(\d+)\.(\d+)$')
+
+def get_net_usage():
+ """Group /proc/net/dev counters by domain.
+
+ N.B. Note that "down" and "up" are reversed - from the perspective of the guest.
+ """
+ by_dev = parse_net_dev()
+ by_domain = defaultdict(lambda: {'down': 0, 'up': 0})
+ for iface in by_dev:
+ m = IFACE_NAME_RE.match(iface)
+ if m:
+ viftype, domid, ifcount = m.groups()
+ domid = int(domid)
+ by_domain[domid]['down'] += by_dev[iface]['up']
+ by_domain[domid]['up'] += by_dev[iface]['down']
+ return by_domain
+
+if __name__ == '__main__':
+ if len(sys.argv) > 1:
+ cmd = sys.argv[1]
+ else:
+ cmd = None
+
+ domains = live_vms()
+
+ if cmd == 'config':
+ print """
+ graph_title Xen domain network usage
+ graph_args --base 1000
+ graph_vlabel bits in (-) / out (+) per ${graph_period}
+ graph_info This graph shows how network is utilized by Xen domains.
+ graph_category network
+ graph_period second"""
+ for d in sorted(domains):
+ for direction in ('down', 'up'):
+ key = "%s_%s" % (d, direction)
+ print "%s.label %s" % (key, domains[d]['munin_name'])
+ print "%s.draw AREASTACK" % key
+ print "%s.max 10000000000" % key
+ print "%s.min 0" % key
+ print "%s.type DERIVE" % key
+ print "%s.cdef %s,8,*" % (key, key)
+ if direction == 'down':
+ print "%s.graph no" % key
+ else:
+ print "%s.negative %s_down" % (key, d)
+ print "%s.info uuid %s" % (key, domains[d]['uuid'])
+ sys.exit(0)
+
+ net_usage = get_net_usage()
+
+ for d in sorted(domains):
+ for direction in ('down', 'up'):
+ print "%s_%s.value %d" % (d, direction, net_usage[domains[d]['domid']][direction])