use of org.batfish.symbolic.CommunityVar in project batfish by batfish.
the class Encoder method environmentBlockingClause.
/*
* Generate a blocking clause for the encoding that says that one
* of the environments that was true before must now be false.
*/
private BoolExpr environmentBlockingClause(Model m) {
BoolExpr acc1 = mkFalse();
BoolExpr acc2 = mkTrue();
// Disable an environment edge if possible
Map<LogicalEdge, SymbolicRoute> map = getMainSlice().getLogicalGraph().getEnvironmentVars();
for (Map.Entry<LogicalEdge, SymbolicRoute> entry : map.entrySet()) {
SymbolicRoute record = entry.getValue();
BoolExpr per = record.getPermitted();
Expr x = m.evaluate(per, false);
if (x.toString().equals("true")) {
acc1 = mkOr(acc1, mkNot(per));
} else {
acc2 = mkAnd(acc2, mkNot(per));
}
}
// Disable a community value if possible
for (Map.Entry<LogicalEdge, SymbolicRoute> entry : map.entrySet()) {
SymbolicRoute record = entry.getValue();
for (Map.Entry<CommunityVar, BoolExpr> centry : record.getCommunities().entrySet()) {
BoolExpr comm = centry.getValue();
Expr x = m.evaluate(comm, false);
if (x.toString().equals("true")) {
acc1 = mkOr(acc1, mkNot(comm));
} else {
acc2 = mkAnd(acc2, mkNot(comm));
}
}
}
return mkAnd(acc1, acc2);
}
use of org.batfish.symbolic.CommunityVar in project batfish by batfish.
the class EncoderSlice method equalCommunities.
private BoolExpr equalCommunities(SymbolicRoute best, SymbolicRoute vars) {
BoolExpr acc = mkTrue();
for (Map.Entry<CommunityVar, BoolExpr> entry : best.getCommunities().entrySet()) {
CommunityVar cvar = entry.getKey();
BoolExpr var = entry.getValue();
BoolExpr other = vars.getCommunities().get(cvar);
if (other == null) {
acc = mkAnd(acc, mkNot(var));
} else {
acc = mkAnd(acc, mkEq(var, other));
}
}
return acc;
}
use of org.batfish.symbolic.CommunityVar 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");
}
}
}
}
use of org.batfish.symbolic.CommunityVar in project batfish by batfish.
the class TransferBDD method matchCommunityList.
/*
* Converts a community list to a boolean expression.
*/
private BDD matchCommunityList(TransferParam<BDDRoute> p, CommunityList cl, BDDRoute other) {
List<CommunityListLine> lines = new ArrayList<>(cl.getLines());
Collections.reverse(lines);
BDD acc = factory.zero();
for (CommunityListLine line : lines) {
boolean action = (line.getAction() == LineAction.ACCEPT);
CommunityVar cvar = new CommunityVar(CommunityVar.Type.REGEX, line.getRegex(), null);
p.debug("Match Line: " + cvar);
p.debug("Action: " + line.getAction());
// Skip this match if it is irrelevant
if (_policyQuotient.getCommsMatchedButNotAssigned().contains(cvar)) {
continue;
}
List<CommunityVar> deps = _commDeps.get(cvar);
for (CommunityVar dep : deps) {
p.debug("Test for: " + dep);
BDD c = other.getCommunities().get(dep);
acc = ite(c, mkBDD(action), acc);
}
}
return acc;
}
use of org.batfish.symbolic.CommunityVar in project batfish by batfish.
the class TransferBDD method compute.
/*
* Convert a list of statements into a Z3 boolean expression for the transfer function.
*/
private TransferResult<TransferReturn, BDD> compute(List<Statement> statements, TransferParam<BDDRoute> p) {
boolean doesReturn = false;
TransferResult<TransferReturn, BDD> result = new TransferResult<>();
result = result.setReturnValue(new TransferReturn(p.getData(), factory.zero())).setFallthroughValue(factory.zero()).setReturnAssignedValue(factory.zero());
for (Statement stmt : statements) {
if (stmt instanceof StaticStatement) {
StaticStatement ss = (StaticStatement) stmt;
switch(ss.getType()) {
case ExitAccept:
doesReturn = true;
p.debug("ExitAccept");
result = returnValue(result, true);
break;
case ReturnTrue:
doesReturn = true;
p.debug("ReturnTrue");
result = returnValue(result, true);
break;
case ExitReject:
doesReturn = true;
p.debug("ExitReject");
result = returnValue(result, false);
break;
case ReturnFalse:
doesReturn = true;
p.debug("ReturnFalse");
result = returnValue(result, false);
break;
case SetDefaultActionAccept:
p.debug("SetDefaulActionAccept");
p = p.setDefaultAccept(true);
break;
case SetDefaultActionReject:
p.debug("SetDefaultActionReject");
p = p.setDefaultAccept(false);
break;
case SetLocalDefaultActionAccept:
p.debug("SetLocalDefaultActionAccept");
p = p.setDefaultAcceptLocal(true);
break;
case SetLocalDefaultActionReject:
p.debug("SetLocalDefaultActionReject");
p = p.setDefaultAcceptLocal(false);
break;
case ReturnLocalDefaultAction:
p.debug("ReturnLocalDefaultAction");
// TODO: need to set local default action in an environment
if (p.getDefaultAcceptLocal()) {
result = returnValue(result, true);
} else {
result = returnValue(result, false);
}
break;
case FallThrough:
p.debug("Fallthrough");
result = fallthrough(result);
break;
case Return:
// TODO: assumming this happens at the end of the function, so it is ignored for now.
p.debug("Return");
break;
case RemovePrivateAs:
p.debug("RemovePrivateAs");
// System.out.println("Warning: use of unimplemented feature RemovePrivateAs");
break;
default:
throw new BatfishException("TODO: computeTransferFunction: " + ss.getType());
}
} else if (stmt instanceof If) {
p.debug("If");
If i = (If) stmt;
TransferResult<TransferReturn, BDD> r = compute(i.getGuard(), p.indent());
BDD guard = r.getReturnValue().getSecond();
p.debug("guard: ");
BDDRoute current = result.getReturnValue().getFirst();
TransferParam<BDDRoute> pTrue = p.indent().setData(current.deepCopy());
TransferParam<BDDRoute> pFalse = p.indent().setData(current.deepCopy());
p.debug("True Branch");
TransferResult<TransferReturn, BDD> trueBranch = compute(i.getTrueStatements(), pTrue);
p.debug("True Branch: " + trueBranch.getReturnValue().getFirst().hashCode());
p.debug("False Branch");
TransferResult<TransferReturn, BDD> falseBranch = compute(i.getFalseStatements(), pFalse);
p.debug("False Branch: " + trueBranch.getReturnValue().getFirst().hashCode());
BDDRoute r1 = trueBranch.getReturnValue().getFirst();
BDDRoute r2 = falseBranch.getReturnValue().getFirst();
BDDRoute recordVal = ite(guard, r1, r2);
// update return values
BDD returnVal = ite(guard, trueBranch.getReturnValue().getSecond(), falseBranch.getReturnValue().getSecond());
// p.debug("New Return Value (neg): " + returnVal.not());
BDD returnAss = ite(guard, trueBranch.getReturnAssignedValue(), falseBranch.getReturnAssignedValue());
// p.debug("New Return Assigned: " + returnAss);
BDD fallThrough = ite(guard, trueBranch.getFallthroughValue(), falseBranch.getFallthroughValue());
// p.debug("New fallthrough: " + fallThrough);
result = result.setReturnValue(new TransferReturn(recordVal, returnVal)).setReturnAssignedValue(returnAss).setFallthroughValue(fallThrough);
p.debug("If return: " + result.getReturnValue().getFirst().hashCode());
} else if (stmt instanceof SetDefaultPolicy) {
p.debug("SetDefaultPolicy");
p = p.setDefaultPolicy((SetDefaultPolicy) stmt);
} else if (stmt instanceof SetMetric) {
p.debug("SetMetric");
SetMetric sm = (SetMetric) stmt;
LongExpr ie = sm.getMetric();
BDD isBGP = p.getData().getProtocolHistory().value(Protocol.BGP);
BDD updateMed = isBGP.and(result.getReturnAssignedValue());
BDD updateMet = isBGP.not().and(result.getReturnAssignedValue());
BDDInteger newValue = applyLongExprModification(p.indent(), p.getData().getMetric(), ie);
BDDInteger med = ite(updateMed, p.getData().getMed(), newValue);
BDDInteger met = ite(updateMet, p.getData().getMetric(), newValue);
p.getData().setMetric(met);
p.getData().setMetric(med);
} else if (stmt instanceof SetOspfMetricType) {
p.debug("SetOspfMetricType");
SetOspfMetricType somt = (SetOspfMetricType) stmt;
OspfMetricType mt = somt.getMetricType();
BDDDomain<OspfType> current = result.getReturnValue().getFirst().getOspfMetric();
BDDDomain<OspfType> newValue = new BDDDomain<>(current);
if (mt == OspfMetricType.E1) {
p.indent().debug("Value: E1");
newValue.setValue(OspfType.E1);
} else {
p.indent().debug("Value: E2");
newValue.setValue(OspfType.E1);
}
newValue = ite(result.getReturnAssignedValue(), p.getData().getOspfMetric(), newValue);
p.getData().setOspfMetric(newValue);
} else if (stmt instanceof SetLocalPreference) {
p.debug("SetLocalPreference");
SetLocalPreference slp = (SetLocalPreference) stmt;
IntExpr ie = slp.getLocalPreference();
BDDInteger newValue = applyIntExprModification(p.indent(), p.getData().getLocalPref(), ie);
newValue = ite(result.getReturnAssignedValue(), p.getData().getLocalPref(), newValue);
p.getData().setLocalPref(newValue);
} else if (stmt instanceof AddCommunity) {
p.debug("AddCommunity");
AddCommunity ac = (AddCommunity) stmt;
Set<CommunityVar> comms = _graph.findAllCommunities(_conf, ac.getExpr());
for (CommunityVar cvar : comms) {
if (!_policyQuotient.getCommsAssignedButNotMatched().contains(cvar)) {
p.indent().debug("Value: " + cvar);
BDD comm = p.getData().getCommunities().get(cvar);
BDD newValue = ite(result.getReturnAssignedValue(), comm, factory.one());
p.indent().debug("New Value: " + newValue);
p.getData().getCommunities().put(cvar, newValue);
}
}
} else if (stmt instanceof SetCommunity) {
p.debug("SetCommunity");
SetCommunity sc = (SetCommunity) stmt;
Set<CommunityVar> comms = _graph.findAllCommunities(_conf, sc.getExpr());
for (CommunityVar cvar : comms) {
if (!_policyQuotient.getCommsAssignedButNotMatched().contains(cvar)) {
p.indent().debug("Value: " + cvar);
BDD comm = p.getData().getCommunities().get(cvar);
BDD newValue = ite(result.getReturnAssignedValue(), comm, factory.one());
p.indent().debug("New Value: " + newValue);
p.getData().getCommunities().put(cvar, newValue);
}
}
} else if (stmt instanceof DeleteCommunity) {
p.debug("DeleteCommunity");
DeleteCommunity ac = (DeleteCommunity) stmt;
Set<CommunityVar> comms = _graph.findAllCommunities(_conf, ac.getExpr());
Set<CommunityVar> toDelete = new HashSet<>();
// Find comms to delete
for (CommunityVar cvar : comms) {
if (cvar.getType() == Type.REGEX) {
toDelete.addAll(_commDeps.get(cvar));
} else {
toDelete.add(cvar);
}
}
// Delete the comms
for (CommunityVar cvar : toDelete) {
if (!_policyQuotient.getCommsAssignedButNotMatched().contains(cvar)) {
p.indent().debug("Value: " + cvar.getValue() + ", " + cvar.getType());
BDD comm = p.getData().getCommunities().get(cvar);
BDD newValue = ite(result.getReturnAssignedValue(), comm, factory.zero());
p.indent().debug("New Value: " + newValue);
p.getData().getCommunities().put(cvar, newValue);
}
}
} else if (stmt instanceof RetainCommunity) {
p.debug("RetainCommunity");
// no op
} else if (stmt instanceof PrependAsPath) {
p.debug("PrependAsPath");
PrependAsPath pap = (PrependAsPath) stmt;
Integer prependCost = prependLength(pap.getExpr());
p.indent().debug("Cost: " + prependCost);
BDDInteger met = p.getData().getMetric();
BDDInteger newValue = met.add(BDDInteger.makeFromValue(met.getFactory(), 32, prependCost));
newValue = ite(result.getReturnAssignedValue(), p.getData().getMetric(), newValue);
p.getData().setMetric(newValue);
} else if (stmt instanceof SetOrigin) {
p.debug("SetOrigin");
// System.out.println("Warning: use of unimplemented feature SetOrigin");
// TODO: implement me
} else if (stmt instanceof SetNextHop) {
p.debug("SetNextHop");
// System.out.println("Warning: use of unimplemented feature SetNextHop");
// TODO: implement me
} else {
throw new BatfishException("TODO: statement transfer function: " + stmt);
}
}
// If this is the outermost call, then we relate the variables
if (p.getInitialCall()) {
p.debug("InitialCall finalizing");
// Apply the default action
if (!doesReturn) {
p.debug("Applying default action: " + p.getDefaultAccept());
if (p.getDefaultAccept()) {
result = returnValue(result, true);
} else {
result = returnValue(result, false);
}
}
// Set all the values to 0 if the return is not true;
TransferReturn ret = result.getReturnValue();
BDDRoute retVal = ite(ret.getSecond(), ret.getFirst(), zeroedRecord());
result = result.setReturnValue(new TransferReturn(retVal, ret.getSecond()));
}
return result;
}
Aggregations