Search in sources :

Example 1 with ArithExpr

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

the class Encoder method addFailedConstraints.

/*
   * Adds the constraint that at most k links have failed.
   * This is done in two steps. First we ensure that each link
   * variable is constrained to take on a value between 0 and 1:
   *
   * 0 <= link_i <= 1
   *
   * Then we ensure that the sum of all links is never more than k:
   *
   * link_1 + link_2 + ... + link_n <= k
   */
private void addFailedConstraints(int k) {
    Set<ArithExpr> vars = new HashSet<>();
    getSymbolicFailures().getFailedInternalLinks().forEach((router, peer, var) -> vars.add(var));
    getSymbolicFailures().getFailedEdgeLinks().forEach((ge, var) -> vars.add(var));
    ArithExpr sum = mkInt(0);
    for (ArithExpr var : vars) {
        sum = mkSum(sum, var);
        add(mkGe(var, mkInt(0)));
        add(mkLe(var, mkInt(1)));
    }
    if (k == 0) {
        for (ArithExpr var : vars) {
            add(mkEq(var, mkInt(0)));
        }
    } else {
        add(mkLe(sum, mkInt(k)));
    }
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) HashSet(java.util.HashSet)

Example 2 with ArithExpr

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

the class EncoderSlice method computeIpProtocols.

/*
   * Convert a set of ip protocols to a boolean expression on the symbolic packet
   */
private BoolExpr computeIpProtocols(Set<IpProtocol> ipProtos) {
    BoolExpr acc = mkFalse();
    for (IpProtocol proto : ipProtos) {
        ArithExpr protoNum = mkInt(proto.number());
        acc = mkOr(acc, mkEq(protoNum, _symbolicPacket.getIpProtocol()));
    }
    return (BoolExpr) acc.simplify();
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) IpProtocol(org.batfish.datamodel.IpProtocol)

Example 3 with ArithExpr

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

the class EncoderSlice method addExportConstraint.

/*
   * Creates the transfer function to represent export filters
   * between two symbolic records. The import filter depends
   * heavily on the protocol.
   */
private void addExportConstraint(LogicalEdge e, SymbolicRoute varsOther, @Nullable SymbolicRoute ospfRedistribVars, @Nullable SymbolicRoute overallBest, Configuration conf, Protocol proto, GraphEdge ge, String router, boolean usedExport, Set<Prefix> originations) {
    SymbolicRoute vars = e.getSymbolicRecord();
    Interface iface = ge.getStart();
    ArithExpr failed = getSymbolicFailures().getFailedVariable(e.getEdge());
    assert (failed != null);
    BoolExpr notFailed = mkEq(failed, mkInt(0));
    // only add constraints once when using a single copy of export variables
    if (!_optimizations.getSliceCanKeepSingleExportVar().get(router).get(proto) || !usedExport) {
        if (proto.isConnected()) {
            BoolExpr val = mkNot(vars.getPermitted());
            add(val);
        }
        if (proto.isStatic()) {
            BoolExpr val = mkNot(vars.getPermitted());
            add(val);
        }
        if (proto.isOspf() || proto.isBgp()) {
            // BGP cost based on export
            Integer cost = proto.isBgp() ? addedCost(proto, ge) : 0;
            BoolExpr val = mkNot(vars.getPermitted());
            BoolExpr active = interfaceActive(iface, proto);
            // Apply BGP export policy and cost based on peer type
            // (1) EBGP --> ALL
            // (2) CLIENT --> ALL
            // (3) NONCLIENT --> EBGP, CLIENT
            boolean isNonClientEdge = proto.isBgp() && getGraph().peerType(ge) != Graph.BgpSendType.TO_EBGP;
            boolean isClientEdge = proto.isBgp() && getGraph().peerType(ge) == Graph.BgpSendType.TO_CLIENT;
            boolean isInternalExport = varsOther.isBest() && _optimizations.getNeedBgpInternal().contains(router);
            BoolExpr doExport = mkTrue();
            if (isInternalExport && proto.isBgp() && isNonClientEdge) {
                if (isClientEdge) {
                    cost = 0;
                } else {
                    // Lookup if we learned from iBGP, and if so, don't export the route
                    SymbolicRoute other = getBestNeighborPerProtocol(router, proto);
                    assert other != null;
                    assert other.getBgpInternal() != null;
                    if (other.getBgpInternal() != null) {
                        doExport = mkNot(other.getBgpInternal());
                        cost = 0;
                    }
                }
            }
            BoolExpr acc;
            RoutingPolicy pol = getGraph().findExportRoutingPolicy(router, proto, e.getEdge());
            if (Encoder.ENABLE_DEBUGGING && pol != null) {
                System.out.println("Export policy (" + _sliceName + "," + ge + "): " + pol.getName());
            }
            // We have to wrap this with the right thing for some reason
            List<Statement> statements;
            Statements.StaticStatement s1 = new Statements.StaticStatement(Statements.ExitAccept);
            Statements.StaticStatement s2 = new Statements.StaticStatement(Statements.ExitReject);
            if (proto.isOspf()) {
                If i = new If();
                List<Statement> stmts = (pol == null ? Collections.singletonList(s2) : pol.getStatements());
                i.setTrueStatements(Collections.singletonList(s1));
                i.setFalseStatements(stmts);
                BooleanExpr expr = new MatchProtocol(RoutingProtocol.OSPF);
                i.setGuard(expr);
                statements = Collections.singletonList(i);
            } else {
                statements = (pol == null ? Collections.singletonList(s1) : pol.getStatements());
            }
            TransferSSA f = new TransferSSA(this, conf, varsOther, vars, proto, statements, cost, ge, true);
            acc = f.compute();
            BoolExpr usable = mkAnd(active, doExport, varsOther.getPermitted(), notFailed);
            // will maintain the same preference when adding to the cost.
            if (ospfRedistribVars != null) {
                assert overallBest != null;
                f = new TransferSSA(this, conf, overallBest, ospfRedistribVars, proto, statements, cost, ge, true);
                BoolExpr acc2 = f.compute();
                // System.out.println("ADDING: \n" + acc2.simplify());
                add(acc2);
                BoolExpr usable2 = mkAnd(active, doExport, ospfRedistribVars.getPermitted(), notFailed);
                BoolExpr geq = greaterOrEqual(conf, proto, ospfRedistribVars, varsOther, e);
                BoolExpr isBetter = mkNot(mkAnd(ospfRedistribVars.getPermitted(), geq));
                BoolExpr usesOspf = mkAnd(varsOther.getPermitted(), isBetter);
                BoolExpr eq = equal(conf, proto, ospfRedistribVars, vars, e, false);
                BoolExpr eqPer = mkEq(ospfRedistribVars.getPermitted(), vars.getPermitted());
                acc = mkIf(usesOspf, mkIf(usable, acc, val), mkIf(usable2, mkAnd(eq, eqPer), val));
            } else {
                acc = mkIf(usable, acc, val);
            }
            for (Prefix p : originations) {
                // For OSPF, we need to explicitly initiate a route
                if (proto.isOspf()) {
                    BoolExpr ifaceUp = interfaceActive(iface, proto);
                    BoolExpr relevantPrefix = isRelevantFor(p, _symbolicPacket.getDstIp());
                    BoolExpr relevant = mkAnd(ifaceUp, relevantPrefix);
                    int adminDistance = defaultAdminDistance(conf, proto);
                    int prefixLength = p.getPrefixLength();
                    BoolExpr per = vars.getPermitted();
                    BoolExpr lp = safeEq(vars.getLocalPref(), mkInt(0));
                    BoolExpr ad = safeEq(vars.getAdminDist(), mkInt(adminDistance));
                    BoolExpr met = safeEq(vars.getMetric(), mkInt(cost));
                    BoolExpr med = safeEq(vars.getMed(), mkInt(100));
                    BoolExpr len = safeEq(vars.getPrefixLength(), mkInt(prefixLength));
                    BoolExpr type = safeEqEnum(vars.getOspfType(), OspfType.O);
                    BoolExpr area = safeEqEnum(vars.getOspfArea(), iface.getOspfAreaName());
                    BoolExpr internal = safeEq(vars.getBgpInternal(), mkFalse());
                    BoolExpr igpMet = safeEq(vars.getIgpMetric(), mkInt(0));
                    BoolExpr comms = mkTrue();
                    for (Map.Entry<CommunityVar, BoolExpr> entry : vars.getCommunities().entrySet()) {
                        comms = mkAnd(comms, mkNot(entry.getValue()));
                    }
                    BoolExpr values = mkAnd(per, lp, ad, met, med, len, type, area, internal, igpMet, comms);
                    // Don't originate OSPF route when there is a better redistributed route
                    if (ospfRedistribVars != null) {
                        BoolExpr betterLen = mkGt(ospfRedistribVars.getPrefixLength(), mkInt(prefixLength));
                        BoolExpr equalLen = mkEq(ospfRedistribVars.getPrefixLength(), mkInt(prefixLength));
                        BoolExpr betterAd = mkLt(ospfRedistribVars.getAdminDist(), mkInt(110));
                        BoolExpr better = mkOr(betterLen, mkAnd(equalLen, betterAd));
                        BoolExpr betterRedistributed = mkAnd(ospfRedistribVars.getPermitted(), better);
                        relevant = mkAnd(relevant, mkNot(betterRedistributed));
                    }
                    acc = mkIf(relevant, values, acc);
                }
            }
            add(acc);
            if (Encoder.ENABLE_DEBUGGING) {
                System.out.println("EXPORT: " + router + " " + varsOther.getName() + " " + ge);
                System.out.println(acc.simplify());
                System.out.println("\n\n");
            }
        }
    }
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) Statement(org.batfish.datamodel.routing_policy.statement.Statement) RoutingPolicy(org.batfish.datamodel.routing_policy.RoutingPolicy) Prefix(org.batfish.datamodel.Prefix) MatchProtocol(org.batfish.datamodel.routing_policy.expr.MatchProtocol) CommunityVar(org.batfish.symbolic.CommunityVar) Statements(org.batfish.datamodel.routing_policy.statement.Statements) If(org.batfish.datamodel.routing_policy.statement.If) HashMap(java.util.HashMap) Map(java.util.Map) Interface(org.batfish.datamodel.Interface) BooleanExpr(org.batfish.datamodel.routing_policy.expr.BooleanExpr)

Example 4 with ArithExpr

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

the class EncoderSlice method addBoundConstraints.

/*
   * Constraint each variable to fall within a valid range.
   * Metric cost is protocol dependent and need not have an
   * upper bound, since overflow is modeled.
   *
   * dstIp, srcIp:        [0,2^32)
   * dstPort, srcPort:    [0,2^16)
   * icmpType, protocol:  [0,2^8)
   * icmpCode:            [0,2^4)
   *
   * prefix length:       [0,2^32)
   * admin distance:      [0,2^8)
   * BGP med, local-pref: [0,2^32)
   * metric cost:         [0,2^8) if environment
   * metric cost:         [0,2^16) otherwise
   */
private void addBoundConstraints() {
    ArithExpr upperBound4 = mkInt((long) Math.pow(2, 4));
    ArithExpr upperBound8 = mkInt((long) Math.pow(2, 8));
    ArithExpr upperBound16 = mkInt((long) Math.pow(2, 16));
    ArithExpr upperBound32 = mkInt((long) Math.pow(2, 32));
    ArithExpr zero = mkInt(0);
    // Valid 16 bit integer
    add(mkGe(_symbolicPacket.getDstPort(), zero));
    add(mkGe(_symbolicPacket.getSrcPort(), zero));
    add(mkLt(_symbolicPacket.getDstPort(), upperBound16));
    add(mkLt(_symbolicPacket.getSrcPort(), upperBound16));
    // Valid 8 bit integer
    add(mkGe(_symbolicPacket.getIcmpType(), zero));
    add(mkGe(_symbolicPacket.getIpProtocol(), zero));
    add(mkLt(_symbolicPacket.getIcmpType(), upperBound8));
    add(mkLe(_symbolicPacket.getIpProtocol(), upperBound8));
    // Valid 4 bit integer
    add(mkGe(_symbolicPacket.getIcmpCode(), zero));
    add(mkLt(_symbolicPacket.getIcmpCode(), upperBound4));
    for (SymbolicRoute e : getAllSymbolicRecords()) {
        if (e.getRouterId() != null) {
            add(mkGe(e.getRouterId(), zero));
        }
        if (e.getAdminDist() != null) {
            add(mkGe(e.getAdminDist(), zero));
            add(mkLt(e.getAdminDist(), upperBound8));
        }
        if (e.getMed() != null) {
            add(mkGe(e.getMed(), zero));
            add(mkLt(e.getMed(), upperBound32));
        }
        if (e.getLocalPref() != null) {
            add(mkGe(e.getLocalPref(), zero));
            add(mkLt(e.getLocalPref(), upperBound32));
        }
        if (e.getMetric() != null) {
            add(mkGe(e.getMetric(), zero));
            if (e.isEnv()) {
                add(mkLt(e.getMetric(), upperBound8));
            }
            add(mkLt(e.getMetric(), upperBound16));
        }
        if (e.getIgpMetric() != null) {
            add(mkGe(e.getIgpMetric(), zero));
        }
        if (e.getPrefixLength() != null) {
            add(mkGe(e.getPrefixLength(), zero));
            add(mkLe(e.getPrefixLength(), mkInt(32)));
        }
    }
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr)

Example 5 with ArithExpr

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

the class EncoderSlice method addImportConstraint.

/*
   * Creates the transfer function to represent import filters
   * between two symbolic records. The import filter depends
   * heavily on the protocol.
   */
private void addImportConstraint(LogicalEdge e, SymbolicRoute varsOther, Configuration conf, Protocol proto, GraphEdge ge, String router) {
    SymbolicRoute vars = e.getSymbolicRecord();
    Interface iface = ge.getStart();
    ArithExpr failed = getSymbolicFailures().getFailedVariable(e.getEdge());
    assert (failed != null);
    BoolExpr notFailed = mkEq(failed, mkInt(0));
    if (vars.getIsUsed()) {
        if (proto.isConnected()) {
            Prefix p = iface.getAddress().getPrefix();
            BoolExpr relevant = mkAnd(interfaceActive(iface, proto), isRelevantFor(p, _symbolicPacket.getDstIp()), notFailed);
            BoolExpr per = vars.getPermitted();
            BoolExpr len = safeEq(vars.getPrefixLength(), mkInt(p.getPrefixLength()));
            BoolExpr ad = safeEq(vars.getAdminDist(), mkInt(1));
            BoolExpr lp = safeEq(vars.getLocalPref(), mkInt(0));
            BoolExpr met = safeEq(vars.getMetric(), mkInt(0));
            BoolExpr values = mkAnd(per, len, ad, lp, met);
            add(mkIf(relevant, values, mkNot(vars.getPermitted())));
        }
        if (proto.isStatic()) {
            List<StaticRoute> srs = getGraph().getStaticRoutes().get(router, iface.getName());
            assert (srs != null);
            BoolExpr acc = mkNot(vars.getPermitted());
            for (StaticRoute sr : srs) {
                Prefix p = sr.getNetwork();
                BoolExpr relevant = mkAnd(interfaceActive(iface, proto), isRelevantFor(p, _symbolicPacket.getDstIp()), notFailed);
                BoolExpr per = vars.getPermitted();
                BoolExpr len = safeEq(vars.getPrefixLength(), mkInt(p.getPrefixLength()));
                BoolExpr ad = safeEq(vars.getAdminDist(), mkInt(sr.getAdministrativeCost()));
                BoolExpr lp = safeEq(vars.getLocalPref(), mkInt(0));
                BoolExpr met = safeEq(vars.getMetric(), mkInt(0));
                BoolExpr values = mkAnd(per, len, ad, lp, met);
                acc = mkIf(relevant, values, acc);
            }
            add(acc);
        }
        if (proto.isOspf() || proto.isBgp()) {
            BoolExpr val = mkNot(vars.getPermitted());
            if (varsOther != null) {
                // BoolExpr isRoot = relevantOrigination(originations);
                BoolExpr active = interfaceActive(iface, proto);
                // Handle iBGP by checking reachability to the next hop to send messages
                boolean isNonClient = (proto.isBgp()) && (getGraph().peerType(ge) != Graph.BgpSendType.TO_EBGP);
                boolean isClient = (proto.isBgp()) && (getGraph().peerType(ge) == Graph.BgpSendType.TO_RR);
                BoolExpr receiveMessage;
                String currentRouter = ge.getRouter();
                String peerRouter = ge.getPeer();
                if (_encoder.getModelIgp() && isNonClient) {
                    // Lookup reachabilty based on peer next-hop
                    receiveMessage = _encoder.getSliceReachability().get(currentRouter).get(peerRouter);
                /* EncoderSlice peerSlice = _encoder.getSlice(peerRouter);
            BoolExpr srcPort = mkEq(peerSlice.getSymbolicPacket().getSrcPort(), mkInt(179));
            BoolExpr srcIp = mkEq(peerSlice.getSymbolicPacket().getSrcIp(), mkInt(0));
            BoolExpr tcpAck = mkEq(peerSlice.getSymbolicPacket().getTcpAck(), mkFalse());
            BoolExpr tcpCwr = mkEq(peerSlice.getSymbolicPacket().getTcpCwr(), mkFalse());
            BoolExpr tcpEce = mkEq(peerSlice.getSymbolicPacket().getTcpEce(), mkFalse());
            BoolExpr tcpFin = mkEq(peerSlice.getSymbolicPacket().getTcpFin(), mkFalse());
            BoolExpr tcpPsh = mkEq(peerSlice.getSymbolicPacket().getTcpPsh(), mkFalse());
            BoolExpr tcpRst = mkEq(peerSlice.getSymbolicPacket().getTcpRst(), mkFalse());
            BoolExpr tcpSyn = mkEq(peerSlice.getSymbolicPacket().getTcpSyn(), mkFalse());
            BoolExpr tcpUrg = mkEq(peerSlice.getSymbolicPacket().getTcpUrg(), mkFalse());
            BoolExpr icmpCode = mkEq(peerSlice.getSymbolicPacket().getIcmpCode(), mkInt(0));
            BoolExpr icmpType = mkEq(peerSlice.getSymbolicPacket().getIcmpType(), mkInt(0));
            BoolExpr all =
                mkAnd(srcPort, srcIp, tcpAck,
                    tcpCwr, tcpEce, tcpFin, tcpPsh, tcpRst, tcpSyn, tcpUrg, icmpCode, icmpType);
            receiveMessage = mkImplies(all, receiveMessage); */
                } else if (_encoder.getModelIgp() && isClient) {
                    // Lookup reachability based on client id tag to find next hop
                    BoolExpr acc = mkTrue();
                    for (Map.Entry<String, Integer> entry : getGraph().getOriginatorId().entrySet()) {
                        String r = entry.getKey();
                        Integer id = entry.getValue();
                        if (!r.equals(currentRouter)) {
                            BoolExpr reach = _encoder.getSliceReachability().get(currentRouter).get(r);
                            /* EncoderSlice peerSlice = _encoder.getSlice(r);
                BoolExpr srcPort = mkEq(peerSlice.getSymbolicPacket().getSrcPort(), mkInt(179));
                BoolExpr srcIp = mkEq(peerSlice.getSymbolicPacket().getSrcIp(), mkInt(0));
                BoolExpr tcpAck = mkEq(peerSlice.getSymbolicPacket().getTcpAck(), mkFalse());
                BoolExpr tcpCwr = mkEq(peerSlice.getSymbolicPacket().getTcpCwr(), mkFalse());
                BoolExpr tcpEce = mkEq(peerSlice.getSymbolicPacket().getTcpEce(), mkFalse());
                BoolExpr tcpFin = mkEq(peerSlice.getSymbolicPacket().getTcpFin(), mkFalse());
                BoolExpr tcpPsh = mkEq(peerSlice.getSymbolicPacket().getTcpPsh(), mkFalse());
                BoolExpr tcpRst = mkEq(peerSlice.getSymbolicPacket().getTcpRst(), mkFalse());
                BoolExpr tcpSyn = mkEq(peerSlice.getSymbolicPacket().getTcpSyn(), mkFalse());
                BoolExpr tcpUrg = mkEq(peerSlice.getSymbolicPacket().getTcpUrg(), mkFalse());
                BoolExpr icmpCode = mkEq(peerSlice.getSymbolicPacket().getIcmpCode(), mkInt(0));
                BoolExpr icmpType = mkEq(peerSlice.getSymbolicPacket().getIcmpType(), mkInt(0));
                BoolExpr all =
                    mkAnd(srcPort, srcIp, tcpAck,
                        tcpCwr, tcpEce, tcpFin, tcpPsh, tcpRst, tcpSyn, tcpUrg, icmpCode, icmpType);
                reach = mkImplies(all, reach); */
                            acc = mkAnd(acc, mkImplies(varsOther.getClientId().checkIfValue(id), reach));
                        }
                    }
                    receiveMessage = acc;
                // Just check if the link is failed
                } else {
                    receiveMessage = notFailed;
                }
                // Take into account BGP loop prevention
                // The path length will prevent any isolated loops
                BoolExpr loop = mkFalse();
                if (proto.isBgp() && ge.getPeer() != null) {
                    String peer = ge.getPeer();
                    GraphEdge gePeer = getGraph().getOtherEnd().get(ge);
                    loop = getSymbolicDecisions().getControlForwarding().get(peer, gePeer);
                }
                assert (loop != null);
                BoolExpr usable = mkAnd(mkNot(loop), active, varsOther.getPermitted(), receiveMessage);
                BoolExpr importFunction;
                RoutingPolicy pol = getGraph().findImportRoutingPolicy(router, proto, e.getEdge());
                if (Encoder.ENABLE_DEBUGGING && pol != null) {
                    System.out.println("Import Policy: " + pol.getName());
                }
                List<Statement> statements;
                if (pol == null) {
                    Statements.StaticStatement s = new Statements.StaticStatement(Statements.ExitAccept);
                    statements = Collections.singletonList(s);
                } else {
                    statements = pol.getStatements();
                }
                // OSPF cost calculated based on incoming interface
                Integer cost = proto.isOspf() ? addedCost(proto, ge) : 0;
                TransferSSA f = new TransferSSA(this, conf, varsOther, vars, proto, statements, cost, ge, false);
                importFunction = f.compute();
                BoolExpr acc = mkIf(usable, importFunction, val);
                if (Encoder.ENABLE_DEBUGGING) {
                    System.out.println("IMPORT FUNCTION: " + router + " " + varsOther.getName());
                    System.out.println(importFunction.simplify());
                    System.out.println("\n\n");
                }
                add(acc);
            } else {
                add(val);
            }
        }
    }
}
Also used : ArithExpr(com.microsoft.z3.ArithExpr) BoolExpr(com.microsoft.z3.BoolExpr) StaticRoute(org.batfish.datamodel.StaticRoute) Statement(org.batfish.datamodel.routing_policy.statement.Statement) RoutingPolicy(org.batfish.datamodel.routing_policy.RoutingPolicy) Prefix(org.batfish.datamodel.Prefix) Entry(java.util.Map.Entry) Statements(org.batfish.datamodel.routing_policy.statement.Statements) GraphEdge(org.batfish.symbolic.GraphEdge) Interface(org.batfish.datamodel.Interface)

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