use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class EncoderSlice method ipWildCardBound.
/*
* Create a boolean expression for a variable being withing an IpWildCard bound
*/
private BoolExpr ipWildCardBound(BitVecExpr field, IpWildcard wc) {
BitVecExpr ip = getCtx().mkBV(wc.getIp().asLong(), 32);
BitVecExpr mask = getCtx().mkBV(~wc.getWildcard().asLong(), 32);
return mkEq(getCtx().mkBVAND(field, mask), getCtx().mkBVAND(ip, mask));
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class PropertyAdder method instrumentPathLength.
// Potentially useful in the future to optimize reachability when we know
// that there can't be routing loops e.g., due to a preliminary static analysis
/* public Map<String, BoolExpr> instrumentReachabilityFast(String router) {
Context ctx = _encoderSlice.getCtx();
Solver solver = _encoderSlice.getSolver();
Map<String, BoolExpr> reachableVars = new HashMap<>();
String sliceName = _encoderSlice.getSliceName();
_encoderSlice
.getGraph()
.getConfigurations()
.forEach(
(r, conf) -> {
int id = _encoderSlice.getEncoder().getId();
String s2 = id + "_" + sliceName + "_reachable_" + r;
BoolExpr var = ctx.mkBoolConst(s2);
reachableVars.put(r, var);
_encoderSlice.getAllVariables().put(var.toString(), var);
});
BoolExpr baseReach = reachableVars.get(router);
_encoderSlice.add(baseReach);
_encoderSlice
.getGraph()
.getEdgeMap()
.forEach(
(r, edges) -> {
if (!r.equals(router)) {
BoolExpr reach = reachableVars.get(r);
BoolExpr hasRecursiveRoute = ctx.mkFalse();
for (GraphEdge edge : edges) {
if (!edge.isAbstract()) {
BoolExpr fwd = _encoderSlice.getForwardsAcross().get(r, edge);
if (edge.getPeer() != null) {
BoolExpr peerReachable = reachableVars.get(edge.getPeer());
BoolExpr sendToReachable = ctx.mkAnd(fwd, peerReachable);
hasRecursiveRoute = ctx.mkOr(hasRecursiveRoute, sendToReachable);
}
}
}
solver.add(ctx.mkEq(reach, hasRecursiveRoute));
}
});
return reachableVars;
}
public Map<String, BoolExpr> instrumentReachabilityFast(Set<GraphEdge> ges) {
Context ctx = _encoderSlice.getCtx();
Solver solver = _encoderSlice.getSolver();
EncoderSlice slice = _encoderSlice;
String sliceName = _encoderSlice.getSliceName();
Graph g = slice.getGraph();
Map<String, BoolExpr> reachableVars = new HashMap<>();
_encoderSlice
.getGraph()
.getConfigurations()
.forEach(
(r, conf) -> {
int id = _encoderSlice.getEncoder().getId();
String s2 = id + "_" + sliceName + "_reachable_" + r;
BoolExpr var = ctx.mkBoolConst(s2);
reachableVars.put(r, var);
_encoderSlice.getAllVariables().put(var.toString(), var);
});
for (Entry<String, List<GraphEdge>> entry : g.getEdgeMap().entrySet()) {
String router = entry.getKey();
List<GraphEdge> edges = entry.getValue();
BoolExpr reach = reachableVars.get(router);
// Add the base case, reachable if we forward to a directly connected interface
BoolExpr hasDirectRoute = ctx.mkFalse();
BoolExpr isAbsorbed = ctx.mkFalse();
SymbolicRoute r = _encoderSlice.getBestNeighborPerProtocol(router, Protocol.CONNECTED);
for (GraphEdge ge : edges) {
if (!ge.isAbstract() && ges.contains(ge)) {
// If a host, consider reachable
if (g.isHost(router)) {
hasDirectRoute = ctx.mkTrue();
break;
}
// Reachable if we leave the network
if (ge.getPeer() == null) {
BoolExpr fwdIface = _encoderSlice.getForwardsAcross().get(ge.getRouter(), ge);
assert (fwdIface != null);
hasDirectRoute = ctx.mkOr(hasDirectRoute, fwdIface);
}
// Also reachable if connected route and we use it despite not forwarding
if (r != null) {
BitVecExpr dstIp = _encoderSlice.getSymbolicPacket().getDstIp();
BitVecExpr ip = ctx.mkBV(ge.getStart().getIp().getIp().asLong(), 32);
BoolExpr reachable = ctx.mkAnd(r.getPermitted(), ctx.mkEq(dstIp, ip));
isAbsorbed = ctx.mkOr(isAbsorbed, reachable);
}
}
}
// Add the recursive case, where it is reachable through a neighbor
BoolExpr hasRecursiveRoute = ctx.mkFalse();
for (GraphEdge edge : edges) {
if (!edge.isAbstract()) {
BoolExpr fwd = _encoderSlice.getForwardsAcross().get(router, edge);
if (edge.getPeer() != null) {
BoolExpr peerReachable = reachableVars.get(edge.getPeer());
BoolExpr sendToReachable = ctx.mkAnd(fwd, peerReachable);
hasRecursiveRoute = ctx.mkOr(hasRecursiveRoute, sendToReachable);
}
}
}
BoolExpr cond = slice.mkOr(hasDirectRoute, isAbsorbed, hasRecursiveRoute);
solver.add(slice.mkEq(reach, cond));
}
return reachableVars;
} */
/*
* Instruments the network with path length information to a
* destination port corresponding to a graph edge ge.
* A router has a path of length n if some neighbor has a path
* with length n-1.
*/
Map<String, ArithExpr> instrumentPathLength(Set<GraphEdge> ges) {
Context ctx = _encoderSlice.getCtx();
Solver solver = _encoderSlice.getSolver();
String sliceName = _encoderSlice.getSliceName();
// Initialize path length variables
Graph graph = _encoderSlice.getGraph();
Map<String, ArithExpr> lenVars = new HashMap<>();
for (String router : graph.getRouters()) {
String name = _encoderSlice.getEncoder().getId() + "_" + sliceName + "_path-length_" + router;
ArithExpr var = ctx.mkIntConst(name);
lenVars.put(router, var);
_encoderSlice.getAllVariables().put(var.toString(), var);
}
ArithExpr zero = ctx.mkInt(0);
ArithExpr one = ctx.mkInt(1);
ArithExpr minusOne = ctx.mkInt(-1);
// Lower bound for all lengths
lenVars.forEach((name, var) -> solver.add(ctx.mkGe(var, minusOne)));
for (Entry<String, List<GraphEdge>> entry : graph.getEdgeMap().entrySet()) {
String router = entry.getKey();
List<GraphEdge> edges = entry.getValue();
ArithExpr length = lenVars.get(router);
// If there is a direct route, then we have length 0
BoolExpr hasDirectRoute = ctx.mkFalse();
BoolExpr isAbsorbed = ctx.mkFalse();
SymbolicRoute r = _encoderSlice.getBestNeighborPerProtocol(router, Protocol.CONNECTED);
for (GraphEdge ge : edges) {
if (!ge.isAbstract() && ges.contains(ge)) {
// Reachable if we leave the network
if (ge.getPeer() == null) {
BoolExpr fwdIface = _encoderSlice.getForwardsAcross().get(ge.getRouter(), ge);
assert (fwdIface != null);
hasDirectRoute = ctx.mkOr(hasDirectRoute, fwdIface);
}
// Also reachable if connected route and we use it despite not forwarding
if (r != null) {
BitVecExpr dstIp = _encoderSlice.getSymbolicPacket().getDstIp();
BitVecExpr ip = ctx.mkBV(ge.getStart().getAddress().getIp().asLong(), 32);
BoolExpr reach = ctx.mkAnd(r.getPermitted(), ctx.mkEq(dstIp, ip));
isAbsorbed = ctx.mkOr(isAbsorbed, reach);
}
}
}
// Otherwise, we find length recursively
BoolExpr accNone = ctx.mkTrue();
BoolExpr accSome = ctx.mkFalse();
for (GraphEdge edge : edges) {
if (!edge.isAbstract() && edge.getPeer() != null) {
BoolExpr dataFwd = _encoderSlice.getForwardsAcross().get(router, edge);
assert (dataFwd != null);
ArithExpr peerLen = lenVars.get(edge.getPeer());
accNone = ctx.mkAnd(accNone, ctx.mkOr(ctx.mkLt(peerLen, zero), ctx.mkNot(dataFwd)));
ArithExpr newVal = ctx.mkAdd(peerLen, one);
BoolExpr fwd = ctx.mkAnd(ctx.mkGe(peerLen, zero), dataFwd, ctx.mkEq(length, newVal));
accSome = ctx.mkOr(accSome, fwd);
}
}
BoolExpr guard = _encoderSlice.mkOr(hasDirectRoute, isAbsorbed);
BoolExpr cond1 = _encoderSlice.mkIf(accNone, ctx.mkEq(length, minusOne), accSome);
BoolExpr cond2 = _encoderSlice.mkIf(guard, ctx.mkEq(length, zero), cond1);
solver.add(cond2);
}
return lenVars;
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class PropertyAdder method instrumentReachability.
/*
* Add reachability information to the network for a destination edge.
* Each router will have a boolean variable determining if it can reach
* the destination. A router is reachable if it has some neighbor that
* is also reachable.
*/
Map<String, BoolExpr> instrumentReachability(Set<GraphEdge> ges) {
Context ctx = _encoderSlice.getCtx();
Solver solver = _encoderSlice.getSolver();
EncoderSlice slice = _encoderSlice;
Map<String, BoolExpr> reachableVars = new HashMap<>();
Map<String, ArithExpr> idVars = new HashMap<>();
initializeReachabilityVars(slice, ctx, solver, reachableVars, idVars);
Graph g = _encoderSlice.getGraph();
for (Entry<String, List<GraphEdge>> entry : g.getEdgeMap().entrySet()) {
String router = entry.getKey();
List<GraphEdge> edges = entry.getValue();
ArithExpr id = idVars.get(router);
// Add the base case, reachable if we forward to a directly connected interface
BoolExpr hasDirectRoute = ctx.mkFalse();
BoolExpr isAbsorbed = ctx.mkFalse();
SymbolicRoute r = _encoderSlice.getBestNeighborPerProtocol(router, Protocol.CONNECTED);
for (GraphEdge ge : edges) {
if (!ge.isAbstract() && ges.contains(ge)) {
// If a host, consider reachable
if (g.isHost(router)) {
hasDirectRoute = ctx.mkTrue();
break;
}
// Reachable if we leave the network
if (ge.getPeer() == null) {
BoolExpr fwdIface = _encoderSlice.getForwardsAcross().get(ge.getRouter(), ge);
assert (fwdIface != null);
hasDirectRoute = ctx.mkOr(hasDirectRoute, fwdIface);
}
// Also reachable if connected route and we use it despite not forwarding
if (r != null) {
BitVecExpr dstIp = _encoderSlice.getSymbolicPacket().getDstIp();
BitVecExpr ip = ctx.mkBV(ge.getStart().getAddress().getIp().asLong(), 32);
BoolExpr reach = ctx.mkAnd(r.getPermitted(), ctx.mkEq(dstIp, ip));
isAbsorbed = ctx.mkOr(isAbsorbed, reach);
}
}
}
// Add the recursive case, where it is reachable through a neighbor
BoolExpr recursive = recursiveReachability(ctx, slice, edges, idVars, router, id);
BoolExpr guard = ctx.mkOr(hasDirectRoute, isAbsorbed);
BoolExpr cond = slice.mkIf(guard, ctx.mkEq(id, ctx.mkInt(1)), recursive);
solver.add(cond);
}
return reachableVars;
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class TransferSSA method joinPoint.
/*
* The [phi] function from SSA that merges variables that may differ across
* different branches of an mkIf statement.
*/
private Pair<Expr, Expr> joinPoint(TransferParam<SymbolicRoute> p, TransferResult<BoolExpr, BoolExpr> r, BoolExpr guard, Pair<String, Pair<Expr, Expr>> values) {
String variableName = values.getFirst();
Expr trueBranch = values.getSecond().getFirst();
Expr falseBranch = values.getSecond().getSecond();
if (variableName.equals("RETURN") || variableName.equals("FALLTHROUGH")) {
Expr t = (trueBranch == null ? _enc.mkFalse() : // can use False because the value has not been assigned
trueBranch);
Expr f = (falseBranch == null ? _enc.mkFalse() : falseBranch);
Expr tass = (trueBranch == null ? r.getReturnAssignedValue() : _enc.mkTrue());
Expr fass = (falseBranch == null ? r.getReturnAssignedValue() : _enc.mkTrue());
BoolExpr newAss = _enc.mkIf(guard, (BoolExpr) tass, (BoolExpr) fass);
BoolExpr retAss = createBoolVariableWith(p, "ASSIGNED", newAss);
BoolExpr variable = (variableName.equals("RETURN") ? r.getReturnValue() : r.getFallthroughValue());
BoolExpr newValue = _enc.mkIf(r.getReturnAssignedValue(), variable, _enc.mkIf(guard, (BoolExpr) t, (BoolExpr) f));
BoolExpr ret = createBoolVariableWith(p, variableName, newValue);
return new Pair<>(ret, retAss);
}
if (variableName.equals("PREFIX-LEN")) {
Expr t = (trueBranch == null ? p.getData().getPrefixLength() : trueBranch);
Expr f = (falseBranch == null ? p.getData().getPrefixLength() : falseBranch);
ArithExpr newValue = _enc.mkIf(guard, (ArithExpr) t, (ArithExpr) f);
newValue = _enc.mkIf(r.getReturnAssignedValue(), p.getData().getPrefixLength(), newValue);
ArithExpr ret = createArithVariableWith(p, "PREFIX-LEN", newValue);
p.getData().setPrefixLength(ret);
return new Pair<>(ret, null);
}
if (variableName.equals("ADMIN-DIST")) {
Expr t = (trueBranch == null ? p.getData().getAdminDist() : trueBranch);
Expr f = (falseBranch == null ? p.getData().getAdminDist() : falseBranch);
ArithExpr newValue = _enc.mkIf(guard, (ArithExpr) t, (ArithExpr) f);
newValue = _enc.mkIf(r.getReturnAssignedValue(), p.getData().getAdminDist(), newValue);
ArithExpr ret = createArithVariableWith(p, "ADMIN-DIST", newValue);
p.getData().setAdminDist(ret);
return new Pair<>(ret, null);
}
if (variableName.equals("LOCAL-PREF")) {
Expr t = (trueBranch == null ? p.getData().getLocalPref() : trueBranch);
Expr f = (falseBranch == null ? p.getData().getLocalPref() : falseBranch);
ArithExpr newValue = _enc.mkIf(guard, (ArithExpr) t, (ArithExpr) f);
newValue = _enc.mkIf(r.getReturnAssignedValue(), p.getData().getLocalPref(), newValue);
ArithExpr ret = createArithVariableWith(p, "LOCAL-PREF", newValue);
p.getData().setLocalPref(ret);
return new Pair<>(ret, null);
}
if (variableName.equals("METRIC")) {
Expr t = (trueBranch == null ? p.getData().getMetric() : trueBranch);
Expr f = (falseBranch == null ? p.getData().getMetric() : falseBranch);
ArithExpr newValue = _enc.mkIf(guard, (ArithExpr) t, (ArithExpr) f);
newValue = _enc.mkIf(r.getReturnAssignedValue(), p.getData().getMetric(), newValue);
ArithExpr ret = createArithVariableWith(p, "METRIC", newValue);
p.getData().setMetric(ret);
return new Pair<>(ret, null);
}
if (variableName.equals("OSPF-TYPE")) {
Expr t = (trueBranch == null ? p.getData().getOspfType().getBitVec() : trueBranch);
Expr f = (falseBranch == null ? p.getData().getOspfType().getBitVec() : falseBranch);
BitVecExpr newValue = _enc.mkIf(guard, (BitVecExpr) t, (BitVecExpr) f);
newValue = _enc.mkIf(r.getReturnAssignedValue(), p.getData().getOspfType().getBitVec(), newValue);
BitVecExpr ret = createBitVecVariableWith(p, "OSPF-TYPE", 2, newValue);
p.getData().getOspfType().setBitVec(ret);
return new Pair<>(ret, null);
}
for (Map.Entry<CommunityVar, BoolExpr> entry : p.getData().getCommunities().entrySet()) {
CommunityVar cvar = entry.getKey();
if (variableName.equals(cvar.getValue())) {
Expr t = (trueBranch == null ? p.getData().getCommunities().get(cvar) : trueBranch);
Expr f = (falseBranch == null ? p.getData().getCommunities().get(cvar) : falseBranch);
BoolExpr newValue = _enc.mkIf(guard, (BoolExpr) t, (BoolExpr) f);
newValue = _enc.mkIf(r.getReturnAssignedValue(), p.getData().getCommunities().get(cvar), newValue);
BoolExpr ret = createBoolVariableWith(p, cvar.getValue(), newValue);
p.getData().getCommunities().put(cvar, ret);
return new Pair<>(ret, null);
}
}
throw new BatfishException("[joinPoint]: unhandled case for " + variableName);
}
use of com.microsoft.z3.BitVecExpr in project batfish by batfish.
the class NodJob method computeSmtInput.
@Override
protected SmtInput computeSmtInput(long startTime, Context ctx) {
NodProgram program = getNodProgram(ctx);
BoolExpr expr = computeSmtConstraintsViaNod(program, _querySynthesizer.getNegate());
Map<String, BitVecExpr> variablesAsConsts = program.getNodContext().getVariablesAsConsts();
return new SmtInput(expr, variablesAsConsts);
}
Aggregations