use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class Z3ContextJob method getSolverInput.
protected BoolExpr getSolverInput(Expr answer, NodProgram program, boolean negate) {
BoolExpr solverInput;
if (answer.getArgs().length > 0) {
Map<String, BitVecExpr> variablesAsConsts = program.getNodContext().getVariablesAsConsts();
List<BitVecExpr> reversedVars = Lists.reverse(program.getNodContext().getVariableNames().stream().filter(name -> !TransformationHeaderField.transformationHeaderFieldNames.contains(name)).map(variablesAsConsts::get).collect(Collectors.toList()));
Expr substitutedAnswer = answer.substituteVars(reversedVars.toArray(new Expr[] {}));
solverInput = (BoolExpr) substitutedAnswer;
} else {
solverInput = (BoolExpr) answer;
}
if (negate) {
solverInput = program.getNodContext().getContext().mkNot(solverInput);
}
return solverInput;
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class BitVecExprTransformer method visitVarIntExpr.
@Override
public BitVecExpr visitVarIntExpr(VarIntExpr varIntExpr) {
String headerField = varIntExpr.getField().getName();
BitVecExpr ret = _nodContext.getVariables().get(headerField);
if (ret == null) {
throw new BatfishException("nodContext missing mapping for variable: '" + headerField + "'");
}
return ret;
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class EncoderSlice method computeWildcardMatch.
/*
* Convert a set of wildcards and a packet field to a symbolic boolean expression
*/
private BoolExpr computeWildcardMatch(Set<IpWildcard> wcs, BitVecExpr field) {
BoolExpr acc = mkFalse();
for (IpWildcard wc : wcs) {
ipWildCardBound(field, wc);
acc = mkOr(acc, ipWildCardBound(field, wc));
}
return (BoolExpr) acc.simplify();
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class EncoderSlice method addControlForwardingConstraints.
/*
* Constraints that define control-plane forwarding.
* If there is some valid import, then control plane forwarding
* will occur out an interface when this is the best choice.
* Otherwise, it will not occur.
*/
private void addControlForwardingConstraints() {
for (Entry<String, Configuration> entry : getGraph().getConfigurations().entrySet()) {
String router = entry.getKey();
Configuration conf = entry.getValue();
boolean someEdge = false;
SymbolicRoute best = _symbolicDecisions.getBestNeighbor().get(router);
Map<GraphEdge, BoolExpr> cfExprs = new HashMap<>();
Set<GraphEdge> constrained = new HashSet<>();
for (Protocol proto : getProtocols().get(router)) {
for (LogicalEdge e : collectAllImportLogicalEdges(router, conf, proto)) {
someEdge = true;
constrained.add(e.getEdge());
SymbolicRoute vars = correctVars(e);
BoolExpr choice = _symbolicDecisions.getChoiceVariables().get(router, proto, e);
BoolExpr isBest = mkAnd(choice, equal(conf, proto, best, vars, e, false));
GraphEdge ge = e.getEdge();
// Connected routes should only forward if not absorbed by interface
GraphEdge other = getGraph().getOtherEnd().get(ge);
BoolExpr connectedWillSend;
if (other == null || getGraph().isHost(ge.getPeer())) {
Ip ip = ge.getStart().getAddress().getIp();
BitVecExpr val = getCtx().mkBV(ip.asLong(), 32);
connectedWillSend = mkNot(mkEq(_symbolicPacket.getDstIp(), val));
} else {
Ip ip = other.getStart().getAddress().getIp();
BitVecExpr val = getCtx().mkBV(ip.asLong(), 32);
connectedWillSend = mkEq(_symbolicPacket.getDstIp(), val);
}
BoolExpr canSend = (proto.isConnected() ? connectedWillSend : mkTrue());
BoolExpr sends = mkAnd(canSend, isBest);
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
add(mkImplies(sends, cForward));
// record the negation as well
cfExprs.merge(ge, sends, (a, b) -> mkOr(a, b));
}
}
// For edges that are never used, we constraint them to not be forwarded out of
for (GraphEdge ge : getGraph().getEdgeMap().get(router)) {
if (!constrained.contains(ge)) {
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
add(mkNot(cForward));
}
}
// Handle the case that the router has no protocol running
if (!someEdge) {
for (GraphEdge ge : getGraph().getEdgeMap().get(router)) {
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
add(mkNot(cForward));
}
} else {
// If no best route, then no forwarding
Map<Protocol, List<ArrayList<LogicalEdge>>> map = _logicalGraph.getLogicalEdges().get(router);
Set<GraphEdge> seen = new HashSet<>();
for (List<ArrayList<LogicalEdge>> eList : map.values()) {
for (ArrayList<LogicalEdge> edges : eList) {
for (LogicalEdge le : edges) {
GraphEdge ge = le.getEdge();
if (seen.contains(ge)) {
continue;
}
seen.add(ge);
BoolExpr expr = cfExprs.get(ge);
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
if (expr != null) {
add(mkImplies(mkNot(expr), mkNot(cForward)));
} else {
add(mkNot(cForward));
}
}
}
}
}
}
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class EncoderSlice method greaterOrEqual.
/*
* Check if a (best) symbolic record is better than another
* symbolic record (vars). This is done using a recursive lexicographic
* encoding. The encoding is as follows:
*
* (best.length > vars.length) or
* (best.length = vars.length) and (
* (best.adminDist < vars.adminDist) or
* (best.adminDist = vars.adminDist) and (
* ...
* )
* )
*
* This recursive encoding introduces a new variable for each subexpressions,
* which ends up being much more efficient than expanding out options.
*/
private BoolExpr greaterOrEqual(Configuration conf, Protocol proto, SymbolicRoute best, SymbolicRoute vars, @Nullable LogicalEdge e) {
ArithExpr defaultLocal = mkInt(defaultLocalPref());
ArithExpr defaultAdmin = defaultAdminDistance(conf, proto, vars);
ArithExpr defaultMet = mkInt(defaultMetric());
ArithExpr defaultMed = mkInt(defaultMed(proto));
ArithExpr defaultLen = mkInt(defaultLength());
ArithExpr defaultIgp = mkInt(defaultIgpMetric());
ArithExpr defaultId = mkInt(0);
BitVecExpr defaultOspfType = defaultOspfType();
BoolExpr betterLen = geBetterHelper(best.getPrefixLength(), vars.getPrefixLength(), defaultLen, false);
BoolExpr equalLen = geEqualHelper(best.getPrefixLength(), vars.getPrefixLength(), defaultLen);
BoolExpr betterAd = geBetterHelper(best.getAdminDist(), vars.getAdminDist(), defaultAdmin, true);
BoolExpr equalAd = geEqualHelper(best.getAdminDist(), vars.getAdminDist(), defaultAdmin);
BoolExpr betterLp = geBetterHelper(best.getLocalPref(), vars.getLocalPref(), defaultLocal, false);
BoolExpr equalLp = geEqualHelper(best.getLocalPref(), vars.getLocalPref(), defaultLocal);
BoolExpr betterMet = geBetterHelper(best.getMetric(), vars.getMetric(), defaultMet, true);
BoolExpr equalMet = geEqualHelper(best.getMetric(), vars.getMetric(), defaultMet);
BoolExpr betterMed = geBetterHelper(best.getMed(), vars.getMed(), defaultMed, true);
BoolExpr equalMed = geEqualHelper(best.getMed(), vars.getMed(), defaultMed);
BitVecExpr bestType = (best.getOspfType() == null ? null : best.getOspfType().getBitVec());
BitVecExpr varsType = (vars.getOspfType() == null ? null : vars.getOspfType().getBitVec());
BoolExpr betterOspfType = geBetterHelper(bestType, varsType, defaultOspfType, true);
BoolExpr equalOspfType = geEqualHelper(bestType, varsType, defaultOspfType);
BoolExpr betterInternal = geBetterHelper(best.getBgpInternal(), vars.getBgpInternal(), mkFalse(), true);
BoolExpr equalInternal = geEqualHelper(best.getBgpInternal(), vars.getBgpInternal(), mkFalse());
BoolExpr betterIgpMet = geBetterHelper(best.getIgpMetric(), vars.getIgpMetric(), defaultIgp, true);
BoolExpr equalIgpMet = geEqualHelper(best.getIgpMetric(), vars.getIgpMetric(), defaultIgp);
BoolExpr tiebreak;
if (vars.getRouterId() != null) {
tiebreak = mkLe(best.getRouterId(), vars.getRouterId());
} else if (best.getRouterId() != null) {
if (e == null) {
tiebreak = mkLe(best.getRouterId(), defaultId);
} else {
long peerId = getGraph().findRouterId(e.getEdge(), proto);
tiebreak = mkLe(best.getRouterId(), mkInt(peerId));
}
} else {
tiebreak = mkTrue();
}
BoolExpr b = mkAnd(equalOspfType, tiebreak);
BoolExpr b1 = mkOr(betterOspfType, b);
BoolExpr b2 = mkAnd(equalIgpMet, b1);
BoolExpr b3 = mkOr(betterIgpMet, b2);
BoolExpr b4 = mkAnd(equalInternal, b3);
BoolExpr b5 = mkOr(betterInternal, b4);
BoolExpr b6 = mkAnd(equalMed, b5);
BoolExpr b7 = mkOr(betterMed, b6);
BoolExpr b8 = mkAnd(equalMet, b7);
BoolExpr b9 = mkOr(betterMet, b8);
BoolExpr b10 = mkAnd(equalLp, b9);
BoolExpr b11 = mkOr(betterLp, b10);
BoolExpr b12 = mkAnd(equalAd, b11);
BoolExpr b13 = mkOr(betterAd, b12);
BoolExpr b14 = mkAnd(equalLen, b13);
return mkOr(betterLen, b14);
}
Aggregations