--- a/bin/pvl.hosts-graph Mon Mar 31 17:30:42 2014 +0300
+++ b/bin/pvl.hosts-graph Mon Mar 31 18:19:59 2014 +0300
@@ -184,6 +184,7 @@
nodes_port = { } # (local, int(local_port)): remote
nodes_out = { } # local: {remote}
+ nodes_in = { } # remote: {local}
links_out = { } # (local, remote): local_port
links_in = { } # (remote, local): remote_port
@@ -268,6 +269,7 @@
links_out[(local_node, remote_node)] = local_port
nodes_port[(local_node, port)] = remote_node
nodes_out.setdefault(local_node, set()).add(remote_node)
+ nodes_in.setdefault(remote_node, set()).add(local_node)
# bidirectional mappings
remote_port = remote_attrs['port']
@@ -349,6 +351,7 @@
links_out[(local_node, remote_node)] = port
nodes_port[(local_node, port)] = remote_node
nodes_out.setdefault(local_node, set()).add(remote_node)
+ nodes_in.setdefault(remote_node, set()).add(local_node)
# update directional or missing links
remote_port = links_out.get((remote_node, local_node))
@@ -386,17 +389,23 @@
links[(local_node, local_port, None, remote_node)] = None
if options.graph_bridge :
+ # scan hosts with bridges
+ bridge_hosts = set()
+
+ for host, host_attrs in snmp.iteritems() :
+ if 'bridge' in host_attrs or any('bridge' in vlan_attrs for vlan_attrs in host_attrs.get('vlan', { }).itervalues()) :
+ bridge_hosts.add(host)
+
# third graph: bridge
for host, host_attrs in snmp.iteritems() :
- local_node = host
-
- node_out = nodes_out.get(local_node)
+ local_out = nodes_out.get(host)
- if not node_out :
+ if not local_out :
log.warning("%s: no outgoing links, skipping bridge", host)
continue
-
- bridge = { }
+
+ # scan vlan/port bridge ethers
+ bridge = { } # (port, vlan): {ethernet}
for port, ethernets in host_attrs.get('bridge', { }).iteritems() :
bridge[(port, None)] = ethernets
@@ -406,11 +415,31 @@
bridge[(port, vlan)] = ethernets
for (port, vlan), ethernets in bridge.iteritems() :
+ local_node = host
local_port = port
remote_node = nodes_port.get((local_node, local_port))
+
+ if remote_node :
+ remote_in = nodes_in.get(remote_node, set())
+ else :
+ remote_in = set()
- if remote_node :
+ remote_leaf = (remote_in == set((host, )))
+
+ # TODO: add ether node and link if remote node also has this ether on this link
+ # also do this if all remote_in's agree that the ether is on the remote_node
+ if not remote_node :
+ log.debug("%s:%s: no remote node", host, port)
+
+ elif remote_leaf and (remote_node not in bridge_hosts) and len(ethernets) > 1 :
+ log.info("%s:%s: map onto non-bridge leaf remote %s", host, port, remote_node)
+
+ # map links out of the assumed remote bridge
+ local_node = remote_node
+ local_port = None
+
+ else :
log.debug("%s:%s/%s bridge skip -> %s", host, port, vlan, remote_node)
continue
@@ -424,10 +453,15 @@
log.debug("%s:%s/%s bridge %s = %s (%s)", host, port, vlan, ethernet, remote_host, remote_label)
else :
remote_node = remote_host = None
+
+ log.debug("%s:%s/%s bridge %s ?", host, port, vlan, ethernet)
if not remote_host :
continue
+ elif remote_host == host and local_node != host :
+ log.debug("%s:%s: skip remote-mapped self", host, port)
+
if remote_node not in nodes :
log.debug("%s:%s: lazy-add remote %s (%s)", host, port, remote_node, remote_label)
@@ -448,7 +482,7 @@
if remote_port :
reverse = (remote_node, remote_port, None, local_node)
- log.info("%s:%s <-> %s:%s", local_node, local_port, remote_port, remote_host)
+ log.info("%s:%s bridge <-> %s:%s", local_node, local_port, remote_port, remote_host)
# fill in remote_port for bidirectional link
del links[reverse]
@@ -456,7 +490,7 @@
links[reverse] = link_vlans
else :
- log.info("%s:%s -> %s", local_node, local_port, remote_host)
+ log.info("%s:%s bridge -> %s", local_node, local_port, remote_host)
links[forward] = link_vlans