Search in sources :

Example 1 with Graph

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

the class AbstractionBuilder method computeAbstraction.

/*
   * Create an abstract network that is forwarding-equivalent to the original
   * network for a given destination-based slice of the original network.
   */
private NetworkSlice computeAbstraction() {
    _exportPol = new HashMap<>();
    _importPol = new HashMap<>();
    if (_prefixes == null) {
        _exportPol = _network.getExportPolicyMap();
        _importPol = _network.getImportPolicyMap();
    } else {
        specialize(false);
    }
    _abstractGroups = new UnionSplit<>(_graph.getRouters());
    // Each origination point will remain concrete
    for (String device : _destinations) {
        _abstractGroups.split(device);
    }
    // Repeatedly split the abstraction to a fixed point
    Set<Set<String>> todo;
    do {
        todo = new HashSet<>();
        _eeMap.clear();
        _polMap.clear();
        Collection<Set<String>> ps = _abstractGroups.partitions();
        for (Set<String> partition : ps) {
            // Nothing to refine if already a concrete node
            if (partition.size() <= 1) {
                continue;
            }
            if (needUniversalAbstraction()) {
                refineAbstraction(todo, ps, partition, false, true);
            } else if (_possibleFailures > 0) {
                refineAbstraction(todo, ps, partition, true, false);
            } else {
                refineAbstraction(todo, ps, partition, false, false);
            }
        // If something changed, then start over early
        // Helps the next iteration to use the newly reflected information.
        // if (todo.size() > 0) {
        // break;
        // }
        }
        // Now refine the abstraction further
        for (Set<String> newPartition : todo) {
            _abstractGroups.split(newPartition);
        }
    } while (!todo.isEmpty());
    // System.out.println("EC Devices: " + _destinations);
    // System.out.println("EC Prefixes: " + _prefixes);
    // System.out.println("Groups: \n" + _abstractGroups.partitions());
    // System.out.println("New graph: \n" + abstractGraph);
    // System.out.println("Num Groups: " + workset.partitions().size());
    Tuple<Graph, AbstractionMap> abstractNetwork = createAbstractNetwork();
    Graph abstractGraph = abstractNetwork.getFirst();
    AbstractionMap abstractionMap = abstractNetwork.getSecond();
    // System.out.println("Num configs: " + abstractGraph.getConfigurations().size());
    Abstraction a = new Abstraction(abstractGraph, abstractionMap);
    return new NetworkSlice(_headerspace, a, _isDefaultCase);
}
Also used : SortedSet(java.util.SortedSet) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Set(java.util.Set) Graph(org.batfish.symbolic.Graph)

Example 2 with Graph

use of org.batfish.symbolic.Graph 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 3 with Graph

use of org.batfish.symbolic.Graph 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 4 with Graph

use of org.batfish.symbolic.Graph 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 5 with Graph

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

the class PropertyAdder method instrumentLoop.

/*
   * Instruments the network to check if a router will be part
   * of a routing loop.
   */
BoolExpr instrumentLoop(String router) {
    Context ctx = _encoderSlice.getCtx();
    Solver solver = _encoderSlice.getSolver();
    String sliceName = _encoderSlice.getSliceName();
    // Add on-loop variables to track a loop
    Map<String, BoolExpr> onLoop = new HashMap<>();
    Graph graph = _encoderSlice.getGraph();
    for (String r : graph.getRouters()) {
        String name = _encoderSlice.getEncoder().getId() + "_" + sliceName + "_on-loop_" + router + "_" + r;
        BoolExpr var = ctx.mkBoolConst(name);
        onLoop.put(r, var);
        _encoderSlice.getAllVariables().put(var.toString(), var);
    }
    for (Entry<String, List<GraphEdge>> entry : graph.getEdgeMap().entrySet()) {
        String r = entry.getKey();
        List<GraphEdge> edges = entry.getValue();
        BoolExpr var = onLoop.get(r);
        BoolExpr acc = ctx.mkBool(false);
        for (GraphEdge edge : edges) {
            if (!edge.isAbstract()) {
                BoolExpr fwd = _encoderSlice.getForwardsAcross().get(r, edge);
                String peer = edge.getPeer();
                if (peer != null) {
                    if (peer.equals(router)) {
                        // If next hop is static route router, then on loop
                        acc = ctx.mkOr(acc, fwd);
                    } else {
                        // Otherwise check if next hop also is on the loop
                        BoolExpr peerOnLoop = onLoop.get(peer);
                        acc = ctx.mkOr(acc, ctx.mkAnd(fwd, peerOnLoop));
                    }
                }
            }
        }
        solver.add(ctx.mkEq(var, acc));
    }
    return onLoop.get(router);
}
Also used : Context(com.microsoft.z3.Context) BoolExpr(com.microsoft.z3.BoolExpr) Solver(com.microsoft.z3.Solver) Graph(org.batfish.symbolic.Graph) HashMap(java.util.HashMap) List(java.util.List) GraphEdge(org.batfish.symbolic.GraphEdge)

Aggregations

Graph (org.batfish.symbolic.Graph)19 GraphEdge (org.batfish.symbolic.GraphEdge)13 BoolExpr (com.microsoft.z3.BoolExpr)12 HashMap (java.util.HashMap)10 Context (com.microsoft.z3.Context)8 List (java.util.List)6 TreeSet (java.util.TreeSet)6 ArithExpr (com.microsoft.z3.ArithExpr)5 Solver (com.microsoft.z3.Solver)5 ArrayList (java.util.ArrayList)5 HashSet (java.util.HashSet)5 BatfishException (org.batfish.common.BatfishException)5 SmtOneAnswerElement (org.batfish.symbolic.answers.SmtOneAnswerElement)5 Map (java.util.Map)4 Configuration (org.batfish.datamodel.Configuration)4 BitVecExpr (com.microsoft.z3.BitVecExpr)3 EnumMap (java.util.EnumMap)3 Set (java.util.Set)3 SortedMap (java.util.SortedMap)3 TreeMap (java.util.TreeMap)3