use of org.batfish.z3.state.Query 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.state.Query in project batfish by batfish.
the class EarliestMoreGeneralReachableLineQuerySynthesizer method getReachabilityProgram.
@Override
public ReachabilityProgram getReachabilityProgram(SynthesizerInput input) {
int unreachableLineIndex = _unreachableLine.getLine();
IpAccessListLine unreachableLine = _list.getLines().get(unreachableLineIndex);
BooleanExpr matchUnreachableLineHeaderSpace = new HeaderSpaceMatchExpr(unreachableLine);
ImmutableList.Builder<QueryStatement> queries = ImmutableList.builder();
ImmutableList.Builder<RuleStatement> rules = ImmutableList.builder();
for (AclLine earlierReachableLine : _earlierReachableLines) {
int earlierLineIndex = earlierReachableLine.getLine();
IpAccessListLine earlierLine = _list.getLines().get(earlierLineIndex);
BooleanExpr matchEarlierLineHeaderSpace = new HeaderSpaceMatchExpr(earlierLine);
NumberedQuery queryRel = new NumberedQuery(earlierLineIndex);
rules.add(new BasicRuleStatement(new AndExpr(ImmutableList.of(new NotExpr(matchEarlierLineHeaderSpace), matchUnreachableLineHeaderSpace, SaneExpr.INSTANCE)), queryRel));
QueryStatement query = new QueryStatement(queryRel);
queries.add(query);
_resultsByQueryIndex.add(earlierLineIndex);
}
return ReachabilityProgram.builder().setInput(input).setQueries(queries.build()).setRules(rules.build()).build();
}
use of org.batfish.z3.state.Query in project batfish by batfish.
the class Batfish method singleReachability.
private AnswerElement singleReachability(ReachabilitySettings reachabilitySettings, ReachabilityQuerySynthesizer.Builder<?, ?> builder) {
Settings settings = getSettings();
String tag = getFlowTag(_testrigSettings);
Set<ForwardingAction> actions = reachabilitySettings.getActions();
boolean useCompression = reachabilitySettings.getUseCompression();
// specialized compression
/*
CompressDataPlaneResult compressionResult =
useCompression ? computeCompressedDataPlane(headerSpace) : null;
Map<String, Configuration> configurations =
useCompression ? compressionResult._compressedConfigs : loadConfigurations();
DataPlane dataPlane = useCompression ? compressionResult._compressedDataPlane : loadDataPlane();
*/
// general compression
Snapshot snapshot = getSnapshot();
Map<String, Configuration> configurations = useCompression ? loadCompressedConfigurations(snapshot) : loadConfigurations(snapshot);
DataPlane dataPlane = loadDataPlane(useCompression);
if (configurations == null) {
throw new BatfishException("error loading configurations");
}
if (dataPlane == null) {
throw new BatfishException("error loading data plane");
}
Set<String> activeIngressNodes;
Set<String> activeFinalNodes;
HeaderSpace headerSpace;
Set<String> transitNodes;
Set<String> nonTransitNodes;
int maxChunkSize;
try {
activeIngressNodes = reachabilitySettings.computeActiveIngressNodes(configurations);
activeFinalNodes = reachabilitySettings.computeActiveFinalNodes(configurations);
headerSpace = reachabilitySettings.getHeaderSpace();
transitNodes = reachabilitySettings.computeActiveTransitNodes(configurations);
nonTransitNodes = reachabilitySettings.computeActiveNonTransitNodes(configurations);
maxChunkSize = reachabilitySettings.getMaxChunkSize();
reachabilitySettings.validateTransitNodes(configurations);
} catch (InvalidReachabilitySettingsException e) {
return e.getInvalidSettingsAnswer();
}
List<Pair<String, String>> originateNodeVrfs = activeIngressNodes.stream().flatMap(ingressNode -> configurations.get(ingressNode).getVrfs().keySet().stream().map(ingressVrf -> new Pair<>(ingressNode, ingressVrf))).collect(Collectors.toList());
int chunkSize = Math.max(1, Math.min(maxChunkSize, originateNodeVrfs.size() / _settings.getAvailableThreads()));
// partition originateNodeVrfs into chunks
List<List<Pair<String, String>>> originateNodeVrfChunks = Lists.partition(originateNodeVrfs, chunkSize);
Synthesizer dataPlaneSynthesizer = synthesizeDataPlane(configurations, dataPlane, loadForwardingAnalysis(configurations, dataPlane), headerSpace, reachabilitySettings.getSpecialize());
// build query jobs
List<NodJob> jobs = originateNodeVrfChunks.stream().map(ImmutableSortedSet::copyOf).map(nodeVrfs -> {
SortedMap<String, Set<String>> vrfsByNode = new TreeMap<>();
nodeVrfs.forEach(nodeVrf -> {
String node = nodeVrf.getFirst();
String vrf = nodeVrf.getSecond();
vrfsByNode.computeIfAbsent(node, key -> new TreeSet<>());
vrfsByNode.get(node).add(vrf);
});
ReachabilityQuerySynthesizer query = builder.setActions(actions).setHeaderSpace(headerSpace).setFinalNodes(activeFinalNodes).setIngressNodeVrfs(vrfsByNode).setTransitNodes(transitNodes).setNonTransitNodes(nonTransitNodes).setSrcNatted(reachabilitySettings.getSrcNatted()).build();
return new NodJob(settings, dataPlaneSynthesizer, query, nodeVrfs, tag, reachabilitySettings.getSpecialize());
}).collect(Collectors.toList());
// run jobs and get resulting flows
Set<Flow> flows = computeNodOutput(jobs);
getDataPlanePlugin().processFlows(flows, loadDataPlane());
AnswerElement answerElement = getHistory();
return answerElement;
}
use of org.batfish.z3.state.Query in project batfish by batfish.
the class AbstractNodJob method getOriginateVrfConstraints.
/**
* Try to find a model for each OriginateVrf. If an OriginateVrf does not have an entry in the
* Map, then the query is unsat when originating from there.
*/
protected Map<OriginateVrf, Map<String, Long>> getOriginateVrfConstraints(Context ctx, SmtInput smtInput) {
Solver solver = ctx.mkSolver();
solver.add(smtInput._expr);
int originateVrfBvSize = _originateVrfInstrumentation.getFieldBits();
BitVecExpr originateVrfFieldConst = ctx.mkBVConst(OriginateVrfInstrumentation.ORIGINATE_VRF_FIELD_NAME, originateVrfBvSize);
ImmutableMap.Builder<OriginateVrf, Map<String, Long>> models = ImmutableMap.builder();
// keep refining until no new models
while (true) {
try {
Map<String, Long> constraints = getSolution(solver, smtInput._variablesAsConsts);
int originateVrfId = Math.toIntExact(constraints.get(OriginateVrfInstrumentation.ORIGINATE_VRF_FIELD_NAME));
OriginateVrf originateVrf = _originateVrfInstrumentation.getOriginateVrfs().get(originateVrfId);
models.put(originateVrf, constraints);
// refine: different OriginateVrf
solver.add(ctx.mkNot(ctx.mkEq(originateVrfFieldConst, ctx.mkBV(originateVrfId, originateVrfBvSize))));
} catch (QueryUnsatException e) {
break;
}
}
return models.build();
}
use of org.batfish.z3.state.Query in project batfish by batfish.
the class ReachabilityProgramOptimizerTest method pruneIrrelevant.
/*
* No query statement, so everything is irrelevant
*/
@Test
public void pruneIrrelevant() {
StateExpr state1 = freshStateExpr();
addRuleFor(state1);
StateExpr state2 = freshStateExpr();
addRuleFor(state2, state1);
Set<RuleStatement> rules = optimize();
assertThat(rules, empty());
}
Aggregations