Search in sources :

Example 1 with BitVecExpr

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));
}
Also used : BitVecExpr(com.microsoft.z3.BitVecExpr)

Example 2 with BitVecExpr

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;
}
Also used : Context(com.microsoft.z3.Context) ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) Solver(com.microsoft.z3.Solver) HashMap(java.util.HashMap) BitVecExpr(com.microsoft.z3.BitVecExpr) Graph(org.batfish.symbolic.Graph) List(java.util.List) GraphEdge(org.batfish.symbolic.GraphEdge)

Example 3 with BitVecExpr

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;
}
Also used : Context(com.microsoft.z3.Context) ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) Solver(com.microsoft.z3.Solver) HashMap(java.util.HashMap) BitVecExpr(com.microsoft.z3.BitVecExpr) Graph(org.batfish.symbolic.Graph) List(java.util.List) GraphEdge(org.batfish.symbolic.GraphEdge)

Example 4 with BitVecExpr

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);
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) CommunityVar(org.batfish.symbolic.CommunityVar) BoolExpr(com.microsoft.z3.BoolExpr) BatfishException(org.batfish.common.BatfishException) BitVecExpr(com.microsoft.z3.BitVecExpr) IntExpr(org.batfish.datamodel.routing_policy.expr.IntExpr) CommunitySetExpr(org.batfish.datamodel.routing_policy.expr.CommunitySetExpr) CallExpr(org.batfish.datamodel.routing_policy.expr.CallExpr) BooleanExpr(org.batfish.datamodel.routing_policy.expr.BooleanExpr) AsPathListExpr(org.batfish.datamodel.routing_policy.expr.AsPathListExpr) BoolExpr(com.microsoft.z3.BoolExpr) ArithExpr(com.microsoft.z3.ArithExpr) WithEnvironmentExpr(org.batfish.datamodel.routing_policy.expr.WithEnvironmentExpr) PrefixSetExpr(org.batfish.datamodel.routing_policy.expr.PrefixSetExpr) BitVecExpr(com.microsoft.z3.BitVecExpr) Expr(com.microsoft.z3.Expr) LongExpr(org.batfish.datamodel.routing_policy.expr.LongExpr) Map(java.util.Map) HashMap(java.util.HashMap) Pair(org.batfish.common.Pair)

Example 5 with BitVecExpr

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);
}
Also used : BoolExpr(com.microsoft.z3.BoolExpr) BitVecExpr(com.microsoft.z3.BitVecExpr)

Aggregations

BitVecExpr (com.microsoft.z3.BitVecExpr)15 BoolExpr (com.microsoft.z3.BoolExpr)11 ArithExpr (com.microsoft.z3.ArithExpr)6 HashMap (java.util.HashMap)6 List (java.util.List)6 GraphEdge (org.batfish.symbolic.GraphEdge)5 Context (com.microsoft.z3.Context)4 Solver (com.microsoft.z3.Solver)4 Map (java.util.Map)4 BatfishException (org.batfish.common.BatfishException)4 Graph (org.batfish.symbolic.Graph)4 Expr (com.microsoft.z3.Expr)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 Pair (org.batfish.common.Pair)2 Configuration (org.batfish.datamodel.Configuration)2 Ip (org.batfish.datamodel.Ip)2 IpProtocol (org.batfish.datamodel.IpProtocol)2 AsPathListExpr (org.batfish.datamodel.routing_policy.expr.AsPathListExpr)2