use of org.batfish.z3.Synthesizer in project batfish by batfish.
the class Batfish method answerAclReachability.
@Override
public AnswerElement answerAclReachability(String aclNameRegexStr, NamedStructureEquivalenceSets<?> aclEqSets) {
AclLinesAnswerElement answerElement = new AclLinesAnswerElement();
Pattern aclNameRegex;
try {
aclNameRegex = Pattern.compile(aclNameRegexStr);
} catch (PatternSyntaxException e) {
throw new BatfishException("Supplied regex for nodes is not a valid java regex: \"" + aclNameRegexStr + "\"", e);
}
Map<String, Configuration> configurations = loadConfigurations();
List<NodSatJob<AclLine>> jobs = new ArrayList<>();
for (Entry<String, ?> e : aclEqSets.getSameNamedStructures().entrySet()) {
String aclName = e.getKey();
if (!aclNameRegex.matcher(aclName).matches()) {
continue;
}
// operator error
if (aclName.contains("~ZONE_INTERFACE_FILTER~") || aclName.contains("~INBOUND_ZONE_FILTER~")) {
continue;
}
Set<?> s = (Set<?>) e.getValue();
for (Object o : s) {
NamedStructureEquivalenceSet<?> aclEqSet = (NamedStructureEquivalenceSet<?>) o;
String hostname = aclEqSet.getRepresentativeElement();
SortedSet<String> eqClassNodes = aclEqSet.getNodes();
answerElement.addEquivalenceClass(aclName, hostname, eqClassNodes);
Configuration c = configurations.get(hostname);
IpAccessList acl = c.getIpAccessLists().get(aclName);
int numLines = acl.getLines().size();
if (numLines == 0) {
_logger.redflag("RED_FLAG: Acl \"" + hostname + ":" + aclName + "\" contains no lines\n");
continue;
}
AclReachabilityQuerySynthesizer query = new AclReachabilityQuerySynthesizer(hostname, aclName, numLines);
Synthesizer aclSynthesizer = synthesizeAcls(Collections.singletonMap(hostname, c));
NodSatJob<AclLine> job = new NodSatJob<>(_settings, aclSynthesizer, query);
jobs.add(job);
}
}
Map<AclLine, Boolean> output = new TreeMap<>();
computeNodSatOutput(jobs, output);
// rearrange output for next step
Map<String, Map<String, List<AclLine>>> arrangedAclLines = new TreeMap<>();
for (Entry<AclLine, Boolean> e : output.entrySet()) {
AclLine line = e.getKey();
String hostname = line.getHostname();
Map<String, List<AclLine>> byAclName = arrangedAclLines.computeIfAbsent(hostname, k -> new TreeMap<>());
String aclName = line.getAclName();
List<AclLine> aclLines = byAclName.computeIfAbsent(aclName, k -> new ArrayList<>());
aclLines.add(line);
}
// now get earliest more general lines
List<NodFirstUnsatJob<AclLine, Integer>> step2Jobs = new ArrayList<>();
for (Entry<String, Map<String, List<AclLine>>> e : arrangedAclLines.entrySet()) {
String hostname = e.getKey();
Configuration c = configurations.get(hostname);
Synthesizer aclSynthesizer = synthesizeAcls(Collections.singletonMap(hostname, c));
Map<String, List<AclLine>> byAclName = e.getValue();
for (Entry<String, List<AclLine>> e2 : byAclName.entrySet()) {
String aclName = e2.getKey();
IpAccessList ipAccessList = c.getIpAccessLists().get(aclName);
List<AclLine> lines = e2.getValue();
for (int i = 0; i < lines.size(); i++) {
AclLine line = lines.get(i);
boolean reachable = output.get(line);
if (!reachable) {
List<AclLine> toCheck = new ArrayList<>();
for (int j = 0; j < i; j++) {
AclLine earlierLine = lines.get(j);
boolean earlierIsReachable = output.get(earlierLine);
if (earlierIsReachable) {
toCheck.add(earlierLine);
}
}
EarliestMoreGeneralReachableLineQuerySynthesizer query = new EarliestMoreGeneralReachableLineQuerySynthesizer(line, toCheck, ipAccessList);
NodFirstUnsatJob<AclLine, Integer> job = new NodFirstUnsatJob<>(_settings, aclSynthesizer, query);
step2Jobs.add(job);
}
}
}
}
Map<AclLine, Integer> step2Output = new TreeMap<>();
computeNodFirstUnsatOutput(step2Jobs, step2Output);
for (AclLine line : output.keySet()) {
Integer earliestMoreGeneralReachableLine = step2Output.get(line);
line.setEarliestMoreGeneralReachableLine(earliestMoreGeneralReachableLine);
}
Set<Pair<String, String>> aclsWithUnreachableLines = new TreeSet<>();
Set<Pair<String, String>> allAcls = new TreeSet<>();
int numUnreachableLines = 0;
int numLines = output.entrySet().size();
for (Entry<AclLine, Boolean> e : output.entrySet()) {
AclLine aclLine = e.getKey();
boolean sat = e.getValue();
String hostname = aclLine.getHostname();
String aclName = aclLine.getAclName();
Pair<String, String> qualifiedAclName = new Pair<>(hostname, aclName);
allAcls.add(qualifiedAclName);
if (!sat) {
numUnreachableLines++;
aclsWithUnreachableLines.add(qualifiedAclName);
}
}
for (Entry<AclLine, Boolean> e : output.entrySet()) {
AclLine aclLine = e.getKey();
int index = aclLine.getLine();
boolean sat = e.getValue();
String hostname = aclLine.getHostname();
String aclName = aclLine.getAclName();
Pair<String, String> qualifiedAclName = new Pair<>(hostname, aclName);
IpAccessList ipAccessList = configurations.get(hostname).getIpAccessLists().get(aclName);
IpAccessListLine ipAccessListLine = ipAccessList.getLines().get(index);
AclReachabilityEntry line = new AclReachabilityEntry(index, ipAccessListLine.getName());
if (aclsWithUnreachableLines.contains(qualifiedAclName)) {
if (sat) {
_logger.debugf("%s:%s:%d:'%s' is REACHABLE\n", hostname, aclName, line.getIndex(), line.getName());
answerElement.addReachableLine(hostname, ipAccessList, line);
} else {
_logger.debugf("%s:%s:%d:'%s' is UNREACHABLE\n\t%s\n", hostname, aclName, line.getIndex(), line.getName(), ipAccessListLine.toString());
Integer earliestMoreGeneralLineIndex = aclLine.getEarliestMoreGeneralReachableLine();
if (earliestMoreGeneralLineIndex != null) {
IpAccessListLine earliestMoreGeneralLine = ipAccessList.getLines().get(earliestMoreGeneralLineIndex);
line.setEarliestMoreGeneralLineIndex(earliestMoreGeneralLineIndex);
line.setEarliestMoreGeneralLineName(earliestMoreGeneralLine.getName());
if (!earliestMoreGeneralLine.getAction().equals(ipAccessListLine.getAction())) {
line.setDifferentAction(true);
}
}
answerElement.addUnreachableLine(hostname, ipAccessList, line);
aclsWithUnreachableLines.add(qualifiedAclName);
}
} else {
answerElement.addReachableLine(hostname, ipAccessList, line);
}
}
for (Pair<String, String> qualfiedAcl : aclsWithUnreachableLines) {
String hostname = qualfiedAcl.getFirst();
String aclName = qualfiedAcl.getSecond();
_logger.debugf("%s:%s has at least 1 unreachable line\n", hostname, aclName);
}
int numAclsWithUnreachableLines = aclsWithUnreachableLines.size();
int numAcls = allAcls.size();
double percentUnreachableAcls = 100d * numAclsWithUnreachableLines / numAcls;
double percentUnreachableLines = 100d * numUnreachableLines / numLines;
_logger.debugf("SUMMARY:\n");
_logger.debugf("\t%d/%d (%.1f%%) acls have unreachable lines\n", numAclsWithUnreachableLines, numAcls, percentUnreachableAcls);
_logger.debugf("\t%d/%d (%.1f%%) acl lines are unreachable\n", numUnreachableLines, numLines, percentUnreachableLines);
return answerElement;
}
use of org.batfish.z3.Synthesizer 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.z3.Synthesizer in project batfish by batfish.
the class Batfish method synthesizeDataPlane.
@Nonnull
public Synthesizer synthesizeDataPlane(Map<String, Configuration> configurations, DataPlane dataPlane, ForwardingAnalysis forwardingAnalysis, HeaderSpace headerSpace, boolean specialize) {
_logger.info("\n*** GENERATING Z3 LOGIC ***\n");
_logger.resetTimer();
_logger.info("Synthesizing Z3 logic...");
Synthesizer s = new Synthesizer(computeSynthesizerInput(configurations, dataPlane, forwardingAnalysis, headerSpace, _settings.getSimplify(), specialize));
List<String> warnings = s.getWarnings();
int numWarnings = warnings.size();
if (numWarnings == 0) {
_logger.info("OK\n");
} else {
for (String warning : warnings) {
_logger.warn(warning);
}
}
_logger.printElapsedTime();
return s;
}
use of org.batfish.z3.Synthesizer in project batfish by batfish.
the class Batfish method synthesizeAcls.
private Synthesizer synthesizeAcls(Map<String, Configuration> configurations) {
_logger.info("\n*** GENERATING Z3 LOGIC ***\n");
_logger.resetTimer();
_logger.info("Synthesizing Z3 ACL logic...");
Synthesizer s = new Synthesizer(SynthesizerInputImpl.builder().setConfigurations(configurations).setSimplify(_settings.getSimplify()).build());
List<String> warnings = s.getWarnings();
int numWarnings = warnings.size();
if (numWarnings == 0) {
_logger.info("OK\n");
} else {
for (String warning : warnings) {
_logger.warn(warning);
}
}
_logger.printElapsedTime();
return s;
}
use of org.batfish.z3.Synthesizer in project batfish by batfish.
the class Batfish method reducedReachability.
@Override
public AnswerElement reducedReachability(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();
popEnvironment();
// load diff configurations and generate diff data plane
pushDeltaEnvironment();
Map<String, Configuration> diffConfigurations = loadConfigurations();
Synthesizer diffDataPlaneSynthesizer = synthesizeDataPlane();
popEnvironment();
Set<String> ingressNodes;
try {
ingressNodes = ImmutableSet.copyOf(Sets.intersection(reachabilitySettings.computeActiveIngressNodes(baseConfigurations), reachabilitySettings.computeActiveIngressNodes(diffConfigurations)));
} catch (InvalidReachabilitySettingsException e) {
return e.getInvalidSettingsAnswer();
}
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> synthesizers = ImmutableList.of(baseDataPlaneSynthesizer, diffDataPlaneSynthesizer, baseDataPlaneSynthesizer);
// generate base reachability and diff blackhole and blacklist queries
List<CompositeNodJob> jobs = ingressNodes.stream().flatMap(node -> baseConfigurations.get(node).getVrfs().keySet().stream().map(vrf -> {
Map<String, Set<String>> ingressNodeVrfs = ImmutableMap.of(node, ImmutableSet.of(vrf));
StandardReachabilityQuerySynthesizer acceptQuery = StandardReachabilityQuerySynthesizer.builder().setActions(ImmutableSet.of(ForwardingAction.ACCEPT, ForwardingAction.NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK)).setHeaderSpace(reachabilitySettings.getHeaderSpace()).setIngressNodeVrfs(ingressNodeVrfs).setFinalNodes(ImmutableSet.of()).setTransitNodes(ImmutableSet.of()).setNonTransitNodes(ImmutableSet.of()).setSrcNatted(reachabilitySettings.getSrcNatted()).build();
StandardReachabilityQuerySynthesizer notAcceptQuery = StandardReachabilityQuerySynthesizer.builder().setActions(ImmutableSet.of(ForwardingAction.ACCEPT, ForwardingAction.NEIGHBOR_UNREACHABLE_OR_EXITS_NETWORK)).setHeaderSpace(new HeaderSpace()).setIngressNodeVrfs(ingressNodeVrfs).setFinalNodes(ImmutableSet.of()).setTransitNodes(ImmutableSet.of()).setNonTransitNodes(ImmutableSet.of()).build();
notAcceptQuery.setNegate(true);
SortedSet<Pair<String, String>> nodes = ImmutableSortedSet.of(new Pair<>(node, vrf));
List<QuerySynthesizer> queries = ImmutableList.of(acceptQuery, notAcceptQuery, blacklistQuery);
return new CompositeNodJob(settings, synthesizers, queries, nodes, tag);
})).collect(Collectors.toList());
// 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;
}
Aggregations