class ForwardingAnalysisImpl implements ForwardingAnalysis, Serializable {

  @VisibleForTesting
  static Map<String, Map<String, Map<String, IpSpace>>> computeArpFalseDestIp(
      Map<String, Map<String, Map<Prefix, IpSpace>>> matchingIps,
      Map<String, Map<String, Map<String, Set<AbstractRoute>>>> routesWhereDstIpCanBeArpIp,
      Map<String, Map<String, IpSpace>> someoneReplies) {
    Span span =
        GlobalTracer.get().buildSpan("ForwardingAnalysisImpl.computeArpFalseDestIp").start();
    try (Scope scope = GlobalTracer.get().scopeManager().activate(span)) {
      assert scope != null; // avoid unused warning
      return toImmutableMap(
          routesWhereDstIpCanBeArpIp,
          Entry::getKey /* hostname */,
          nodeEntry -> {
            String hostname = nodeEntry.getKey();
            Map<String, IpSpace> someoneRepliesNode =
                someoneReplies.getOrDefault(hostname, ImmutableMap.of());
            return toImmutableMap(
                nodeEntry.getValue(),
                Entry::getKey /* vrf */,
                vrfEntry -> {
                  String vrf = vrfEntry.getKey();
                  Map<Prefix, IpSpace> vrfMatchingIps = matchingIps.get(hostname).get(vrf);
                  return vrfEntry.getValue().entrySet().stream()
                      /* null_interface is handled in computeNullRoutedIps */
                      .filter(entry -> !entry.getKey().equals(Interface.NULL_INTERFACE_NAME))
                      .collect(
                          ImmutableMap.toImmutableMap(
                              Entry::getKey /* outInterface */,
                              ifaceEntry -> {
                                String outInterface = ifaceEntry.getKey();
                                Set<AbstractRoute> routes = ifaceEntry.getValue();
                                IpSpace someoneRepliesIface =
                                    someoneRepliesNode.getOrDefault(
                                        outInterface, EmptyIpSpace.INSTANCE);
                                IpSpace ipsRoutedOutInterface =
                                    computeRouteMatchConditions(routes, vrfMatchingIps);
                                return AclIpSpace.rejecting(someoneRepliesIface)
                                    .thenPermitting(ipsRoutedOutInterface)
                                    .build();
                              }));
                });
          });
    } finally {
      span.finish();
    }
  }

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

}