pvl.hosts-lldp: handle non-lldp-supporting switches, use dot1q per default for (port, vlan) leaf node mappings, with fallback to dot1d
authorTero Marttila <terom@paivola.fi>
Tue, 18 Mar 2014 21:25:35 +0200
changeset 398 de275bf6db70
parent 397 8455f42d8926
child 399 aadf76a05ec1
pvl.hosts-lldp: handle non-lldp-supporting switches, use dot1q per default for (port, vlan) leaf node mappings, with fallback to dot1d
bin/pvl.hosts-lldp
--- a/bin/pvl.hosts-lldp	Tue Mar 18 21:24:35 2014 +0200
+++ b/bin/pvl.hosts-lldp	Tue Mar 18 21:25:35 2014 +0200
@@ -51,6 +51,10 @@
         except snmp.SNMPError as ex :
             log.warning("%s: %s", host, ex)
             continue
+        
+        if not local :
+            log.info("%s: no lldp support", host)
+            continue
 
         log.info("%s: %s", host, local)
 
@@ -117,7 +121,13 @@
     
     # second pass to discver links
     for host, agent in _hosts_lldp :
-        for port, remote in agent.remotes() :
+        try :
+            remotes = list(agent.remotes())
+        except snmp.SNMPError as ex :
+            log.warn("%s: broken lldp remotes: %s", host, ex)
+            continue
+
+        for port, remote in remotes :
             port = agent.port(port)
 
             remote_chassis = remote['chassis']
@@ -145,7 +155,7 @@
         # multiple taggd vlans / port
         vlan_tagged = collections.defaultdict(set)
 
-        for vlan, (tagged, untagged) in agent.vlans() :
+        for vlan, (tagged, untagged) in agent.vlan_ports() :
             log.info("%s: %s: %s + %s", host, vlan, tagged, untagged)
             
             for port in tagged :
@@ -174,10 +184,38 @@
     for host, agent in hosts_bridge(options, hosts) :
         ports = collections.defaultdict(list)
 
-        for ether, port in agent.fdb() :
-            if port :
-                ports[port].append(ether)
-        
+        try :
+            vlan_fdb_ports = list(agent.vlan_fdb_ports())
+        except snmp.SNMPError as ex :
+            log.warn("%s: broken dot1q fdb: %s", host, ex)
+            continue
+
+        if vlan_fdb_ports :
+            log.info("%s: have dot1q ports", host)
+
+            for ether, port, vlan in agent.vlan_fdb_ports() :
+                if not port :
+                    # XXX: unknown?
+                    continue
+
+                ports[(port, vlan)].append(ether)
+        else :
+            try :
+                fdb_ports = list(agent.fdb_ports())
+            except snmp.SNMPError as ex :
+                log.warn("%s: broken dot1q fdb: %s", host, ex)
+                continue
+            
+            # fallback to dot1d fdb
+            log.info("%s: fallback to dot1d", host)
+
+            for ether, port in agent.fdb_ports() :
+                if not port :
+                    # XXX: unknown?
+                    continue
+
+                ports[(port, None)].append(ether)
+
         yield host, ports
 
 COLOR_VLANS = {
@@ -394,11 +432,23 @@
             if remote_host :
                 print "{host:30} {host.location:>30} {local[port]:>25} <-> {remote[port]:<25} {remote_host.location:>30} # {remote[chassis]} ({remote_host})".format(host=host, local=local, remote=remote, remote_host=remote_host)
             else :
-                print "{host:30} {host.location:>30} {local[port]:>25} <-- {remote[port]:<25} {empty:30} # {remote[chassis]} ({remote[sys_name]})".format(host=host, local=local, remote=remote, empty='')
+                print "{host:30} {host.location:>30} {local[port]:>25} --> {remote[port]:<25} {empty:30} # {remote[chassis]} ({remote[sys_name]})".format(host=host, local=local, remote=remote, empty='')
        
+        for host, ports in vlans.iteritems() :
+            for port, (untag, tagged) in ports.iteritems() :
+                print "{host:30} {host.location:>30} {port:25} {untag}{tagged}".format(host=host, port=port,
+                        untag       = '({untag}) '.format(untag=untag) if untag else '',
+                        tagged      = ' '.join('<{tag}>'.format(tag=tag) for tag in tagged),
+                )
+
         for host, ports in leafs :
-            for port, ethers in ports.iteritems() :
-                print "{host:30} {host.location:>30} {port:25} <== # {ethers}".format(host=host, port=port, ethers=' '.join(ethers))
+            for (port, vlan), ethers in ports.iteritems() :
+                print "{host:30} {host.location:>30} {port:25} <-- {vlan} # {ethers}".format(
+                        host        = host,
+                        port        = port,
+                        vlan        = '<{vlan}>'.format(vlan=vlan) if vlan else '',
+                        ethers      = ' '.join(ethers),
+                )
 
 if __name__ == '__main__':
     pvl.args.main(main)