1#!/usr/bin/python 2# Copyright (c) PLUMgrid, Inc. 3# Licensed under the Apache License, Version 2.0 (the "License") 4 5from bcc import BPF 6from ctypes import c_uint, c_int, c_ulonglong, Structure 7import json 8from netaddr import IPAddress 9from os import rename 10from pyroute2 import IPRoute, NetNS, IPDB, NSPopen 11import sys 12from time import sleep 13 14ipr = IPRoute() 15ipdb = IPDB(nl=ipr) 16 17b = BPF(src_file="monitor.c", debug=0) 18ingress_fn = b.load_func("handle_ingress", BPF.SCHED_CLS) 19egress_fn = b.load_func("handle_egress", BPF.SCHED_CLS) 20outer_fn = b.load_func("handle_outer", BPF.SCHED_CLS) 21inner_fn = b.load_func("handle_inner", BPF.SCHED_CLS) 22stats = b.get_table("stats") 23# using jump table for inner and outer packet split 24parser = b.get_table("parser") 25parser[c_int(1)] = c_int(outer_fn.fd) 26parser[c_int(2)] = c_int(inner_fn.fd) 27 28ifc = ipdb.interfaces.eth0 29 30ipr.tc("add", "ingress", ifc.index, "ffff:") 31ipr.tc("add-filter", "bpf", ifc.index, ":1", fd=ingress_fn.fd, 32 name=ingress_fn.name, parent="ffff:", action="ok", classid=1) 33ipr.tc("add", "sfq", ifc.index, "1:") 34ipr.tc("add-filter", "bpf", ifc.index, ":1", fd=egress_fn.fd, 35 name=egress_fn.name, parent="1:", action="ok", classid=1) 36 37def stats2json(k, v): 38 return { 39 "vni": int(k.vni), 40 "outer_sip": str(IPAddress(k.outer_sip)), 41 "outer_dip": str(IPAddress(k.outer_dip)), 42 "inner_sip": str(IPAddress(k.inner_sip)), 43 "inner_dip": str(IPAddress(k.inner_dip)), 44 "tx_pkts": v.tx_pkts, "tx_bytes": v.tx_bytes, 45 "rx_pkts": v.rx_pkts, "rx_bytes": v.rx_bytes, 46 } 47 48def delta_stats(v, oldv): 49 return stats.Leaf(v.tx_pkts - oldv.tx_pkts, v.rx_pkts - oldv.rx_pkts, 50 v.tx_bytes - oldv.tx_bytes, v.rx_bytes - oldv.rx_bytes) 51def key2str(k): 52 return "%s,%s,%d,%s,%s" % (IPAddress(k.outer_sip), IPAddress(k.outer_dip), k.vni, 53 IPAddress(k.inner_sip), IPAddress(k.inner_dip)) 54 55prev = {} 56 57while True: 58 result_total = [] 59 result_delta = [] 60 tmp = {} 61 # compute both the total and last-N-seconds statistics 62 for k, v in stats.items(): 63 # subtract the previous totals from the current, or 0 if none exists 64 v2 = delta_stats(v, prev.get(key2str(k), stats.Leaf(0, 0, 0, 0))) 65 if v2.tx_pkts != 0 or v2.rx_pkts != 0: 66 result_delta.append(stats2json(k, v2)) 67 tmp[key2str(k)] = v 68 result_total.append(stats2json(k, v)) 69 70 prev = tmp 71 72 with open("./chord-transitions/data/tunnel.json.new", "w") as f: 73 json.dump(result_total, f) 74 rename("./chord-transitions/data/tunnel.json.new", "./chord-transitions/data/tunnel.json") 75 with open("./chord-transitions/data/tunnel-delta.json.new", "w") as f: 76 json.dump(result_delta, f) 77 rename("./chord-transitions/data/tunnel-delta.json.new", "./chord-transitions/data/tunnel-delta.json") 78 sleep(5) 79ipdb.release() 80 81