diff --git a/webapp/app.py b/webapp/app.py index f654e206..de7f2fbb 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -14,6 +14,7 @@ import mobility_routes import node_routes import service_routes import session_routes +import throughput_routes import websocket_routes import wlan_routes import xml_routes @@ -45,6 +46,7 @@ register_blueprint(mobility_routes) register_blueprint(node_routes) register_blueprint(service_routes) register_blueprint(session_routes) +register_blueprint(throughput_routes) register_blueprint(wlan_routes) register_blueprint(xml_routes) diff --git a/webapp/session_routes.py b/webapp/session_routes.py index 5228425d..3608cc99 100644 --- a/webapp/session_routes.py +++ b/webapp/session_routes.py @@ -42,7 +42,7 @@ def create_session(): session.config_handlers.append(websocket_routes.broadcast_config) session.link_handlers.append(websocket_routes.broadcast_link) session.exception_handlers.append(websocket_routes.broadcast_exception) - session.file_handlers.append(websocket_routes.broadtcast_file) + session.file_handlers.append(websocket_routes.broadcast_file) response_data = jsonify( id=session.session_id, diff --git a/webapp/throughput_routes.py b/webapp/throughput_routes.py new file mode 100644 index 00000000..e0c5a727 --- /dev/null +++ b/webapp/throughput_routes.py @@ -0,0 +1,96 @@ +import re +import threading +import time + +from flask import jsonify +from flask.blueprints import Blueprint + +import websocket_routes + +coreemu = None +_interface_regex = re.compile("\d+") +_throughput_thread = None +_thread_flag = True + +api = Blueprint("throughput_api", __name__) + + +def get_net_stats(): + with open("/proc/net/dev", "r") as net_stats: + data = net_stats.readlines()[2:] + + stats = {} + for line in data: + line = line.strip() + if not line: + continue + line = line.split() + line[0] = line[0].strip(":") + stats[line[0]] = {"rx": float(line[1]), "tx": float(line[9])} + + return stats + + +def throughput_collector(delay=3): + global _thread_flag + _thread_flag = True + last_check = None + last_stats = None + while _thread_flag: + now = time.time() + stats = get_net_stats() + + # calculate average + if last_check is not None: + interval = now - last_check + bridges = [] + interfaces = [] + for key, current_rxtx in stats.iteritems(): + previous_rxtx = last_stats.get(key) + if not previous_rxtx: + print "skipping %s, no previous value" % key + continue + rx_kbps = (current_rxtx["rx"] - previous_rxtx["rx"]) * 8.0 / interval + tx_kbps = (current_rxtx["tx"] - previous_rxtx["tx"]) * 8.0 / interval + throughput = rx_kbps + tx_kbps + print "%s - %s" % (key, throughput) + if key.startswith("veth"): + key = key.split(".") + node_id = int(_interface_regex.search(key[0]).group()) + interface_id = int(key[1]) + interfaces.append({"node": node_id, "interface": interface_id, "throughput": throughput}) + elif key.startswith("b."): + node_id = key.split(".")[1] + bridges.append({"node": node_id, "throughput": throughput}) + + throughputs = {"bridges": bridges, "interfaces": interfaces} + websocket_routes.socketio.emit("throughput", throughputs) + # for interface in sorted(interfaces, key=lambda x: x["node"]): + # print "%s:%s - %s" % (interface["node"], interface["interface"], interface["throughput"]) + # for bridge in sorted(bridges, key=lambda x: x["node"]): + # print "%s - %s" % (bridge["node"], bridge["throughput"]) + + last_check = now + last_stats = stats + time.sleep(delay) + + +@api.route("/throughput/start", methods=["PUT"]) +def start_throughput(): + global _throughput_thread + if not _throughput_thread: + _throughput_thread = threading.Thread(target=throughput_collector) + _throughput_thread.daemon = True + _throughput_thread.start() + return jsonify() + + +@api.route("/throughput/stop", methods=["PUT"]) +def stop_throughput(): + global _throughput_thread + global _thread_flag + if _throughput_thread: + _thread_flag = False + _throughput_thread.join() + _throughput_thread = None + return jsonify() diff --git a/webapp/websocket_routes.py b/webapp/websocket_routes.py index d6079fef..800d7bfb 100644 --- a/webapp/websocket_routes.py +++ b/webapp/websocket_routes.py @@ -19,7 +19,7 @@ def register(app): logger.info("websocket client disconnected") -def broadtcast_file(file_data): +def broadcast_file(file_data): socketio.emit("file", { "message_type": file_data.message_type, "node": file_data.node,