class ForwardingAnalysisImpl implements ForwardingAnalysis, Serializable {

  static Map<String, Map<String, Map<String, IpSpace>>> union(
      Map<String, Map<String, Map<String, IpSpace>>> ipSpaces1,
      Map<String, Map<String, Map<String, IpSpace>>> ipSpaces2) {
    Span span = GlobalTracer.get().buildSpan("construct union").start();
    try (Scope scope = GlobalTracer.get().scopeManager().activate(span)) {
      assert scope != null; // avoid unused warning

      checkArgument(
          ipSpaces1.keySet().equals(ipSpaces2.keySet()),
          "Can't union with different nodes: %s and %s",
          ipSpaces1.keySet(),
          ipSpaces2.keySet());

      return toImmutableMap(
          ipSpaces1,
          Entry::getKey, /* hostname */
          nodeEntry -> {
            Map<String, Map<String, IpSpace>> nodeIpSpace2 = ipSpaces2.get(nodeEntry.getKey());
            checkArgument(
                nodeIpSpace2.keySet().equals(nodeEntry.getValue().keySet()),
                "Can't union with different VRFs in node %s: %s and %s",
                nodeEntry.getKey(),
                nodeEntry.getValue().keySet(),
                nodeIpSpace2.keySet());
            return toImmutableMap(
                nodeEntry.getValue(),
                Entry::getKey, /* vrf */
                vrfEntry -> {
                  Map<String, IpSpace> vrfIpSpaces2 = nodeIpSpace2.get(vrfEntry.getKey());
                  checkArgument(
                      vrfIpSpaces2.keySet().equals(vrfEntry.getValue().keySet()),
                      "Can't union with different interfaces in node %s VRF %s: %s and %s",
                      nodeEntry.getKey(),
                      vrfEntry.getKey(),
                      vrfEntry.getValue().keySet(),
                      vrfIpSpaces2.keySet());
                  return toImmutableMap(
                      vrfEntry.getValue(),
                      Entry::getKey, /* interface */
                      ifaceEntry ->
                          AclIpSpace.union(
                              ifaceEntry.getValue(), vrfIpSpaces2.get(ifaceEntry.getKey())));
                });
          });
    } finally {
      span.finish();
    }
  }

  public  ForwardingAnalysisImpl(
      Map<String, Configuration> configurations,
      Map<String, Map<String, Fib>> fibs,
      Topology topology,
      Map<Location, LocationInfo> locationInfo);

}