Search in sources :

Example 11 with GraphEdge

use of org.batfish.symbolic.GraphEdge in project batfish by batfish.

the class EncoderSlice method initAclFunctions.

/*
   * Initialize boolean expressions to represent ACLs on each interface.
   */
private void initAclFunctions() {
    for (Entry<String, List<GraphEdge>> entry : getGraph().getEdgeMap().entrySet()) {
        String router = entry.getKey();
        List<GraphEdge> edges = entry.getValue();
        for (GraphEdge ge : edges) {
            Interface i = ge.getStart();
            IpAccessList outbound = i.getOutgoingFilter();
            if (outbound != null) {
                String outName = String.format("%d_%s_%s_%s_%s_%s", _encoder.getId(), _sliceName, router, i.getName(), "OUTBOUND", outbound.getName());
                BoolExpr outAcl = getCtx().mkBoolConst(outName);
                BoolExpr outAclFunc = computeACL(outbound);
                add(mkEq(outAcl, outAclFunc));
                _outboundAcls.put(ge, outAcl);
            }
            IpAccessList inbound = i.getIncomingFilter();
            if (inbound != null) {
                String inName = String.format("%d_%s_%s_%s_%s_%s", _encoder.getId(), _sliceName, router, i.getName(), "INBOUND", inbound.getName());
                BoolExpr inAcl = getCtx().mkBoolConst(inName);
                BoolExpr inAclFunc = computeACL(inbound);
                add(mkEq(inAcl, inAclFunc));
                _inboundAcls.put(ge, inAcl);
            }
        }
    }
}
Also used : BoolExpr(com.microsoft.z3.BoolExpr) IpAccessList(org.batfish.datamodel.IpAccessList) ArrayList(java.util.ArrayList) List(java.util.List) IpAccessList(org.batfish.datamodel.IpAccessList) GraphEdge(org.batfish.symbolic.GraphEdge) Interface(org.batfish.datamodel.Interface)

Example 12 with GraphEdge

use of org.batfish.symbolic.GraphEdge in project batfish by batfish.

the class Optimizations method computeCanMergeExportVars.

/*
   * Determines when we can merge export variables into a single copy.
   * This will be safe when there is no peer-specific export filter.
   */
private void computeCanMergeExportVars() {
    Graph g = _encoderSlice.getGraph();
    HeaderQuestion q = _encoderSlice.getEncoder().getQuestion();
    boolean noFailures = q.getFailures() == 0;
    _encoderSlice.getGraph().getConfigurations().forEach((router, conf) -> {
        HashMap<Protocol, Boolean> map = new HashMap<>();
        _sliceCanKeepSingleExportVar.put(router, map);
        // the neighbor already being the root of the tree.
        for (Protocol proto : getProtocols().get(router)) {
            if (proto.isConnected() || proto.isStatic()) {
                map.put(proto, noFailures && Optimizations.ENABLE_EXPORT_MERGE_OPTIMIZATION);
            } else if (proto.isOspf()) {
                // Ensure all interfaces are active
                boolean allIfacesActive = true;
                for (GraphEdge edge : g.getEdgeMap().get(router)) {
                    if (g.isEdgeUsed(conf, proto, edge)) {
                        Interface iface = edge.getStart();
                        allIfacesActive = allIfacesActive && g.isInterfaceActive(proto, iface);
                    }
                }
                // Ensure single area for this router
                Set<Long> areas = _encoderSlice.getGraph().getAreaIds().get(router);
                boolean singleArea = areas.size() <= 1;
                map.put(proto, noFailures && allIfacesActive && singleArea && ENABLE_EXPORT_MERGE_OPTIMIZATION);
            } else if (proto.isBgp()) {
                boolean acc = true;
                BgpProcess p = conf.getDefaultVrf().getBgpProcess();
                for (Map.Entry<Prefix, BgpNeighbor> e : p.getNeighbors().entrySet()) {
                    BgpNeighbor n = e.getValue();
                    // If iBGP used, then don't merge
                    if (n.getLocalAs().equals(n.getRemoteAs())) {
                        acc = false;
                        break;
                    }
                    // If not the default export policy, then don't merge
                    if (!isDefaultBgpExport(conf, n)) {
                        acc = false;
                        break;
                    }
                }
                map.put(proto, noFailures && acc && ENABLE_EXPORT_MERGE_OPTIMIZATION);
            } else {
                throw new BatfishException("Error: unkown protocol: " + proto.name());
            }
        }
    });
}
Also used : BatfishException(org.batfish.common.BatfishException) HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) BgpProcess(org.batfish.datamodel.BgpProcess) Prefix(org.batfish.datamodel.Prefix) BgpNeighbor(org.batfish.datamodel.BgpNeighbor) Graph(org.batfish.symbolic.Graph) HeaderQuestion(org.batfish.datamodel.questions.smt.HeaderQuestion) Protocol(org.batfish.symbolic.Protocol) GraphEdge(org.batfish.symbolic.GraphEdge) HashMap(java.util.HashMap) Map(java.util.Map) Interface(org.batfish.datamodel.Interface)

Example 13 with GraphEdge

use of org.batfish.symbolic.GraphEdge 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 14 with GraphEdge

use of org.batfish.symbolic.GraphEdge 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 15 with GraphEdge

use of org.batfish.symbolic.GraphEdge 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)

Aggregations

GraphEdge (org.batfish.symbolic.GraphEdge)47 BoolExpr (com.microsoft.z3.BoolExpr)23 HashMap (java.util.HashMap)19 ArrayList (java.util.ArrayList)16 List (java.util.List)16 Graph (org.batfish.symbolic.Graph)14 TreeSet (java.util.TreeSet)13 Prefix (org.batfish.datamodel.Prefix)12 ArithExpr (com.microsoft.z3.ArithExpr)10 Configuration (org.batfish.datamodel.Configuration)10 Protocol (org.batfish.symbolic.Protocol)10 HashSet (java.util.HashSet)8 Interface (org.batfish.datamodel.Interface)8 Context (com.microsoft.z3.Context)7 Map (java.util.Map)7 Ip (org.batfish.datamodel.Ip)7 IpAccessList (org.batfish.datamodel.IpAccessList)7 TreeMap (java.util.TreeMap)6 IpProtocol (org.batfish.datamodel.IpProtocol)6 BitVecExpr (com.microsoft.z3.BitVecExpr)5