# HG changeset patch # User Tero Marttila # Date 1396279199 -10800 # Node ID b9aa8c35741fffd8e94fc5e881b00683fcab574a # Parent cb7782e5a2fdcfd9ce0662aec95f72175643655a pvl.hosts-graph: map bridge ethers from bridge nodes onto non-bridge leaf nodes diff -r cb7782e5a2fd -r b9aa8c35741f bin/pvl.hosts-graph --- 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