summaryrefslogtreecommitdiff
path: root/haircontrol/discovery.py
blob: 7c3c9f000e40b56559cec2eb616fce6959d8165a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from haircontrol.data import *
from haircontrol.inspectors import *

class Discovery:

    def __init__(self): #, inspector):
        # XXX Use only one Inspector
        self.linux_inspector = LinuxInspector()
        self.ubnt_inspector = UbntInspector()
        self.toughswitch_inspector = ToughSwitchInspector()
        self.net = EtherDomain()

    def discover_static_hinting(self, name_ip_tuples):
        for name, ip in name_ip_tuples:
            self.net.add_equipment(Equipment(name, ip))

    def discover_lldp_hinting(self, e_lldp):
        self.net.add_equipment(e_lldp)
        self.linux_inspector.connect(e_lldp)

        # Learn local interfaces of e_lldp
        result = self.linux_inspector.command('ip-link')
        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:
                if remote_ifname not in [ 'br0' ]: # XXX configurable filter
                    e.add_seen_mac(remote_ifname, local_mac)

        self.linux_inspector.disconnect()

    def discover_from_root(self, e_root):
        self.net.add_equipment(e_root)
        self.linux_inspector.connect(e_root)

        # Learn root neighbours (directly or indirectly connected via trasparent bridges)
        result = self.linux_inspector.command('ip-neigh')
        for (ip, ifname, mac) in result:
            self.net.index_mac_ip(mac, ip)
            e_root.add_seen_mac(ifname, mac)

        self.linux_inspector.disconnect()

        # Create Equipment object for all neighbours (if not already previously done by hinting)
        for iface in e_root.ifaces.values():
            local_ifname = iface.name
            local_mac = iface.mac
            for remote_mac in iface.mac_seen:
                remote_ip = self.net.mac2ip.get(remote_mac)
                if remote_ip:
                    e = self.net.equipments.get(remote_ip)
                    if not e:
                        e = Equipment('?', remote_ip)
                        e.add_iface('?', remote_mac)
                        self.net.add_equipment(e)
        
        # Inspect all non-already inspected equipement
        done = False
        while not done:
            done = True
            for ip,e in self.net.equipments.items():
                if not e.inspected:
                    done = False
                    # Inspect antennas bridge tables
                    if ip.startswith('172.16.1'): # XXX Filter with OUI
                        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()
                    # Inspect switches
                    elif ip.startswith('172.16.3'): # XXX Filter with OUI
                        self.toughswitch_inspector.connect(e)
                        result = self.toughswitch_inspector.command('mactable_data.cgi')
                        for (ifname, mac) in result:
                            e.add_seen_mac(ifname, mac)
                        self.toughswitch_inspector.disconnect()
                    # Flag unknowns as inspected (and warn)
                    else:
                        e.inspected = 'cannot'
                        print("Notice: Unimplemented inspector for %s"%e)