use of org.batfish.datamodel.collections.NodeInterfacePair 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);
}
}
}
use of org.batfish.datamodel.collections.NodeInterfacePair 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;
}
use of org.batfish.datamodel.collections.NodeInterfacePair in project batfish by batfish.
the class Batfish method blacklistInterface.
/**
* Helper function to disable a blacklisted interface and update the given {@link
* ValidateEnvironmentAnswerElement} if the interface does not actually exist.
*/
private static void blacklistInterface(Map<String, Configuration> configurations, ValidateEnvironmentAnswerElement veae, NodeInterfacePair iface) {
String hostname = iface.getHostname();
String ifaceName = iface.getInterface();
@Nullable Configuration node = configurations.get(hostname);
if (node == null) {
veae.setValid(false);
veae.getUndefinedInterfaceBlacklistNodes().add(hostname);
return;
}
@Nullable Interface nodeIface = node.getInterfaces().get(ifaceName);
if (nodeIface == null) {
veae.setValid(false);
veae.getUndefinedInterfaceBlacklistInterfaces().computeIfAbsent(hostname, k -> new TreeSet<>()).add(ifaceName);
return;
}
nodeIface.setActive(false);
nodeIface.setBlacklisted(true);
}
use of org.batfish.datamodel.collections.NodeInterfacePair in project batfish by batfish.
the class Batfish method pathDiff.
@Override
public AnswerElement pathDiff(ReachabilitySettings reachabilitySettings) {
Settings settings = getSettings();
checkDifferentialDataPlaneQuestionDependencies();
String tag = getDifferentialFlowTag();
// load base configurations and generate base data plane
pushBaseEnvironment();
Map<String, Configuration> baseConfigurations = loadConfigurations();
Synthesizer baseDataPlaneSynthesizer = synthesizeDataPlane();
Topology baseTopology = getEnvironmentTopology();
popEnvironment();
// load diff configurations and generate diff data plane
pushDeltaEnvironment();
Map<String, Configuration> diffConfigurations = loadConfigurations();
Synthesizer diffDataPlaneSynthesizer = synthesizeDataPlane();
Topology diffTopology = getEnvironmentTopology();
popEnvironment();
pushDeltaEnvironment();
SortedSet<String> blacklistNodes = getNodeBlacklist();
Set<NodeInterfacePair> blacklistInterfaces = getInterfaceBlacklist();
SortedSet<Edge> blacklistEdges = getEdgeBlacklist();
popEnvironment();
BlacklistDstIpQuerySynthesizer blacklistQuery = new BlacklistDstIpQuerySynthesizer(null, blacklistNodes, blacklistInterfaces, blacklistEdges, baseConfigurations);
// compute composite program and flows
List<Synthesizer> commonEdgeSynthesizers = ImmutableList.of(baseDataPlaneSynthesizer, diffDataPlaneSynthesizer, baseDataPlaneSynthesizer);
List<CompositeNodJob> jobs = new ArrayList<>();
// generate local edge reachability and black hole queries
SortedSet<Edge> diffEdges = diffTopology.getEdges();
for (Edge edge : diffEdges) {
String ingressNode = edge.getNode1();
String outInterface = edge.getInt1();
String vrf = diffConfigurations.get(ingressNode).getInterfaces().get(outInterface).getVrf().getName();
ReachEdgeQuerySynthesizer reachQuery = new ReachEdgeQuerySynthesizer(ingressNode, vrf, edge, true, reachabilitySettings.getHeaderSpace());
ReachEdgeQuerySynthesizer noReachQuery = new ReachEdgeQuerySynthesizer(ingressNode, vrf, edge, true, new HeaderSpace());
noReachQuery.setNegate(true);
List<QuerySynthesizer> queries = ImmutableList.of(reachQuery, noReachQuery, blacklistQuery);
SortedSet<Pair<String, String>> nodes = ImmutableSortedSet.of(new Pair<>(ingressNode, vrf));
CompositeNodJob job = new CompositeNodJob(settings, commonEdgeSynthesizers, queries, nodes, tag);
jobs.add(job);
}
// we also need queries for nodes next to edges that are now missing,
// in the case that those nodes still exist
List<Synthesizer> missingEdgeSynthesizers = ImmutableList.of(baseDataPlaneSynthesizer, baseDataPlaneSynthesizer);
SortedSet<Edge> baseEdges = baseTopology.getEdges();
SortedSet<Edge> missingEdges = ImmutableSortedSet.copyOf(Sets.difference(baseEdges, diffEdges));
for (Edge missingEdge : missingEdges) {
String ingressNode = missingEdge.getNode1();
String outInterface = missingEdge.getInt1();
if (diffConfigurations.containsKey(ingressNode) && diffConfigurations.get(ingressNode).getInterfaces().containsKey(outInterface)) {
String vrf = diffConfigurations.get(ingressNode).getInterfaces().get(outInterface).getVrf().getName();
ReachEdgeQuerySynthesizer reachQuery = new ReachEdgeQuerySynthesizer(ingressNode, vrf, missingEdge, true, reachabilitySettings.getHeaderSpace());
List<QuerySynthesizer> queries = ImmutableList.of(reachQuery, blacklistQuery);
SortedSet<Pair<String, String>> nodes = ImmutableSortedSet.of(new Pair<>(ingressNode, vrf));
CompositeNodJob job = new CompositeNodJob(settings, missingEdgeSynthesizers, queries, nodes, tag);
jobs.add(job);
}
}
// TODO: maybe do something with nod answer element
Set<Flow> flows = computeCompositeNodOutput(jobs, new NodAnswerElement());
pushBaseEnvironment();
getDataPlanePlugin().processFlows(flows, loadDataPlane());
popEnvironment();
pushDeltaEnvironment();
getDataPlanePlugin().processFlows(flows, loadDataPlane());
popEnvironment();
AnswerElement answerElement = getHistory();
return answerElement;
}
use of org.batfish.datamodel.collections.NodeInterfacePair in project batfish by batfish.
the class Graph method initGraph.
/*
* Initialize the topology by inferring interface pairs and
* create the opposite edge mapping.
*/
private void initGraph(Topology topology) {
Map<NodeInterfacePair, Interface> ifaceMap = new HashMap<>();
Map<String, Set<NodeInterfacePair>> routerIfaceMap = new HashMap<>();
for (Entry<String, Configuration> entry : _configurations.entrySet()) {
String router = entry.getKey();
Configuration conf = entry.getValue();
Set<NodeInterfacePair> ifacePairs = new HashSet<>();
for (Entry<String, Interface> entry2 : conf.getInterfaces().entrySet()) {
String name = entry2.getKey();
Interface iface = entry2.getValue();
NodeInterfacePair nip = new NodeInterfacePair(router, name);
ifacePairs.add(nip);
ifaceMap.put(nip, iface);
}
routerIfaceMap.put(router, ifacePairs);
}
Map<NodeInterfacePair, SortedSet<Edge>> ifaceEdges = topology.getInterfaceEdges();
_neighbors = new HashMap<>();
for (Entry<String, Set<NodeInterfacePair>> entry : routerIfaceMap.entrySet()) {
String router = entry.getKey();
Set<NodeInterfacePair> nips = entry.getValue();
Set<GraphEdge> graphEdges = new HashSet<>();
Set<String> neighs = new HashSet<>();
for (NodeInterfacePair nip : nips) {
SortedSet<Edge> es = ifaceEdges.get(nip);
Interface i1 = ifaceMap.get(nip);
boolean hasNoOtherEnd = (es == null && i1.getAddress() != null);
if (hasNoOtherEnd) {
GraphEdge ge = new GraphEdge(i1, null, router, null, false, false);
graphEdges.add(ge);
}
if (es != null) {
boolean hasMultipleEnds = (es.size() > 2);
if (hasMultipleEnds) {
GraphEdge ge = new GraphEdge(i1, null, router, null, false, false);
graphEdges.add(ge);
} else {
for (Edge e : es) {
// Weird inference behavior from Batfish here with a self-loop
if (router.equals(e.getNode1()) && router.equals(e.getNode2())) {
GraphEdge ge = new GraphEdge(i1, null, router, null, false, false);
graphEdges.add(ge);
}
// Only look at the first pair
if (!router.equals(e.getNode2())) {
Interface i2 = ifaceMap.get(e.getInterface2());
String neighbor = e.getNode2();
GraphEdge ge1 = new GraphEdge(i1, i2, router, neighbor, false, false);
GraphEdge ge2 = new GraphEdge(i2, i1, neighbor, router, false, false);
_otherEnd.put(ge1, ge2);
graphEdges.add(ge1);
neighs.add(neighbor);
}
}
}
}
}
_allRealEdges.addAll(graphEdges);
_allEdges.addAll(graphEdges);
_edgeMap.put(router, new ArrayList<>(graphEdges));
_neighbors.put(router, neighs);
}
}
Aggregations