Search in sources :

Example 6 with ArithExpr

use of com.microsoft.z3.ArithExpr in project batfish by batfish.

the class EncoderSlice method computeValidRange.

/*
   * Convert a set of ranges and a packet field to a symbolic boolean expression
   */
private BoolExpr computeValidRange(Set<SubRange> ranges, ArithExpr field) {
    BoolExpr acc = mkFalse();
    for (SubRange range : ranges) {
        int start = range.getStart();
        int end = range.getEnd();
        if (start == end) {
            BoolExpr val = mkEq(field, mkInt(start));
            acc = mkOr(acc, val);
        } else {
            BoolExpr val1 = mkGe(field, mkInt(start));
            BoolExpr val2 = mkLe(field, mkInt(end));
            acc = mkOr(acc, mkAnd(val1, val2));
        }
    }
    return (BoolExpr) acc.simplify();
}
Also used : BoolExpr(com.microsoft.z3.BoolExpr) SubRange(org.batfish.datamodel.SubRange)

Example 7 with ArithExpr

use of com.microsoft.z3.ArithExpr 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 8 with ArithExpr

use of com.microsoft.z3.ArithExpr in project batfish by batfish.

the class PropertyAdder method recursiveReachability.

/*
   * Generates constraints for reachability through some neighbor.
   * If a router forwards to some neighbor with id label > 0, then the id of this router is
   * greater than that of all next hops. This prevents considering loops and also means that
   * we interpret the router as reachable. If there is no such neighbor, then this router is
   * not reachable and we set the id to 0.
   */
private BoolExpr recursiveReachability(Context ctx, EncoderSlice slice, List<GraphEdge> edges, Map<String, ArithExpr> idVars, String router, ArithExpr id) {
    ArithExpr zero = ctx.mkInt(0);
    BoolExpr hasRecursiveRoute = ctx.mkFalse();
    BoolExpr largerIds = ctx.mkTrue();
    for (GraphEdge edge : edges) {
        if (!edge.isAbstract()) {
            BoolExpr fwd = _encoderSlice.getForwardsAcross().get(router, edge);
            if (edge.getPeer() != null) {
                ArithExpr peerId = idVars.get(edge.getPeer());
                BoolExpr peerReachable = ctx.mkGt(peerId, zero);
                BoolExpr sendToReachable = ctx.mkAnd(fwd, peerReachable);
                hasRecursiveRoute = ctx.mkOr(hasRecursiveRoute, sendToReachable);
                BoolExpr increasingId = ctx.mkImplies(sendToReachable, ctx.mkGt(id, peerId));
                largerIds = ctx.mkAnd(largerIds, increasingId);
            }
        }
    }
    return slice.mkIf(hasRecursiveRoute, largerIds, ctx.mkEq(id, zero));
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) GraphEdge(org.batfish.symbolic.GraphEdge)

Example 9 with ArithExpr

use of com.microsoft.z3.ArithExpr 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 10 with ArithExpr

use of com.microsoft.z3.ArithExpr in project batfish by batfish.

the class PropertyChecker method relateFailures.

private BoolExpr relateFailures(Encoder enc1, Encoder enc2) {
    BoolExpr related = enc1.mkTrue();
    for (GraphEdge ge : enc1.getMainSlice().getGraph().getAllRealEdges()) {
        ArithExpr a1 = enc1.getSymbolicFailures().getFailedVariable(ge);
        ArithExpr a2 = enc2.getSymbolicFailures().getFailedVariable(ge);
        assert a1 != null;
        assert a2 != null;
        related = enc1.mkEq(a1, a2);
    }
    return related;
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) GraphEdge(org.batfish.symbolic.GraphEdge)

Aggregations

ArithExpr (com.microsoft.z3.ArithExpr)27 BoolExpr (com.microsoft.z3.BoolExpr)25 HashMap (java.util.HashMap)12 GraphEdge (org.batfish.symbolic.GraphEdge)10 BitVecExpr (com.microsoft.z3.BitVecExpr)7 Prefix (org.batfish.datamodel.Prefix)6 Graph (org.batfish.symbolic.Graph)6 List (java.util.List)5 Map (java.util.Map)5 Context (com.microsoft.z3.Context)4 Solver (com.microsoft.z3.Solver)4 HashSet (java.util.HashSet)4 Interface (org.batfish.datamodel.Interface)4 CommunityVar (org.batfish.symbolic.CommunityVar)4 Expr (com.microsoft.z3.Expr)3 BatfishException (org.batfish.common.BatfishException)3 SubRange (org.batfish.datamodel.SubRange)3 RoutingPolicy (org.batfish.datamodel.routing_policy.RoutingPolicy)3 BooleanExpr (org.batfish.datamodel.routing_policy.expr.BooleanExpr)3 SmtOneAnswerElement (org.batfish.symbolic.answers.SmtOneAnswerElement)3