summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Pouzenc <ludovic@pouzenc.fr>2016-05-16 01:19:53 +0200
committerLudovic Pouzenc <ludovic@pouzenc.fr>2016-05-16 01:19:53 +0200
commitcc70191abcb928d2ec057b7aa04683c2ce8491e1 (patch)
tree24e6237649d128156dc307832cceefefd1d5ee2b
parentf8b71c3606ca201a4f0abedd2155819f288f5d63 (diff)
downloadhaircontrol-cc70191abcb928d2ec057b7aa04683c2ce8491e1.zip
haircontrol-cc70191abcb928d2ec057b7aa04683c2ce8491e1.tar.gz
haircontrol-cc70191abcb928d2ec057b7aa04683c2ce8491e1.tar.bz2
Implement parsing of brmacs.cgi and status.cgi (only for local interfaces)
-rw-r--r--haircontrol/data.py11
-rw-r--r--haircontrol/discovery.py30
-rw-r--r--haircontrol/inspectors.py40
3 files changed, 71 insertions, 10 deletions
diff --git a/haircontrol/data.py b/haircontrol/data.py
index 6f5733d..8adf75f 100644
--- a/haircontrol/data.py
+++ b/haircontrol/data.py
@@ -37,6 +37,13 @@ class Equipment:
def __repr__(self):
return repr( (self.name, self.mgmtip, list(self.ifaces.values())) )
+ def add_iface(self, ifname, mac):
+ iface = self.ifaces.get(ifname)
+ if iface:
+ iface.mac = mac
+ else:
+ self.ifaces[ifname] = Interface(ifname, mac)
+
def add_seen_mac(self, ifname, mac):
iface = self.ifaces.get(ifname)
if not iface:
@@ -52,6 +59,6 @@ class Interface:
self.mac_seen = []
def __repr__(self):
- return repr( ( self.mac, self.name, self.mac_seen ) )
- #return repr( ( self.mac, self.name, '[ %i mac_seen ]'%len(self.mac_seen) ) )
+ #return repr( ( self.mac, self.name, self.mac_seen ) )
+ return repr( ( self.mac, self.name, '[ %i mac_seen ]'%len(self.mac_seen) ) )
diff --git a/haircontrol/discovery.py b/haircontrol/discovery.py
index 243e3b6..5f63349 100644
--- a/haircontrol/discovery.py
+++ b/haircontrol/discovery.py
@@ -5,6 +5,7 @@ from haircontrol.inspectors import *
class Discovery:
def __init__(self): #, inspector):
+ # XXX Use only one Inspector
self.linux_inspector = LinuxInspector()
self.ubnt_inspector = UbntInspector()
self.net = EtherDomain()
@@ -15,16 +16,19 @@ class Discovery:
# Learn local interfaces of e_lldp
result = self.linux_inspector.command('ip-link')
- for (_, ifname, mac) in result:
- e_lldp.ifaces[ifname] = Interface(ifname, mac)
+ for (ifname, mac) in result:
+ if ifname not in [ 'lo' ]: # XXX configurable filter
+ e_lldp.add_iface(ifname, mac)
# Create equipments and ifaces from LLDP neighbour discovery
result = self.linux_inspector.command('lldpctl')
for (local_ifname, local_mac, remote_name, remote_ipmgmt, ports) in result:
e = Equipment(remote_name, remote_ipmgmt)
self.net.add_equipment(e)
+ # lldp returns logical port, not physicial port for remote bridges
for remote_ifname in ports:
- e.add_seen_mac(remote_ifname, local_mac)
+ if remote_ifname not in [ 'br0' ]: # XXX configurable filter
+ e.add_seen_mac(remote_ifname, local_mac)
self.linux_inspector.disconnect()
@@ -32,6 +36,7 @@ class Discovery:
self.net.add_equipment(e_root)
self.linux_inspector.connect(e_root)
+ # Learn root neighbours
result = self.linux_inspector.command('ip-neigh')
for (ip, ifname, mac) in result:
self.net.index_mac_ip(mac, ip)
@@ -39,3 +44,22 @@ class Discovery:
self.linux_inspector.disconnect()
+ # Inspect antennas bridge tables
+ for ip in self.net.equipments:
+ if ip.startswith('172.16.1'): # XXX Use neighbours, filter with OUI
+ e = self.net.equipments[ip]
+ self.ubnt_inspector.connect(e)
+
+ # Learn local interfaces
+ result = self.ubnt_inspector.command('status.cgi')
+ for (ifname, mac) in result:
+ if ifname not in [ 'lo', 'wifi0', 'br0' ]: # XXX configurable filter
+ e.add_iface(ifname, mac)
+
+ # Learn bridge tables
+ result = self.ubnt_inspector.command('brmacs.cgi')
+ for (ifname, mac) in result:
+ e.add_seen_mac(ifname, mac)
+
+ self.ubnt_inspector.disconnect()
+
diff --git a/haircontrol/inspectors.py b/haircontrol/inspectors.py
index 33bf360..f59287a 100644
--- a/haircontrol/inspectors.py
+++ b/haircontrol/inspectors.py
@@ -1,4 +1,5 @@
import re
+import json
import xml.etree.ElementTree
class Inspector():
@@ -68,7 +69,7 @@ class LinuxInspector(Inspector):
'ip-link': {
'cmd': 'ip -o link',
'kind': 'text',
- 're': re.compile("(?P<id>\d+):\s+(?P<ifname>[^:]*):.+\s+(?:link/ether\s+(?P<mac>[a-f0-9:]*)\s+brd|link/none)")
+ 're': re.compile("\d+:\s+(?P<ifname>[^:]*):.+\s+(?:link/ether\s+(?P<mac>[a-f0-9:]*)\s+brd|link/none)")
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default \ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000\ link/ether 8c:89:a5:c7:be:88 brd ff:ff:ff:ff:ff:ff
},
@@ -103,21 +104,50 @@ class LinuxInspector(Inspector):
class UbntInspector(Inspector):
+ def _parse_cgi_json(self, fd):
+ for cgi_headers in fd:
+ if cgi_headers == '\n':
+ break
+ js = {}
+ try:
+ js = json.load(fd)
+ except ValueError:
+ print("Warn : unparsable json")
+ fd.close()
+ return js
+
def parse_status_json(self, fd):
- return 'parse_status_json'
+ result = []
+ interfaces = self._parse_cgi_json(fd).get('interfaces')
+ # XXX dup parse_brmacs_json(fd) and many other cool info to get
+ if interfaces:
+ for line in interfaces:
+ if isinstance(line, dict):
+ ifname = line.get('ifname')
+ mac = line.get('hwaddr')
+ result.append( (ifname, mac) )
+ return result
def parse_brmacs_json(self, fd):
- return 'parse_brmacs_json'
+ result = []
+ brmacs = self._parse_cgi_json(fd).get('brmacs')
+ if brmacs:
+ for line in brmacs:
+ if isinstance(line, dict):
+ ifname = line.get('port')
+ mac = line.get('hwaddr')
+ result.append( (ifname, mac) )
+ return result
+
cmds = {
'status.cgi': {
'cmd':'..',
- 'kind': 'cgi-json',
'func': parse_status_json
},
'brmacs.cgi': {
'cmd':'..',
- 'kind': 'cgi-json',
'func': parse_brmacs_json
}
}
+