@Test public void testComputeLayer3Topology_linkLocalAddresses() { _cb.setConfigurationFormat(ConfigurationFormat.CISCO_IOS); Configuration c1 = _cb.setHostname("c1").build(); Configuration c2 = _cb.setHostname("c2").build(); Ip ip = Ip.parse("169.254.0.1"); Interface i1 = _ib.setOwner(c1).setAddress(LinkLocalAddress.of(ip)).build(); Interface i2 = _ib.setOwner(c2).setAddress(LinkLocalAddress.of(ip)).build(); Layer1Topology layer1Topology = new Layer1Topology( Collections.singleton( new Layer1Edge( new Layer1Node(c1.getHostname(), i1.getName()), new Layer1Node(c2.getHostname(), i2.getName())))); Topology t = computeRawLayer3Topology( layer1Topology, layer1Topology, Layer2Topology.EMPTY, ImmutableMap.of(c1.getHostname(), c1, c2.getHostname(), c2)); Edge edge = new Edge( NodeInterfacePair.of(c1.getHostname(), i1.getName()), NodeInterfacePair.of(c2.getHostname(), i2.getName())); assertThat(t.getEdges(), containsInAnyOrder(edge, edge.reverse())); }
@VisibleForTesting static @Nonnull Topology computeRawLayer3Topology( @Nonnull Layer1Topology rawLayer1Topology, @Nonnull Layer1Topology layer1LogicalTopology, @Nonnull Layer2Topology layer2Topology, @Nonnull Map<String, Configuration> configurations) { Set<String> layer1TailNodes = Stream.concat( rawLayer1Topology.getGraph().edges().stream(), layer1LogicalTopology.getGraph().edges().stream()) .map(l1Edge -> l1Edge.getNode1().getHostname()) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> filteredEdgeStream = synthesizeL3Topology(configurations).getEdges().stream() .filter( edge -> !layer1TailNodes.contains(edge.getNode1()) || !layer1TailNodes.contains(edge.getNode2()) || layer2Topology.inSameBroadcastDomain(edge.getHead(), edge.getTail())); NetworkConfigurations nc = NetworkConfigurations.of(configurations); Stream<Edge> layer1LLAEdgeStream = layer1LogicalTopology.getGraph().edges().stream() .filter( edge -> !nc.getInterface( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true) && !nc.getInterface( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true)) .flatMap( edge -> { Edge l3Edge = new Edge( NodeInterfacePair.of( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()), NodeInterfacePair.of( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName())); return Stream.of(l3Edge, l3Edge.reverse()); }); ImmutableSet<NodeInterfacePair> subInterfaces = configurations.values().stream() .flatMap(Configuration::activeInterfaces) .filter(i -> i.getInterfaceType() == InterfaceType.AGGREGATE_CHILD) .map(i -> NodeInterfacePair.of(i.getOwner().getHostname(), i.getName())) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> subInterfaceLLAStream = subInterfaces.stream() .flatMap( i1 -> subInterfaces.stream() .filter( i2 -> !i1.equals(i2) && layer2Topology.inSameBroadcastDomain(i1, i2)) .map(i2 -> new Edge(i1, i2))); return new Topology( Streams.concat(filteredEdgeStream, layer1LLAEdgeStream, subInterfaceLLAStream) .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder()))); }
TopologyUtil { @VisibleForTesting static @Nonnull Topology computeRawLayer3Topology( @Nonnull Layer1Topology rawLayer1Topology, @Nonnull Layer1Topology layer1LogicalTopology, @Nonnull Layer2Topology layer2Topology, @Nonnull Map<String, Configuration> configurations) { Set<String> layer1TailNodes = Stream.concat( rawLayer1Topology.getGraph().edges().stream(), layer1LogicalTopology.getGraph().edges().stream()) .map(l1Edge -> l1Edge.getNode1().getHostname()) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> filteredEdgeStream = synthesizeL3Topology(configurations).getEdges().stream() .filter( edge -> !layer1TailNodes.contains(edge.getNode1()) || !layer1TailNodes.contains(edge.getNode2()) || layer2Topology.inSameBroadcastDomain(edge.getHead(), edge.getTail())); NetworkConfigurations nc = NetworkConfigurations.of(configurations); Stream<Edge> layer1LLAEdgeStream = layer1LogicalTopology.getGraph().edges().stream() .filter( edge -> !nc.getInterface( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true) && !nc.getInterface( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true)) .flatMap( edge -> { Edge l3Edge = new Edge( NodeInterfacePair.of( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()), NodeInterfacePair.of( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName())); return Stream.of(l3Edge, l3Edge.reverse()); }); ImmutableSet<NodeInterfacePair> subInterfaces = configurations.values().stream() .flatMap(Configuration::activeInterfaces) .filter(i -> i.getInterfaceType() == InterfaceType.AGGREGATE_CHILD) .map(i -> NodeInterfacePair.of(i.getOwner().getHostname(), i.getName())) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> subInterfaceLLAStream = subInterfaces.stream() .flatMap( i1 -> subInterfaces.stream() .filter( i2 -> !i1.equals(i2) && layer2Topology.inSameBroadcastDomain(i1, i2)) .map(i2 -> new Edge(i1, i2))); return new Topology( Streams.concat(filteredEdgeStream, layer1LLAEdgeStream, subInterfaceLLAStream) .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder()))); } }
TopologyUtil { @VisibleForTesting static @Nonnull Topology computeRawLayer3Topology( @Nonnull Layer1Topology rawLayer1Topology, @Nonnull Layer1Topology layer1LogicalTopology, @Nonnull Layer2Topology layer2Topology, @Nonnull Map<String, Configuration> configurations) { Set<String> layer1TailNodes = Stream.concat( rawLayer1Topology.getGraph().edges().stream(), layer1LogicalTopology.getGraph().edges().stream()) .map(l1Edge -> l1Edge.getNode1().getHostname()) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> filteredEdgeStream = synthesizeL3Topology(configurations).getEdges().stream() .filter( edge -> !layer1TailNodes.contains(edge.getNode1()) || !layer1TailNodes.contains(edge.getNode2()) || layer2Topology.inSameBroadcastDomain(edge.getHead(), edge.getTail())); NetworkConfigurations nc = NetworkConfigurations.of(configurations); Stream<Edge> layer1LLAEdgeStream = layer1LogicalTopology.getGraph().edges().stream() .filter( edge -> !nc.getInterface( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true) && !nc.getInterface( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true)) .flatMap( edge -> { Edge l3Edge = new Edge( NodeInterfacePair.of( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()), NodeInterfacePair.of( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName())); return Stream.of(l3Edge, l3Edge.reverse()); }); ImmutableSet<NodeInterfacePair> subInterfaces = configurations.values().stream() .flatMap(Configuration::activeInterfaces) .filter(i -> i.getInterfaceType() == InterfaceType.AGGREGATE_CHILD) .map(i -> NodeInterfacePair.of(i.getOwner().getHostname(), i.getName())) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> subInterfaceLLAStream = subInterfaces.stream() .flatMap( i1 -> subInterfaces.stream() .filter( i2 -> !i1.equals(i2) && layer2Topology.inSameBroadcastDomain(i1, i2)) .map(i2 -> new Edge(i1, i2))); return new Topology( Streams.concat(filteredEdgeStream, layer1LLAEdgeStream, subInterfaceLLAStream) .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder()))); } private  TopologyUtil(); }
TopologyUtil { @VisibleForTesting static @Nonnull Topology computeRawLayer3Topology( @Nonnull Layer1Topology rawLayer1Topology, @Nonnull Layer1Topology layer1LogicalTopology, @Nonnull Layer2Topology layer2Topology, @Nonnull Map<String, Configuration> configurations) { Set<String> layer1TailNodes = Stream.concat( rawLayer1Topology.getGraph().edges().stream(), layer1LogicalTopology.getGraph().edges().stream()) .map(l1Edge -> l1Edge.getNode1().getHostname()) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> filteredEdgeStream = synthesizeL3Topology(configurations).getEdges().stream() .filter( edge -> !layer1TailNodes.contains(edge.getNode1()) || !layer1TailNodes.contains(edge.getNode2()) || layer2Topology.inSameBroadcastDomain(edge.getHead(), edge.getTail())); NetworkConfigurations nc = NetworkConfigurations.of(configurations); Stream<Edge> layer1LLAEdgeStream = layer1LogicalTopology.getGraph().edges().stream() .filter( edge -> !nc.getInterface( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true) && !nc.getInterface( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true)) .flatMap( edge -> { Edge l3Edge = new Edge( NodeInterfacePair.of( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()), NodeInterfacePair.of( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName())); return Stream.of(l3Edge, l3Edge.reverse()); }); ImmutableSet<NodeInterfacePair> subInterfaces = configurations.values().stream() .flatMap(Configuration::activeInterfaces) .filter(i -> i.getInterfaceType() == InterfaceType.AGGREGATE_CHILD) .map(i -> NodeInterfacePair.of(i.getOwner().getHostname(), i.getName())) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> subInterfaceLLAStream = subInterfaces.stream() .flatMap( i1 -> subInterfaces.stream() .filter( i2 -> !i1.equals(i2) && layer2Topology.inSameBroadcastDomain(i1, i2)) .map(i2 -> new Edge(i1, i2))); return new Topology( Streams.concat(filteredEdgeStream, layer1LLAEdgeStream, subInterfaceLLAStream) .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder()))); } private  TopologyUtil(); static @Nonnull Layer1Topology cleanLayer1PhysicalTopology(
      @Nonnull Layer1Topology rawLayer1Topology,
      @Nonnull Map<String, Configuration> configurations); static @Nonnull Optional<Layer1Topology> unionLayer1PhysicalTopologies(
      Optional<Layer1Topology> topology1, Optional<Layer1Topology> topology2); static @Nonnull Layer2Topology computeLayer2Topology(
      @Nonnull Layer1Topology layer1LogicalTopology,
      VxlanTopology vxlanTopology,
      @Nonnull Map<String, Configuration> configurations); static @Nonnull Topology computeRawLayer3Topology(
      @Nonnull Optional<Layer1Topology> rawLayer1PhysicalTopology,
      @Nonnull Optional<Layer1Topology> layer1LogicalTopology,
      @Nonnull Optional<Layer2Topology> layer2Topology,
      @Nonnull Map<String, Configuration> configurations); static @Nonnull Topology computeLayer3Topology(
      Topology rawLayer3Topology, Set<Edge> overlayEdges); static @Nullable Interface getInterface(
      @Nonnull Layer1Node layer1Node, @Nonnull Map<String, Configuration> configurations); static @Nullable Interface getInterface(
      @Nonnull Layer2Node layer2Node, @Nonnull Map<String, Configuration> configurations); static IpsecTopology computeIpsecTopology(Map<String, Configuration> configurations); static Map<String, Set<Interface>> computeNodeInterfaces(
      Map<String, Configuration> configurations); static Topology synthesizeL3Topology(Map<String, Configuration> configurations); static @Nonnull Layer1Topology computeLayer1LogicalTopology(
      Layer1Topology layer1PhysicalTopology, Map<String, Configuration> configurations); @Nonnull static TunnelTopology computeInitialTunnelTopology(
      Map<String, Configuration> configurations); @Nonnull static TunnelTopology pruneUnreachableTunnelEdges(
      TunnelTopology initialTunnelTopology,
      NetworkConfigurations configurations,
      TracerouteEngine tracerouteEngine); }
TopologyUtil { @VisibleForTesting static @Nonnull Topology computeRawLayer3Topology( @Nonnull Layer1Topology rawLayer1Topology, @Nonnull Layer1Topology layer1LogicalTopology, @Nonnull Layer2Topology layer2Topology, @Nonnull Map<String, Configuration> configurations) { Set<String> layer1TailNodes = Stream.concat( rawLayer1Topology.getGraph().edges().stream(), layer1LogicalTopology.getGraph().edges().stream()) .map(l1Edge -> l1Edge.getNode1().getHostname()) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> filteredEdgeStream = synthesizeL3Topology(configurations).getEdges().stream() .filter( edge -> !layer1TailNodes.contains(edge.getNode1()) || !layer1TailNodes.contains(edge.getNode2()) || layer2Topology.inSameBroadcastDomain(edge.getHead(), edge.getTail())); NetworkConfigurations nc = NetworkConfigurations.of(configurations); Stream<Edge> layer1LLAEdgeStream = layer1LogicalTopology.getGraph().edges().stream() .filter( edge -> !nc.getInterface( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true) && !nc.getInterface( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName()) .map(Interface::getAllLinkLocalAddresses) .map(Set::isEmpty) .orElse(true)) .flatMap( edge -> { Edge l3Edge = new Edge( NodeInterfacePair.of( edge.getNode1().getHostname(), edge.getNode1().getInterfaceName()), NodeInterfacePair.of( edge.getNode2().getHostname(), edge.getNode2().getInterfaceName())); return Stream.of(l3Edge, l3Edge.reverse()); }); ImmutableSet<NodeInterfacePair> subInterfaces = configurations.values().stream() .flatMap(Configuration::activeInterfaces) .filter(i -> i.getInterfaceType() == InterfaceType.AGGREGATE_CHILD) .map(i -> NodeInterfacePair.of(i.getOwner().getHostname(), i.getName())) .collect(ImmutableSet.toImmutableSet()); Stream<Edge> subInterfaceLLAStream = subInterfaces.stream() .flatMap( i1 -> subInterfaces.stream() .filter( i2 -> !i1.equals(i2) && layer2Topology.inSameBroadcastDomain(i1, i2)) .map(i2 -> new Edge(i1, i2))); return new Topology( Streams.concat(filteredEdgeStream, layer1LLAEdgeStream, subInterfaceLLAStream) .collect(ImmutableSortedSet.toImmutableSortedSet(Comparator.naturalOrder()))); } private  TopologyUtil(); static @Nonnull Layer1Topology cleanLayer1PhysicalTopology(
      @Nonnull Layer1Topology rawLayer1Topology,
      @Nonnull Map<String, Configuration> configurations); static @Nonnull Optional<Layer1Topology> unionLayer1PhysicalTopologies(
      Optional<Layer1Topology> topology1, Optional<Layer1Topology> topology2); static @Nonnull Layer2Topology computeLayer2Topology(
      @Nonnull Layer1Topology layer1LogicalTopology,
      VxlanTopology vxlanTopology,
      @Nonnull Map<String, Configuration> configurations); static @Nonnull Topology computeRawLayer3Topology(
      @Nonnull Optional<Layer1Topology> rawLayer1PhysicalTopology,
      @Nonnull Optional<Layer1Topology> layer1LogicalTopology,
      @Nonnull Optional<Layer2Topology> layer2Topology,
      @Nonnull Map<String, Configuration> configurations); static @Nonnull Topology computeLayer3Topology(
      Topology rawLayer3Topology, Set<Edge> overlayEdges); static @Nullable Interface getInterface(
      @Nonnull Layer1Node layer1Node, @Nonnull Map<String, Configuration> configurations); static @Nullable Interface getInterface(
      @Nonnull Layer2Node layer2Node, @Nonnull Map<String, Configuration> configurations); static IpsecTopology computeIpsecTopology(Map<String, Configuration> configurations); static Map<String, Set<Interface>> computeNodeInterfaces(
      Map<String, Configuration> configurations); static Topology synthesizeL3Topology(Map<String, Configuration> configurations); static @Nonnull Layer1Topology computeLayer1LogicalTopology(
      Layer1Topology layer1PhysicalTopology, Map<String, Configuration> configurations); @Nonnull static TunnelTopology computeInitialTunnelTopology(
      Map<String, Configuration> configurations); @Nonnull static TunnelTopology pruneUnreachableTunnelEdges(
      TunnelTopology initialTunnelTopology,
      NetworkConfigurations configurations,
      TracerouteEngine tracerouteEngine);  }