statistics.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/env python3
  2. import socket
  3. #import netifaces as netif
  4. import subprocess
  5. import re
  6. from lib.respondd import Respondd
  7. import lib.helper
  8. class Statistics(Respondd):
  9. def __init__(self, config):
  10. Respondd.__init__(self, config)
  11. def getClients(self):
  12. output = subprocess.check_output(["batctl", "-m", self._config['batman'], "tl", "-n"])
  13. output_utf8 = output.decode("utf-8")
  14. lines = output_utf8.splitlines()
  15. batadv_mac = lib.helper.getDevice_MAC(self._config['batman'])
  16. j = {"total": 0, "wifi": 0}
  17. for line in lines:
  18. # batman-adv -> translation-table.c -> batadv_tt_local_seq_print_text
  19. # R = BATADV_TT_CLIENT_ROAM
  20. # P = BATADV_TT_CLIENT_NOPURGE
  21. # N = BATADV_TT_CLIENT_NEW
  22. # X = BATADV_TT_CLIENT_PENDING
  23. # W = BATADV_TT_CLIENT_WIFI
  24. # I = BATADV_TT_CLIENT_ISOLA
  25. # . = unset
  26. # * c0:11:73:b2:8f:dd -1 [.P..W.] 1.710 (0xe680a836)
  27. ml = re.match(r"^\s\*\s([0-9a-f:]+)\s+-\d\s\[([RPNXWI\.]+)\]", line, re.I)
  28. if ml:
  29. if not batadv_mac == ml.group(1): # Filter bat0
  30. if not ml.group(1).startswith('33:33:') and not ml.group(1).startswith('01:00:5e:'): # Filter Multicast
  31. j["total"] += 1
  32. if ml.group(2)[4] == 'W':
  33. j["wifi"] += 1
  34. return j
  35. def getTraffic(self): # TODO: design rework needed!
  36. return (lambda fields: dict(
  37. (key, dict(
  38. (type_, int(value_))
  39. for key_, type_, value_ in fields
  40. if key_ == key))
  41. for key in ['rx', 'tx', 'forward', 'mgmt_rx', 'mgmt_tx']
  42. ))(list(
  43. (
  44. key.replace('_bytes', '').replace('_dropped', ''),
  45. 'bytes' if key.endswith('_bytes') else 'dropped' if key.endswith('_dropped') else 'packets',
  46. value
  47. )
  48. for key, value in map(lambda s: list(map(str.strip, s.split(': ', 1))), lib.helper.call(['ethtool', '-S', self._config['batman']])[1:])
  49. ))
  50. def getMemory(self): # TODO: design rework needed!
  51. return dict(
  52. (key.replace('Mem', '').lower(), int(value.split(' ')[0]))
  53. for key, value in map(lambda s: map(str.strip, s.split(': ', 1)), open('/proc/meminfo').readlines())
  54. if key in ('MemTotal', 'MemFree', 'Buffers', 'Cached')
  55. )
  56. def getFastd(self):
  57. fastd_data = b""
  58. try:
  59. sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  60. sock.connect(config["fastd_socket"])
  61. except socket.error as err:
  62. print("socket error: ", sys.stderr, err)
  63. return None
  64. while True:
  65. data = sock.recv(1024)
  66. if not data:
  67. break
  68. fastd_data += data
  69. sock.close()
  70. return json.loads(fastd_data.decode("utf-8"))
  71. def getMeshVPNPeers(self):
  72. j = {}
  73. if "fastd_socket" in self._config:
  74. fastd = self.getFastd()
  75. for peer in fastd["peers"].values():
  76. if peer["connection"]:
  77. j[peer["name"]] = {
  78. "established": peer["connection"]["established"]
  79. }
  80. else:
  81. j[peer["name"]] = None
  82. return j
  83. else:
  84. return None
  85. def getGateway(self):
  86. output = subprocess.check_output(["batctl", "-m", self._config['batman'], "gwl", "-n"])
  87. output_utf8 = output.decode("utf-8")
  88. lines = output_utf8.splitlines()
  89. j = None
  90. for line in lines:
  91. gw_line = re.match(r"^(\*|=>) +([0-9a-f:]+) \([\d ]+\) ([0-9a-f:]+)", line)
  92. if gw_line:
  93. j = {}
  94. j["gateway"] = gw_line.group(2)
  95. j["gateway_nexthop"] = gw_line.group(3)
  96. return j
  97. def get(self):
  98. j = {
  99. "clients": self.getClients(),
  100. "traffic": self.getTraffic(),
  101. "idletime": float(open('/proc/uptime').read().split(' ')[1]),
  102. "loadavg": float(open('/proc/loadavg').read().split(' ')[0]),
  103. "memory": self.getMemory(),
  104. "processes": dict(zip(('running', 'total'), map(int, open('/proc/loadavg').read().split(' ')[3].split('/')))),
  105. "uptime": float(open('/proc/uptime').read().split(' ')[0]),
  106. "mesh_vpn" : { # HopGlass-Server: node.flags.uplink = parsePeerGroup(_.get(n, 'statistics.mesh_vpn'))
  107. "groups": {
  108. "backbone": {
  109. "peers": self.getMeshVPNPeers()
  110. }
  111. }
  112. }
  113. }
  114. gateway = self.getGateway()
  115. if gateway != None:
  116. j = lib.helper.merge(j, gateway)
  117. return j