|
@@ -1,9 +1,9 @@
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
import socket
|
|
|
-#import netifaces as netif
|
|
|
-import subprocess
|
|
|
import re
|
|
|
+import sys
|
|
|
+import json
|
|
|
|
|
|
from lib.respondd import Respondd
|
|
|
import lib.helper
|
|
@@ -14,14 +14,11 @@ class Statistics(Respondd):
|
|
|
Respondd.__init__(self, config)
|
|
|
|
|
|
def getClients(self):
|
|
|
- j = {"total": 0, "wifi": 0}
|
|
|
+ ret = {'total': 0, 'wifi': 0}
|
|
|
|
|
|
- batmanMAC = lib.helper.getDevice_MAC(self._config['batman'])
|
|
|
-
|
|
|
- output = subprocess.check_output(["batctl", "-m", self._config['batman'], "tl", "-n"])
|
|
|
- output_utf8 = output.decode("utf-8")
|
|
|
- lines = output_utf8.splitlines()
|
|
|
+ macBridge = lib.helper.getInterfaceMAC(self._config['bridge'])
|
|
|
|
|
|
+ lines = lib.helper.call(['batctl', '-m', self._config['batman'], 'tl', '-n'])
|
|
|
for line in lines:
|
|
|
# batman-adv -> translation-table.c -> batadv_tt_local_seq_print_text
|
|
|
# R = BATADV_TT_CLIENT_ROAM
|
|
@@ -32,47 +29,84 @@ class Statistics(Respondd):
|
|
|
# I = BATADV_TT_CLIENT_ISOLA
|
|
|
# . = unset
|
|
|
# * c0:11:73:b2:8f:dd -1 [.P..W.] 1.710 (0xe680a836)
|
|
|
- ml = re.match(r"^\s\*\s([0-9a-f:]+)\s+-\d\s\[([RPNXWI\.]+)\]", line, re.I)
|
|
|
- if ml:
|
|
|
- if not batmanMAC == ml.group(1): # Filter bat0
|
|
|
- if not ml.group(1).startswith('33:33:') and not ml.group(1).startswith('01:00:5e:'): # Filter Multicast
|
|
|
- j["total"] += 1
|
|
|
- if ml.group(2)[4] == 'W':
|
|
|
- j["wifi"] += 1
|
|
|
-
|
|
|
- return j
|
|
|
-
|
|
|
- def getTraffic(self): # TODO: design rework needed!
|
|
|
- return (lambda fields: dict(
|
|
|
- (key, dict(
|
|
|
- (type_, int(value_))
|
|
|
- for key_, type_, value_ in fields
|
|
|
- if key_ == key))
|
|
|
- for key in ['rx', 'tx', 'forward', 'mgmt_rx', 'mgmt_tx']
|
|
|
- ))(list(
|
|
|
- (
|
|
|
- key.replace('_bytes', '').replace('_dropped', ''),
|
|
|
- 'bytes' if key.endswith('_bytes') else 'dropped' if key.endswith('_dropped') else 'packets',
|
|
|
- value
|
|
|
- )
|
|
|
- for key, value in map(lambda s: list(map(str.strip, s.split(': ', 1))), lib.helper.call(['ethtool', '-S', self._config['batman']])[1:])
|
|
|
- ))
|
|
|
-
|
|
|
- def getMemory(self): # TODO: design rework needed!
|
|
|
- return dict(
|
|
|
- (key.replace('Mem', '').lower(), int(value.split(' ')[0]))
|
|
|
- for key, value in map(lambda s: map(str.strip, s.split(': ', 1)), open('/proc/meminfo').readlines())
|
|
|
- if key in ('MemTotal', 'MemFree', 'Buffers', 'Cached')
|
|
|
- )
|
|
|
+ #d4:3d:7e:34:5c:b1 -1 [.P....] 0.000 (0x12a02817)
|
|
|
+ lineMatch = re.match(r'^[\s*]*([0-9a-f:]+)\s+-\d\s\[([RPNXWI\.]+)\]', line, re.I)
|
|
|
+ if lineMatch:
|
|
|
+ mac = lineMatch.group(1)
|
|
|
+ flags = lineMatch.group(2)
|
|
|
+ if macBridge != mac and flags[0] != 'R': # Filter bridge and roaming clients
|
|
|
+ if not mac.startswith('33:33:') and not mac.startswith('01:00:5e:'): # Filter Multicast
|
|
|
+ ret['total'] += 1
|
|
|
+ if flags[4] == 'W':
|
|
|
+ ret['wifi'] += 1
|
|
|
+
|
|
|
+ return ret
|
|
|
+
|
|
|
+ def getTraffic(self):
|
|
|
+ traffic = {}
|
|
|
+ lines = lib.helper.call(['ethtool', '-S', self._config['batman']])
|
|
|
+ if len(lines) == 0:
|
|
|
+ return {}
|
|
|
+ for line in lines[1:]:
|
|
|
+ lineSplit = line.strip().split(':', 1)
|
|
|
+ name = lineSplit[0]
|
|
|
+ value = lineSplit[1].strip()
|
|
|
+ traffic[name] = value
|
|
|
+
|
|
|
+ ret = {
|
|
|
+ 'tx': {
|
|
|
+ 'packets': traffic['tx'],
|
|
|
+ 'bytes': traffic['tx_bytes'],
|
|
|
+ 'dropped': traffic['tx_dropped'],
|
|
|
+ },
|
|
|
+ 'rx': {
|
|
|
+ 'packets': traffic['rx'],
|
|
|
+ 'bytes': traffic['rx_bytes'],
|
|
|
+ },
|
|
|
+ 'forward': {
|
|
|
+ 'packets': traffic['forward'],
|
|
|
+ 'bytes': traffic['forward_bytes'],
|
|
|
+ },
|
|
|
+ 'mgmt_rx': {
|
|
|
+ 'packets': traffic['mgmt_rx'],
|
|
|
+ 'bytes': traffic['mgmt_rx_bytes'],
|
|
|
+ },
|
|
|
+ 'mgmt_tx': {
|
|
|
+ 'packets': traffic['mgmt_tx'],
|
|
|
+ 'bytes': traffic['mgmt_tx_bytes'],
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def getMemory():
|
|
|
+ ret = {}
|
|
|
+ lines = open('/proc/meminfo').readlines()
|
|
|
+ for line in lines:
|
|
|
+ lineSplit = line.split(' ', 1)
|
|
|
+ name = lineSplit[0][:-1]
|
|
|
+ value = lineSplit[1].strip().split(' ', 1)[0]
|
|
|
+
|
|
|
+ if name == 'MemTotal':
|
|
|
+ ret['total'] = value
|
|
|
+ elif name == 'MemFree':
|
|
|
+ ret['free'] = value
|
|
|
+ elif name == 'Buffers':
|
|
|
+ ret['buffers'] = value
|
|
|
+ elif name == 'Cached':
|
|
|
+ ret['cached'] = value
|
|
|
+
|
|
|
+ return ret
|
|
|
|
|
|
def getFastd(self):
|
|
|
- dataFastd = b""
|
|
|
+ dataFastd = b''
|
|
|
|
|
|
try:
|
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
- sock.connect(config["fastd_socket"])
|
|
|
+ sock.connect(self._config['fastd_socket'])
|
|
|
except socket.error as err:
|
|
|
- print("socket error: ", sys.stderr, err)
|
|
|
+ print('socket error: ', sys.stderr, err)
|
|
|
return None
|
|
|
|
|
|
while True:
|
|
@@ -82,54 +116,51 @@ class Statistics(Respondd):
|
|
|
dataFastd += data
|
|
|
|
|
|
sock.close()
|
|
|
- return json.loads(dataFastd.decode("utf-8"))
|
|
|
+ return json.loads(dataFastd.decode('utf-8'))
|
|
|
|
|
|
def getMeshVPNPeers(self):
|
|
|
- j = {}
|
|
|
+ ret = {}
|
|
|
|
|
|
- if "fastd_socket" in self._config:
|
|
|
+ if 'fastd_socket' in self._config:
|
|
|
fastd = self.getFastd()
|
|
|
- for peer in fastd["peers"].values():
|
|
|
- if peer["connection"]:
|
|
|
- j[peer["name"]] = {
|
|
|
- "established": peer["connection"]["established"]
|
|
|
+ for peer in fastd['peers'].values():
|
|
|
+ if peer['connection']:
|
|
|
+ ret[peer['name']] = {
|
|
|
+ 'established': peer['connection']['established']
|
|
|
}
|
|
|
else:
|
|
|
- j[peer["name"]] = None
|
|
|
+ ret[peer['name']] = None
|
|
|
|
|
|
- return j
|
|
|
+ return ret
|
|
|
else:
|
|
|
return None
|
|
|
|
|
|
def getGateway(self):
|
|
|
- j = None
|
|
|
-
|
|
|
- output = subprocess.check_output(["batctl", "-m", self._config['batman'], "gwl", "-n"])
|
|
|
- output_utf8 = output.decode("utf-8")
|
|
|
- lines = output_utf8.splitlines()
|
|
|
+ ret = None
|
|
|
|
|
|
+ lines = lib.helper.call(['batctl', '-m', self._config['batman'], 'gwl', '-n'])
|
|
|
for line in lines:
|
|
|
- gw_line = re.match(r"^(\*|=>) +([0-9a-f:]+) \([\d ]+\) ([0-9a-f:]+)", line)
|
|
|
- if gw_line:
|
|
|
- j = {}
|
|
|
- j["gateway"] = gw_line.group(2)
|
|
|
- j["gateway_nexthop"] = gw_line.group(3)
|
|
|
+ lineMatch = re.match(r'^(\*|=>) +([0-9a-f:]+) \([\d ]+\) ([0-9a-f:]+)', line)
|
|
|
+ if lineMatch:
|
|
|
+ ret = {}
|
|
|
+ ret['gateway'] = lineMatch.group(2)
|
|
|
+ ret['gateway_nexthop'] = lineMatch.group(3)
|
|
|
|
|
|
- return j
|
|
|
+ return ret
|
|
|
|
|
|
def _get(self):
|
|
|
- j = {
|
|
|
- "clients": self.getClients(),
|
|
|
- "traffic": self.getTraffic(),
|
|
|
- "idletime": float(open('/proc/uptime').read().split(' ')[1]),
|
|
|
- "loadavg": float(open('/proc/loadavg').read().split(' ')[0]),
|
|
|
- "memory": self.getMemory(),
|
|
|
- "processes": dict(zip(('running', 'total'), map(int, open('/proc/loadavg').read().split(' ')[3].split('/')))),
|
|
|
- "uptime": float(open('/proc/uptime').read().split(' ')[0]),
|
|
|
- "mesh_vpn" : { # HopGlass-Server: node.flags.uplink = parsePeerGroup(_.get(n, 'statistics.mesh_vpn'))
|
|
|
- "groups": {
|
|
|
- "backbone": {
|
|
|
- "peers": self.getMeshVPNPeers()
|
|
|
+ ret = {
|
|
|
+ 'clients': self.getClients(),
|
|
|
+ 'traffic': self.getTraffic(),
|
|
|
+ 'idletime': float(open('/proc/uptime').read().split(' ')[1]),
|
|
|
+ 'loadavg': float(open('/proc/loadavg').read().split(' ')[0]),
|
|
|
+ 'memory': self.getMemory(),
|
|
|
+ 'processes': dict(zip(('running', 'total'), map(int, open('/proc/loadavg').read().split(' ')[3].split('/')))),
|
|
|
+ 'uptime': float(open('/proc/uptime').read().split(' ')[0]),
|
|
|
+ 'mesh_vpn' : { # HopGlass-Server: node.flags.uplink = parsePeerGroup(_.get(n, 'statistics.mesh_vpn'))
|
|
|
+ 'groups': {
|
|
|
+ 'backbone': {
|
|
|
+ 'peers': self.getMeshVPNPeers()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -137,7 +168,7 @@ class Statistics(Respondd):
|
|
|
|
|
|
gateway = self.getGateway()
|
|
|
if gateway != None:
|
|
|
- j = lib.helper.merge(j, gateway)
|
|
|
+ ret = lib.helper.merge(ret, gateway)
|
|
|
|
|
|
- return j
|
|
|
+ return ret
|
|
|
|