Search in sources :

Example 1 with FlowTrace

use of org.batfish.datamodel.FlowTrace in project batfish by batfish.

the class CommonUtil method initRemoteBgpNeighbors.

/**
 * Initialize BGP neighbors for all nodes.
 *
 * @param configurations map of all configurations, keyed by hostname
 * @param ipOwners mapping of Ips to a set of nodes (hostnames) that owns those IPs
 * @param checkReachability whether bgp neighbor reachability should be checked
 * @param flowProcessor dataplane plugin to use to check reachability. Must not be {@code null} if
 *     {@code checkReachability = true}
 * @param dp dataplane to use to check reachability. Must not be {@code null} if {@code
 *     checkReachability = true}
 */
public static void initRemoteBgpNeighbors(Map<String, Configuration> configurations, Map<Ip, Set<String>> ipOwners, boolean checkReachability, @Nullable FlowProcessor flowProcessor, @Nullable DataPlane dp) {
    // TODO: handle duplicate ips on different vrfs
    Map<BgpNeighbor, Ip> remoteAddresses = new IdentityHashMap<>();
    Map<Ip, Set<BgpNeighbor>> localAddresses = new HashMap<>();
    /*
     * Construct maps indicating which neighbor owns which Ip Address
     */
    for (Configuration node : configurations.values()) {
        String hostname = node.getHostname();
        for (Vrf vrf : node.getVrfs().values()) {
            BgpProcess proc = vrf.getBgpProcess();
            if (proc == null) {
                // nothing to do if no bgp process on this VRF
                continue;
            }
            for (BgpNeighbor bgpNeighbor : proc.getNeighbors().values()) {
                /*
           * Begin by initializing candidate neighbors to an empty set
           */
                bgpNeighbor.initCandidateRemoteBgpNeighbors();
                // Skip things we don't handle
                if (bgpNeighbor.getPrefix().getPrefixLength() < Prefix.MAX_PREFIX_LENGTH) {
                    throw new BatfishException(hostname + ": Do not support dynamic bgp sessions at this time: " + bgpNeighbor.getPrefix());
                }
                Ip remoteAddress = bgpNeighbor.getAddress();
                if (remoteAddress == null) {
                    throw new BatfishException(hostname + ": Could not determine remote address of bgp neighbor: " + bgpNeighbor);
                }
                Ip localAddress = bgpNeighbor.getLocalIp();
                if (localAddress == null || !ipOwners.containsKey(localAddress) || !ipOwners.get(localAddress).contains(hostname)) {
                    // Local address is not owned by anybody
                    continue;
                }
                remoteAddresses.put(bgpNeighbor, remoteAddress);
                // Add this neighbor as owner of its local address
                localAddresses.computeIfAbsent(localAddress, k -> Collections.newSetFromMap(new IdentityHashMap<>())).add(bgpNeighbor);
            }
        }
    }
    /*
     * For each neighbor, construct the set of candidate neighbors, then filter out impossible
     * sessions.
     */
    for (Entry<BgpNeighbor, Ip> e : remoteAddresses.entrySet()) {
        BgpNeighbor bgpNeighbor = e.getKey();
        Ip remoteAddress = e.getValue();
        Ip localAddress = bgpNeighbor.getLocalIp();
        int localLocalAs = bgpNeighbor.getLocalAs();
        int localRemoteAs = bgpNeighbor.getRemoteAs();
        /*
       * Let the set of candidate neighbors be set of neighbors that own the remoteAddress
       */
        Set<BgpNeighbor> remoteBgpNeighborCandidates = localAddresses.get(remoteAddress);
        if (remoteBgpNeighborCandidates == null) {
            // No possible remote neighbors
            continue;
        }
        /*
       * Filter the set of candidate neighbors based on these checks:
       * - Remote neighbor's remote address is the same as our local address
       * - Remote neighbor's remote AS is the same as our local AS (and vice-versa)
       */
        for (BgpNeighbor remoteBgpNeighborCandidate : remoteBgpNeighborCandidates) {
            int remoteLocalAs = remoteBgpNeighborCandidate.getLocalAs();
            int remoteRemoteAs = remoteBgpNeighborCandidate.getRemoteAs();
            Ip reciprocalRemoteIp = remoteBgpNeighborCandidate.getAddress();
            if (localAddress.equals(reciprocalRemoteIp) && localLocalAs == remoteRemoteAs && localRemoteAs == remoteLocalAs) {
                /*
           * Fairly confident establishing the session is possible here, but still check
           * reachability if needed.
           * We should check reachability only for eBgp multihop or iBgp
           */
                if (checkReachability && (bgpNeighbor.getEbgpMultihop() || localLocalAs == remoteLocalAs)) {
                    /*
             * Ensure that the session can be established by running traceroute in both directions
             */
                    if (flowProcessor == null || dp == null) {
                        throw new BatfishException("Cannot compute neighbor reachability without a dataplane");
                    }
                    Flow.Builder fb = new Flow.Builder();
                    fb.setIpProtocol(IpProtocol.TCP);
                    fb.setTag("neighbor-resolution");
                    fb.setIngressNode(bgpNeighbor.getOwner().getHostname());
                    fb.setSrcIp(localAddress);
                    fb.setDstIp(remoteAddress);
                    fb.setSrcPort(NamedPort.EPHEMERAL_LOWEST.number());
                    fb.setDstPort(NamedPort.BGP.number());
                    Flow forwardFlow = fb.build();
                    fb.setIngressNode(remoteBgpNeighborCandidate.getOwner().getHostname());
                    fb.setSrcIp(forwardFlow.getDstIp());
                    fb.setDstIp(forwardFlow.getSrcIp());
                    fb.setSrcPort(forwardFlow.getDstPort());
                    fb.setDstPort(forwardFlow.getSrcPort());
                    Flow backwardFlow = fb.build();
                    SortedMap<Flow, Set<FlowTrace>> traces = flowProcessor.processFlows(dp, ImmutableSet.of(forwardFlow, backwardFlow));
                    if (traces.values().stream().map(fts -> fts.stream().allMatch(ft -> ft.getDisposition() != FlowDisposition.ACCEPTED)).anyMatch(Predicate.isEqual(true))) {
                        /*
               * If either flow has all traceroutes fail, do not consider the neighbor valid
               */
                        continue;
                    }
                    bgpNeighbor.getCandidateRemoteBgpNeighbors().add(remoteBgpNeighborCandidate);
                } else {
                    bgpNeighbor.getCandidateRemoteBgpNeighbors().add(remoteBgpNeighborCandidate);
                }
            }
        }
        Set<BgpNeighbor> finalCandidates = bgpNeighbor.getCandidateRemoteBgpNeighbors();
        if (finalCandidates.size() > 1) {
            /* If we still have not narrowed it down to a single neighbor,
         * pick based on sorted hostnames
         */
            SortedMap<String, BgpNeighbor> hostnameToNeighbor = finalCandidates.stream().collect(ImmutableSortedMap.toImmutableSortedMap(String::compareTo, k -> k.getOwner().getHostname(), Function.identity()));
            bgpNeighbor.setRemoteBgpNeighbor(hostnameToNeighbor.get(hostnameToNeighbor.firstKey()));
        } else if (finalCandidates.size() == 1) {
            bgpNeighbor.setRemoteBgpNeighbor(finalCandidates.iterator().next());
        } else {
            bgpNeighbor.setRemoteBgpNeighbor(null);
        }
    }
}
Also used : SSLEngineConfigurator(org.glassfish.grizzly.ssl.SSLEngineConfigurator) SSLContext(javax.net.ssl.SSLContext) FileTime(java.nio.file.attribute.FileTime) StringUtils(org.apache.commons.lang3.StringUtils) Configurations(org.apache.commons.configuration2.builder.fluent.Configurations) Interface(org.batfish.datamodel.Interface) DirectoryStream(java.nio.file.DirectoryStream) BfConsts(org.batfish.common.BfConsts) Flow(org.batfish.datamodel.Flow) Topology(org.batfish.datamodel.Topology) Map(java.util.Map) ResourceConfig(org.glassfish.jersey.server.ResourceConfig) Pair(org.batfish.common.Pair) Path(java.nio.file.Path) DataPlane(org.batfish.datamodel.DataPlane) VrrpGroup(org.batfish.datamodel.VrrpGroup) ClientTracingFeature(io.opentracing.contrib.jaxrs2.client.ClientTracingFeature) Set(java.util.Set) FileAttribute(java.nio.file.attribute.FileAttribute) StandardCharsets(java.nio.charset.StandardCharsets) DirectoryIteratorException(java.nio.file.DirectoryIteratorException) IOUtils(org.apache.commons.io.IOUtils) Stream(java.util.stream.Stream) Supplier(java.util.function.Supplier) TreeSet(java.util.TreeSet) JSONAssert(org.skyscreamer.jsonassert.JSONAssert) MustBeClosed(com.google.errorprone.annotations.MustBeClosed) SSLSession(javax.net.ssl.SSLSession) FlowProcessor(org.batfish.common.plugin.FlowProcessor) BiConsumer(java.util.function.BiConsumer) SSLContextConfigurator(org.glassfish.grizzly.ssl.SSLContextConfigurator) ImmutableSortedMap(com.google.common.collect.ImmutableSortedMap) Nullable(javax.annotation.Nullable) Files(java.nio.file.Files) Route(org.batfish.datamodel.Route) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) FileUtils(org.apache.commons.io.FileUtils) KeyManager(javax.net.ssl.KeyManager) TreeMap(java.util.TreeMap) Paths(java.nio.file.Paths) X509TrustManager(javax.net.ssl.X509TrustManager) BufferedReader(java.io.BufferedReader) X509Certificate(java.security.cert.X509Certificate) IpsecVpn(org.batfish.datamodel.IpsecVpn) NoSuchFileException(java.nio.file.NoSuchFileException) IpProtocol(org.batfish.datamodel.IpProtocol) SortedSet(java.util.SortedSet) URL(java.net.URL) TrustManager(javax.net.ssl.TrustManager) FlowTrace(org.batfish.datamodel.FlowTrace) InterfaceAddress(org.batfish.datamodel.InterfaceAddress) OspfNeighbor(org.batfish.datamodel.OspfNeighbor) Edge(org.batfish.datamodel.Edge) IpWildcardSetIpSpace(org.batfish.datamodel.IpWildcardSetIpSpace) OspfProcess(org.batfish.datamodel.OspfProcess) URI(java.net.URI) HostnameVerifier(javax.net.ssl.HostnameVerifier) NamedPort(org.batfish.datamodel.NamedPort) Vrf(org.batfish.datamodel.Vrf) OspfArea(org.batfish.datamodel.OspfArea) ImmutableSetMultimap(com.google.common.collect.ImmutableSetMultimap) ImmutableSet(com.google.common.collect.ImmutableSet) IdentityHashMap(java.util.IdentityHashMap) PatternSyntaxException(java.util.regex.PatternSyntaxException) TrustManagerFactory(javax.net.ssl.TrustManagerFactory) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Collection(java.util.Collection) FlowDisposition(org.batfish.datamodel.FlowDisposition) KeyStore(java.security.KeyStore) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) FileNotFoundException(java.io.FileNotFoundException) List(java.util.List) Entry(java.util.Map.Entry) Pattern(java.util.regex.Pattern) BgpNeighbor(org.batfish.datamodel.BgpNeighbor) SortedMap(java.util.SortedMap) IpWildcard(org.batfish.datamodel.IpWildcard) Ip(org.batfish.datamodel.Ip) NodeInterfacePair(org.batfish.datamodel.collections.NodeInterfacePair) Hashing(com.google.common.hash.Hashing) HashMap(java.util.HashMap) BatfishException(org.batfish.common.BatfishException) BgpProcess(org.batfish.datamodel.BgpProcess) Function(java.util.function.Function) HashSet(java.util.HashSet) ClientBuilder(javax.ws.rs.client.ClientBuilder) Configuration(org.batfish.datamodel.Configuration) OutputStreamWriter(java.io.OutputStreamWriter) OutputStream(java.io.OutputStream) IpLink(org.batfish.datamodel.IpLink) Iterator(java.util.Iterator) MalformedURLException(java.net.MalformedURLException) KeyManagerFactory(javax.net.ssl.KeyManagerFactory) GlobalTracer(io.opentracing.util.GlobalTracer) FileInputStream(java.io.FileInputStream) SetMultimap(com.google.common.collect.SetMultimap) Consumer(java.util.function.Consumer) GrizzlyHttpServerFactory(org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Collections(java.util.Collections) InputStream(java.io.InputStream) Prefix(org.batfish.datamodel.Prefix) BatfishException(org.batfish.common.BatfishException) Set(java.util.Set) TreeSet(java.util.TreeSet) SortedSet(java.util.SortedSet) ImmutableSet(com.google.common.collect.ImmutableSet) HashSet(java.util.HashSet) Configuration(org.batfish.datamodel.Configuration) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) BgpProcess(org.batfish.datamodel.BgpProcess) Ip(org.batfish.datamodel.Ip) IdentityHashMap(java.util.IdentityHashMap) ClientBuilder(javax.ws.rs.client.ClientBuilder) Vrf(org.batfish.datamodel.Vrf) Flow(org.batfish.datamodel.Flow) BgpNeighbor(org.batfish.datamodel.BgpNeighbor)

Example 2 with FlowTrace

use of org.batfish.datamodel.FlowTrace in project batfish by batfish.

the class BdpEngine method processFlows.

@Override
public SortedMap<Flow, Set<FlowTrace>> processFlows(DataPlane dataPlane, Set<Flow> flows) {
    Map<Flow, Set<FlowTrace>> flowTraces = new ConcurrentHashMap<>();
    BdpDataPlane dp = (BdpDataPlane) dataPlane;
    flows.parallelStream().forEach(flow -> {
        Set<FlowTrace> currentFlowTraces = new TreeSet<>();
        flowTraces.put(flow, currentFlowTraces);
        String ingressNodeName = flow.getIngressNode();
        if (ingressNodeName == null) {
            throw new BatfishException("Cannot construct flow trace since ingressNode is not specified");
        }
        Ip dstIp = flow.getDstIp();
        if (dstIp == null) {
            throw new BatfishException("Cannot construct flow trace since dstIp is not specified");
        }
        Set<Edge> visitedEdges = Collections.emptySet();
        List<FlowTraceHop> hops = new ArrayList<>();
        Set<String> dstIpOwners = dp._ipOwners.get(dstIp);
        SortedSet<Edge> edges = new TreeSet<>();
        String ingressInterfaceName = flow.getIngressInterface();
        if (ingressInterfaceName != null) {
            edges.add(new Edge(TRACEROUTE_INGRESS_NODE_NAME, TRACEROUTE_INGRESS_NODE_INTERFACE_NAME, ingressNodeName, ingressInterfaceName));
            processCurrentNextHopInterfaceEdges(dp, TRACEROUTE_INGRESS_NODE_NAME, visitedEdges, hops, currentFlowTraces, flow, flow, dstIp, dstIpOwners, null, new TreeSet<>(), null, null, edges, false);
        } else {
            collectFlowTraces(dp, ingressNodeName, visitedEdges, hops, currentFlowTraces, flow, flow);
        }
    });
    return new TreeMap<>(flowTraces);
}
Also used : BatfishException(org.batfish.common.BatfishException) SortedSet(java.util.SortedSet) Set(java.util.Set) TreeSet(java.util.TreeSet) LinkedHashSet(java.util.LinkedHashSet) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet) Ip(org.batfish.datamodel.Ip) ArrayList(java.util.ArrayList) TreeMap(java.util.TreeMap) Flow(org.batfish.datamodel.Flow) FlowTraceHop(org.batfish.datamodel.FlowTraceHop) TreeSet(java.util.TreeSet) FlowTrace(org.batfish.datamodel.FlowTrace) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Edge(org.batfish.datamodel.Edge)

Example 3 with FlowTrace

use of org.batfish.datamodel.FlowTrace in project batfish by batfish.

the class BdpEngine method collectFlowTraces.

private void collectFlowTraces(BdpDataPlane dp, String currentNodeName, Set<Edge> visitedEdges, List<FlowTraceHop> hopsSoFar, Set<FlowTrace> flowTraces, Flow originalFlow, Flow transformedFlow) {
    Ip dstIp = transformedFlow.getDstIp();
    Set<String> dstIpOwners = dp._ipOwners.get(dstIp);
    if (dstIpOwners != null && dstIpOwners.contains(currentNodeName)) {
        FlowTrace trace = new FlowTrace(FlowDisposition.ACCEPTED, hopsSoFar, FlowDisposition.ACCEPTED.toString());
        flowTraces.add(trace);
    } else {
        Node currentNode = dp._nodes.get(currentNodeName);
        String vrfName;
        if (hopsSoFar.isEmpty()) {
            vrfName = transformedFlow.getIngressVrf();
        } else {
            FlowTraceHop lastHop = hopsSoFar.get(hopsSoFar.size() - 1);
            String receivingInterface = lastHop.getEdge().getInt2();
            vrfName = currentNode._c.getInterfaces().get(receivingInterface).getVrf().getName();
        }
        VirtualRouter currentVirtualRouter = currentNode._virtualRouters.get(vrfName);
        Map<AbstractRoute, Map<String, Map<Ip, Set<AbstractRoute>>>> nextHopInterfacesByRoute = currentVirtualRouter._fib.getNextHopInterfacesByRoute(dstIp);
        Map<String, Map<Ip, Set<AbstractRoute>>> nextHopInterfacesWithRoutes = currentVirtualRouter._fib.getNextHopInterfaces(dstIp);
        if (!nextHopInterfacesWithRoutes.isEmpty()) {
            for (String nextHopInterfaceName : nextHopInterfacesWithRoutes.keySet()) {
                // SortedSet<String> routesForThisNextHopInterface = new
                // TreeSet<>(
                // nextHopInterfacesWithRoutes.get(nextHopInterfaceName)
                // .stream().map(ar -> ar.toString())
                // .collect(Collectors.toSet()));
                SortedSet<String> routesForThisNextHopInterface = new TreeSet<>();
                Ip finalNextHopIp = null;
                for (Entry<AbstractRoute, Map<String, Map<Ip, Set<AbstractRoute>>>> e : nextHopInterfacesByRoute.entrySet()) {
                    AbstractRoute routeCandidate = e.getKey();
                    Map<String, Map<Ip, Set<AbstractRoute>>> routeCandidateNextHopInterfaces = e.getValue();
                    if (routeCandidateNextHopInterfaces.containsKey(nextHopInterfaceName)) {
                        Ip nextHopIp = routeCandidate.getNextHopIp();
                        if (!nextHopIp.equals(Route.UNSET_ROUTE_NEXT_HOP_IP)) {
                            Set<Ip> finalNextHopIps = routeCandidateNextHopInterfaces.get(nextHopInterfaceName).keySet();
                            if (finalNextHopIps.size() > 1) {
                                throw new BatfishException("Can not currently handle multiple final next hop ips across multiple " + "routes leading to one next hop interface");
                            }
                            Ip newFinalNextHopIp = finalNextHopIps.iterator().next();
                            if (finalNextHopIp != null && !newFinalNextHopIp.equals(finalNextHopIp)) {
                                throw new BatfishException("Can not currently handle multiple final next hop ips for same next hop " + "interface");
                            }
                            finalNextHopIp = newFinalNextHopIp;
                        }
                        routesForThisNextHopInterface.add(routeCandidate + "_fnhip:" + finalNextHopIp);
                    }
                }
                NodeInterfacePair nextHopInterface = new NodeInterfacePair(currentNodeName, nextHopInterfaceName);
                if (nextHopInterfaceName.equals(Interface.NULL_INTERFACE_NAME)) {
                    List<FlowTraceHop> newHops = new ArrayList<>(hopsSoFar);
                    Edge newEdge = new Edge(nextHopInterface, new NodeInterfacePair(Configuration.NODE_NONE_NAME, Interface.NULL_INTERFACE_NAME));
                    FlowTraceHop newHop = new FlowTraceHop(newEdge, routesForThisNextHopInterface, hopFlow(originalFlow, transformedFlow));
                    newHops.add(newHop);
                    FlowTrace nullRouteTrace = new FlowTrace(FlowDisposition.NULL_ROUTED, newHops, FlowDisposition.NULL_ROUTED.toString());
                    flowTraces.add(nullRouteTrace);
                } else {
                    Interface outgoingInterface = dp._nodes.get(nextHopInterface.getHostname())._c.getInterfaces().get(nextHopInterface.getInterface());
                    // Apply any relevant source NAT rules.
                    transformedFlow = applySourceNat(transformedFlow, outgoingInterface.getSourceNats());
                    SortedSet<Edge> edges = dp._topology.getInterfaceEdges().get(nextHopInterface);
                    if (edges != null) {
                        boolean continueToNextNextHopInterface = false;
                        continueToNextNextHopInterface = processCurrentNextHopInterfaceEdges(dp, currentNodeName, visitedEdges, hopsSoFar, flowTraces, originalFlow, transformedFlow, dstIp, dstIpOwners, nextHopInterfaceName, routesForThisNextHopInterface, finalNextHopIp, nextHopInterface, edges, true);
                        if (continueToNextNextHopInterface) {
                            continue;
                        }
                    } else {
                        /*
               * Should only get here for delta environment where
               * non-flow-sink interface from base has no edges in delta
               */
                        Edge neighborUnreachbleEdge = new Edge(nextHopInterface, new NodeInterfacePair(Configuration.NODE_NONE_NAME, Interface.NULL_INTERFACE_NAME));
                        FlowTraceHop neighborUnreachableHop = new FlowTraceHop(neighborUnreachbleEdge, routesForThisNextHopInterface, hopFlow(originalFlow, transformedFlow));
                        List<FlowTraceHop> newHops = new ArrayList<>(hopsSoFar);
                        newHops.add(neighborUnreachableHop);
                        /**
                         * Check if denied out. If not, make standard neighbor-unreachable trace.
                         */
                        IpAccessList outFilter = outgoingInterface.getOutgoingFilter();
                        boolean denied = false;
                        if (outFilter != null) {
                            FlowDisposition disposition = FlowDisposition.DENIED_OUT;
                            denied = flowTraceDeniedHelper(flowTraces, originalFlow, transformedFlow, newHops, outFilter, disposition);
                        }
                        if (!denied) {
                            FlowTrace trace = new FlowTrace(FlowDisposition.NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK, newHops, FlowDisposition.NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK.toString());
                            flowTraces.add(trace);
                        }
                    }
                }
            }
        } else {
            FlowTrace trace = new FlowTrace(FlowDisposition.NO_ROUTE, hopsSoFar, FlowDisposition.NO_ROUTE.toString());
            flowTraces.add(trace);
        }
    }
}
Also used : SortedSet(java.util.SortedSet) Set(java.util.Set) TreeSet(java.util.TreeSet) LinkedHashSet(java.util.LinkedHashSet) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet) Ip(org.batfish.datamodel.Ip) ArrayList(java.util.ArrayList) TreeSet(java.util.TreeSet) AbstractRoute(org.batfish.datamodel.AbstractRoute) BatfishException(org.batfish.common.BatfishException) NodeInterfacePair(org.batfish.datamodel.collections.NodeInterfacePair) FlowDisposition(org.batfish.datamodel.FlowDisposition) FlowTraceHop(org.batfish.datamodel.FlowTraceHop) FlowTrace(org.batfish.datamodel.FlowTrace) IpAccessList(org.batfish.datamodel.IpAccessList) LRUMap(org.apache.commons.collections4.map.LRUMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) Edge(org.batfish.datamodel.Edge) Interface(org.batfish.datamodel.Interface)

Example 4 with FlowTrace

use of org.batfish.datamodel.FlowTrace in project batfish by batfish.

the class BdpEngine method flowTraceDeniedHelper.

private boolean flowTraceDeniedHelper(Set<FlowTrace> flowTraces, Flow originalFlow, Flow transformedFlow, List<FlowTraceHop> newHops, IpAccessList filter, FlowDisposition disposition) {
    boolean out = disposition == FlowDisposition.DENIED_OUT;
    FilterResult outResult = filter.filter(transformedFlow);
    boolean denied = outResult.getAction() == LineAction.REJECT;
    if (denied) {
        String outFilterName = filter.getName();
        Integer matchLine = outResult.getMatchLine();
        String lineDesc;
        if (matchLine != null) {
            lineDesc = filter.getLines().get(matchLine).getName();
            if (lineDesc == null) {
                lineDesc = "line:" + matchLine;
            }
        } else {
            lineDesc = "no-match";
        }
        String notes = disposition + "{" + outFilterName + "}{" + lineDesc + "}";
        if (out) {
            FlowTraceHop lastHop = newHops.get(newHops.size() - 1);
            newHops.remove(newHops.size() - 1);
            Edge lastEdge = lastHop.getEdge();
            Edge deniedOutEdge = new Edge(lastEdge.getFirst(), new NodeInterfacePair(Configuration.NODE_NONE_NAME, Interface.NULL_INTERFACE_NAME));
            FlowTraceHop deniedOutHop = new FlowTraceHop(deniedOutEdge, lastHop.getRoutes(), hopFlow(originalFlow, transformedFlow));
            newHops.add(deniedOutHop);
        }
        FlowTrace trace = new FlowTrace(disposition, newHops, notes);
        flowTraces.add(trace);
    }
    return denied;
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) FlowTraceHop(org.batfish.datamodel.FlowTraceHop) NodeInterfacePair(org.batfish.datamodel.collections.NodeInterfacePair) FlowTrace(org.batfish.datamodel.FlowTrace) FilterResult(org.batfish.datamodel.FilterResult) Edge(org.batfish.datamodel.Edge)

Example 5 with FlowTrace

use of org.batfish.datamodel.FlowTrace in project batfish by batfish.

the class CounterExample method buildFlowTrace.

/*
   * Build flow information for a given hop along a path
   */
Tuple<Flow, FlowTrace> buildFlowTrace(Encoder enc, String router) {
    EncoderSlice slice = enc.getMainSlice();
    SymbolicPacket pkt = slice.getSymbolicPacket();
    SymbolicDecisions decisions = slice.getSymbolicDecisions();
    Flow f = buildFlow(pkt, router);
    SortedSet<String> visited = new TreeSet<>();
    List<FlowTraceHop> hops = new ArrayList<>();
    String current = router;
    while (true) {
        visited.add(current);
        // Get the forwarding variables
        Map<GraphEdge, BoolExpr> dfwd = decisions.getDataForwarding().get(current);
        Map<GraphEdge, BoolExpr> cfwd = decisions.getControlForwarding().get(current);
        Map<GraphEdge, BoolExpr> across = enc.getMainSlice().getForwardsAcross().get(current);
        // Find the route used
        SymbolicRoute r = decisions.getBestNeighbor().get(current);
        Protocol proto = buildProcotol(r, slice, current);
        Prefix pfx = buildPrefix(r, f);
        // pick the next router
        boolean found = false;
        for (Entry<GraphEdge, BoolExpr> entry : dfwd.entrySet()) {
            GraphEdge ge = entry.getKey();
            BoolExpr dexpr = entry.getValue();
            BoolExpr cexpr = cfwd.get(ge);
            BoolExpr aexpr = across.get(ge);
            String route = buildRoute(pfx, proto, ge);
            if (isTrue(dexpr)) {
                hops.add(buildFlowTraceHop(ge, route));
                if (ge.getPeer() != null && visited.contains(ge.getPeer())) {
                    FlowTrace ft = new FlowTrace(FlowDisposition.LOOP, hops, "LOOP");
                    return new Tuple<>(f, ft);
                }
                if (isFalse(aexpr)) {
                    Interface i = ge.getEnd();
                    IpAccessList acl = i.getIncomingFilter();
                    FilterResult fr = acl.filter(f);
                    String line = "default deny";
                    if (fr.getMatchLine() != null) {
                        line = acl.getLines().get(fr.getMatchLine()).getName();
                    }
                    String note = String.format("DENIED_IN{%s}{%s}", acl.getName(), line);
                    FlowTrace ft = new FlowTrace(FlowDisposition.DENIED_IN, hops, note);
                    return new Tuple<>(f, ft);
                }
                boolean isLoopback = slice.getGraph().isLoopback(ge);
                if (isLoopback) {
                    FlowTrace ft = new FlowTrace(FlowDisposition.ACCEPTED, hops, "ACCEPTED");
                    return new Tuple<>(f, ft);
                }
                if (ge.getPeer() == null) {
                    boolean isBgpPeering = slice.getGraph().getEbgpNeighbors().get(ge) != null;
                    if (isBgpPeering) {
                        FlowTrace ft = new FlowTrace(FlowDisposition.ACCEPTED, hops, "ACCEPTED");
                        return new Tuple<>(f, ft);
                    } else {
                        FlowTrace ft = new FlowTrace(FlowDisposition.NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK, hops, "NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK");
                        return new Tuple<>(f, ft);
                    }
                }
                if (slice.getGraph().isHost(ge.getPeer())) {
                    FlowTrace ft = new FlowTrace(FlowDisposition.ACCEPTED, hops, "ACCEPTED");
                    return new Tuple<>(f, ft);
                }
                current = ge.getPeer();
                found = true;
                break;
            } else if (isTrue(cexpr)) {
                hops.add(buildFlowTraceHop(ge, route));
                Interface i = ge.getStart();
                IpAccessList acl = i.getOutgoingFilter();
                FilterResult fr = acl.filter(f);
                IpAccessListLine line = acl.getLines().get(fr.getMatchLine());
                String note = String.format("DENIED_OUT{%s}{%s}", acl.getName(), line.getName());
                FlowTrace ft = new FlowTrace(FlowDisposition.DENIED_OUT, hops, note);
                return new Tuple<>(f, ft);
            }
        }
        if (!found) {
            BoolExpr permitted = r.getPermitted();
            if (boolVal(permitted)) {
                // Check if there is an accepting interface
                for (GraphEdge ge : slice.getGraph().getEdgeMap().get(current)) {
                    Interface i = ge.getStart();
                    Ip ip = i.getAddress().getIp();
                    if (ip.equals(f.getDstIp())) {
                        FlowTrace ft = new FlowTrace(FlowDisposition.ACCEPTED, hops, "ACCEPTED");
                        return new Tuple<>(f, ft);
                    }
                }
                FlowTrace ft = new FlowTrace(FlowDisposition.NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK, hops, "NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK");
                return new Tuple<>(f, ft);
            }
            FlowTrace ft = new FlowTrace(FlowDisposition.NO_ROUTE, hops, "NO_ROUTE");
            return new Tuple<>(f, ft);
        }
    }
}
Also used : BoolExpr(com.microsoft.z3.BoolExpr) Ip(org.batfish.datamodel.Ip) ArrayList(java.util.ArrayList) Prefix(org.batfish.datamodel.Prefix) TreeSet(java.util.TreeSet) IpAccessListLine(org.batfish.datamodel.IpAccessListLine) IpProtocol(org.batfish.datamodel.IpProtocol) RoutingProtocol(org.batfish.datamodel.RoutingProtocol) Protocol(org.batfish.symbolic.Protocol) Flow(org.batfish.datamodel.Flow) FlowTraceHop(org.batfish.datamodel.FlowTraceHop) FlowTrace(org.batfish.datamodel.FlowTrace) IpAccessList(org.batfish.datamodel.IpAccessList) FilterResult(org.batfish.datamodel.FilterResult) GraphEdge(org.batfish.symbolic.GraphEdge) Tuple(org.batfish.symbolic.utils.Tuple) Interface(org.batfish.datamodel.Interface)

Aggregations

FlowTrace (org.batfish.datamodel.FlowTrace)12 Edge (org.batfish.datamodel.Edge)8 Flow (org.batfish.datamodel.Flow)8 FlowTraceHop (org.batfish.datamodel.FlowTraceHop)8 Ip (org.batfish.datamodel.Ip)7 ArrayList (java.util.ArrayList)5 ImmutableMap (com.google.common.collect.ImmutableMap)4 Map (java.util.Map)4 SortedMap (java.util.SortedMap)4 TreeSet (java.util.TreeSet)4 Interface (org.batfish.datamodel.Interface)4 NodeInterfacePair (org.batfish.datamodel.collections.NodeInterfacePair)4 ImmutableSortedMap (com.google.common.collect.ImmutableSortedMap)3 LinkedHashSet (java.util.LinkedHashSet)3 Set (java.util.Set)3 SortedSet (java.util.SortedSet)3 TreeMap (java.util.TreeMap)3 BatfishException (org.batfish.common.BatfishException)3 FlowDisposition (org.batfish.datamodel.FlowDisposition)3 IpAccessList (org.batfish.datamodel.IpAccessList)3