#!/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) # /vm contains a path like "/vm/UUID"; strip the "/vm/" data['uuid'] = xsc.read('', '/local/domain/%d/vm' % domid)[4:] if data['name'].startswith('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.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 print "%s.draw LINE1" % key else: print "%s.negative %s_down" % (key, d) print "%s.draw AREASTACK" % key 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])