Search in sources :

Example 1 with FlowDisposition

use of org.batfish.datamodel.FlowDisposition 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 2 with FlowDisposition

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

the class BdpEngine method processCurrentNextHopInterfaceEdges.

private boolean processCurrentNextHopInterfaceEdges(BdpDataPlane dp, String currentNodeName, Set<Edge> visitedEdges, List<FlowTraceHop> hopsSoFar, Set<FlowTrace> flowTraces, Flow originalFlow, Flow transformedFlow, Ip dstIp, Set<String> dstIpOwners, @Nullable String nextHopInterfaceName, SortedSet<String> routesForThisNextHopInterface, @Nullable Ip finalNextHopIp, @Nullable NodeInterfacePair nextHopInterface, SortedSet<Edge> edges, boolean arp) {
    boolean continueToNextNextHopInterface = false;
    int unreachableNeighbors = 0;
    int potentialNeighbors = 0;
    for (Edge edge : edges) {
        if (!edge.getNode1().equals(currentNodeName)) {
            continue;
        }
        potentialNeighbors++;
        List<FlowTraceHop> newHops = new ArrayList<>(hopsSoFar);
        Set<Edge> newVisitedEdges = new LinkedHashSet<>(visitedEdges);
        FlowTraceHop newHop = new FlowTraceHop(edge, routesForThisNextHopInterface, hopFlow(originalFlow, transformedFlow));
        newVisitedEdges.add(edge);
        newHops.add(newHop);
        /*
       * Check to see whether neighbor would refrain from sending ARP reply
       * (NEIGHBOR_UNREACHABLE)
       *
       * This occurs if:
       *
       * - Using interface-only route
       *
       * AND
       *
       * - Neighbor does not own arpIp
       *
       * AND EITHER
       *
       * -- Neighbor not using proxy-arp
       *
       * - OR
       *
       * -- Subnet of neighbor's receiving-interface contains arpIp
       */
        if (arp) {
            Ip arpIp;
            Set<String> arpIpOwners;
            if (finalNextHopIp == null) {
                arpIp = dstIp;
                arpIpOwners = dstIpOwners;
            } else {
                arpIp = finalNextHopIp;
                arpIpOwners = dp._ipOwners.get(arpIp);
            }
            // using interface-only route
            String node2 = edge.getNode2();
            if (arpIpOwners == null || !arpIpOwners.contains(node2)) {
                // neighbor does not own arpIp
                String int2Name = edge.getInt2();
                Interface int2 = dp._nodes.get(node2)._c.getInterfaces().get(int2Name);
                boolean neighborUnreachable = false;
                Boolean proxyArp = int2.getProxyArp();
                if (proxyArp == null || !proxyArp) {
                    // TODO: proxyArp probably shouldn't be null
                    neighborUnreachable = true;
                } else {
                    for (InterfaceAddress address : int2.getAllAddresses()) {
                        if (address.getPrefix().containsIp(arpIp)) {
                            neighborUnreachable = true;
                            break;
                        }
                    }
                }
                if (neighborUnreachable) {
                    unreachableNeighbors++;
                    continue;
                }
            }
        }
        if (visitedEdges.contains(edge)) {
            FlowTrace trace = new FlowTrace(FlowDisposition.LOOP, newHops, FlowDisposition.LOOP.toString());
            flowTraces.add(trace);
            potentialNeighbors--;
            continue;
        }
        String nextNodeName = edge.getNode2();
        // now check output filter and input filter
        if (nextHopInterfaceName != null) {
            IpAccessList outFilter = dp._nodes.get(currentNodeName)._c.getInterfaces().get(nextHopInterfaceName).getOutgoingFilter();
            if (outFilter != null) {
                FlowDisposition disposition = FlowDisposition.DENIED_OUT;
                boolean denied = flowTraceDeniedHelper(flowTraces, originalFlow, transformedFlow, newHops, outFilter, disposition);
                if (denied) {
                    potentialNeighbors--;
                    continue;
                }
            }
        }
        IpAccessList inFilter = dp._nodes.get(nextNodeName)._c.getInterfaces().get(edge.getInt2()).getIncomingFilter();
        if (inFilter != null) {
            FlowDisposition disposition = FlowDisposition.DENIED_IN;
            boolean denied = flowTraceDeniedHelper(flowTraces, originalFlow, transformedFlow, newHops, inFilter, disposition);
            if (denied) {
                potentialNeighbors--;
                continue;
            }
        }
        // recurse
        collectFlowTraces(dp, nextNodeName, newVisitedEdges, newHops, flowTraces, originalFlow, transformedFlow);
    }
    if (arp && unreachableNeighbors > 0 && unreachableNeighbors == potentialNeighbors) {
        FlowTrace trace = neighborUnreachableTrace(hopsSoFar, nextHopInterface, routesForThisNextHopInterface, originalFlow, transformedFlow);
        flowTraces.add(trace);
        continueToNextNextHopInterface = true;
    }
    return continueToNextNextHopInterface;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) InterfaceAddress(org.batfish.datamodel.InterfaceAddress) Ip(org.batfish.datamodel.Ip) ArrayList(java.util.ArrayList) FlowDisposition(org.batfish.datamodel.FlowDisposition) FlowTraceHop(org.batfish.datamodel.FlowTraceHop) FlowTrace(org.batfish.datamodel.FlowTrace) IpAccessList(org.batfish.datamodel.IpAccessList) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Edge(org.batfish.datamodel.Edge) Interface(org.batfish.datamodel.Interface)

Aggregations

ArrayList (java.util.ArrayList)2 LinkedHashSet (java.util.LinkedHashSet)2 Edge (org.batfish.datamodel.Edge)2 FlowDisposition (org.batfish.datamodel.FlowDisposition)2 FlowTrace (org.batfish.datamodel.FlowTrace)2 FlowTraceHop (org.batfish.datamodel.FlowTraceHop)2 Interface (org.batfish.datamodel.Interface)2 Ip (org.batfish.datamodel.Ip)2 IpAccessList (org.batfish.datamodel.IpAccessList)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 ImmutableSortedSet (com.google.common.collect.ImmutableSortedSet)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Set (java.util.Set)1 SortedMap (java.util.SortedMap)1 SortedSet (java.util.SortedSet)1 TreeMap (java.util.TreeMap)1 TreeSet (java.util.TreeSet)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1