use of org.batfish.symbolic.GraphEdge in project batfish by batfish.
the class Encoder method buildCounterExample.
/*
* Add the relevant variables in the counterexample to
* display to the user in a human-readable fashion
*/
private void buildCounterExample(Encoder enc, Model m, SortedMap<String, String> model, SortedMap<String, String> packetModel, SortedSet<String> fwdModel, SortedMap<String, SortedMap<String, String>> envModel, SortedSet<String> failures) {
SortedMap<Expr, String> valuation = new TreeMap<>();
// If user asks for the full model
for (Entry<String, Expr> entry : _allVariables.entrySet()) {
String name = entry.getKey();
Expr e = entry.getValue();
Expr val = m.evaluate(e, true);
if (!val.equals(e)) {
String s = val.toString();
if (_question.getFullModel()) {
model.put(name, s);
}
valuation.put(e, s);
}
}
// Packet model
SymbolicPacket p = enc.getMainSlice().getSymbolicPacket();
String dstIp = valuation.get(p.getDstIp());
String srcIp = valuation.get(p.getSrcIp());
String dstPt = valuation.get(p.getDstPort());
String srcPt = valuation.get(p.getSrcPort());
String icmpCode = valuation.get(p.getIcmpCode());
String icmpType = valuation.get(p.getIcmpType());
String ipProtocol = valuation.get(p.getIpProtocol());
String tcpAck = valuation.get(p.getTcpAck());
String tcpCwr = valuation.get(p.getTcpCwr());
String tcpEce = valuation.get(p.getTcpEce());
String tcpFin = valuation.get(p.getTcpFin());
String tcpPsh = valuation.get(p.getTcpPsh());
String tcpRst = valuation.get(p.getTcpRst());
String tcpSyn = valuation.get(p.getTcpSyn());
String tcpUrg = valuation.get(p.getTcpUrg());
Ip dip = new Ip(Long.parseLong(dstIp));
Ip sip = new Ip(Long.parseLong(srcIp));
packetModel.put("dstIp", dip.toString());
if (sip.asLong() != 0) {
packetModel.put("srcIp", sip.toString());
}
if (dstPt != null && !dstPt.equals("0")) {
packetModel.put("dstPort", dstPt);
}
if (srcPt != null && !srcPt.equals("0")) {
packetModel.put("srcPort", srcPt);
}
if (icmpCode != null && !icmpCode.equals("0")) {
packetModel.put("icmpCode", icmpCode);
}
if (icmpType != null && !icmpType.equals("0")) {
packetModel.put("icmpType", icmpType);
}
if (ipProtocol != null && !ipProtocol.equals("0")) {
Integer number = Integer.parseInt(ipProtocol);
IpProtocol proto = IpProtocol.fromNumber(number);
packetModel.put("protocol", proto.toString());
}
if ("true".equals(tcpAck)) {
packetModel.put("tcpAck", "set");
}
if ("true".equals(tcpCwr)) {
packetModel.put("tcpCwr", "set");
}
if ("true".equals(tcpEce)) {
packetModel.put("tcpEce", "set");
}
if ("true".equals(tcpFin)) {
packetModel.put("tcpFin", "set");
}
if ("true".equals(tcpPsh)) {
packetModel.put("tcpPsh", "set");
}
if ("true".equals(tcpRst)) {
packetModel.put("tcpRst", "set");
}
if ("true".equals(tcpSyn)) {
packetModel.put("tcpSyn", "set");
}
if ("true".equals(tcpUrg)) {
packetModel.put("tcpUrg", "set");
}
for (EncoderSlice slice : enc.getSlices().values()) {
for (Entry<LogicalEdge, SymbolicRoute> entry2 : slice.getLogicalGraph().getEnvironmentVars().entrySet()) {
LogicalEdge lge = entry2.getKey();
SymbolicRoute r = entry2.getValue();
if ("true".equals(valuation.get(r.getPermitted()))) {
SortedMap<String, String> recordMap = new TreeMap<>();
GraphEdge ge = lge.getEdge();
String nodeIface = ge.getRouter() + "," + ge.getStart().getName() + " (BGP)";
envModel.put(nodeIface, recordMap);
if (r.getPrefixLength() != null) {
String x = valuation.get(r.getPrefixLength());
if (x != null) {
int len = Integer.parseInt(x);
Prefix p1 = new Prefix(dip, len);
recordMap.put("prefix", p1.toString());
}
}
if (r.getAdminDist() != null) {
String x = valuation.get(r.getAdminDist());
if (x != null) {
recordMap.put("admin distance", x);
}
}
if (r.getLocalPref() != null) {
String x = valuation.get(r.getLocalPref());
if (x != null) {
recordMap.put("local preference", x);
}
}
if (r.getMetric() != null) {
String x = valuation.get(r.getMetric());
if (x != null) {
recordMap.put("protocol metric", x);
}
}
if (r.getMed() != null) {
String x = valuation.get(r.getMed());
if (x != null) {
recordMap.put("multi-exit disc.", valuation.get(r.getMed()));
}
}
if (r.getOspfArea() != null && r.getOspfArea().getBitVec() != null) {
String x = valuation.get(r.getOspfArea().getBitVec());
if (x != null) {
Integer i = Integer.parseInt(x);
Long area = r.getOspfArea().value(i);
recordMap.put("OSPF Area", area.toString());
}
}
if (r.getOspfType() != null && r.getOspfType().getBitVec() != null) {
String x = valuation.get(r.getOspfType().getBitVec());
if (x != null) {
Integer i = Integer.parseInt(x);
OspfType type = r.getOspfType().value(i);
recordMap.put("OSPF Type", type.toString());
}
}
for (Entry<CommunityVar, BoolExpr> entry3 : r.getCommunities().entrySet()) {
CommunityVar cvar = entry3.getKey();
BoolExpr e = entry3.getValue();
String c = valuation.get(e);
// TODO: what about OTHER type?
if ("true".equals(c) && displayCommunity(cvar)) {
String s = cvar.getValue();
String t = slice.getNamedCommunities().get(cvar.getValue());
s = (t == null ? s : t);
recordMap.put("community " + s, "");
}
}
}
}
}
// Forwarding Model
enc.getMainSlice().getSymbolicDecisions().getDataForwarding().forEach((router, edge, e) -> {
String s = valuation.get(e);
if ("true".equals(s)) {
SymbolicRoute r = enc.getMainSlice().getSymbolicDecisions().getBestNeighbor().get(router);
if (r.getProtocolHistory() != null) {
Protocol proto;
List<Protocol> allProtocols = enc.getMainSlice().getProtocols().get(router);
if (allProtocols.size() == 1) {
proto = allProtocols.get(0);
} else {
s = valuation.get(r.getProtocolHistory().getBitVec());
int i = Integer.parseInt(s);
proto = r.getProtocolHistory().value(i);
}
fwdModel.add(edge + " (" + proto.name() + ")");
} else {
fwdModel.add(edge.toString());
}
}
});
_symbolicFailures.getFailedInternalLinks().forEach((x, y, e) -> {
String s = valuation.get(e);
if ("1".equals(s)) {
String pair = (x.compareTo(y) < 0 ? x + "," + y : y + "," + x);
failures.add("link(" + pair + ")");
}
});
_symbolicFailures.getFailedEdgeLinks().forEach((ge, e) -> {
String s = valuation.get(e);
if ("1".equals(s)) {
failures.add("link(" + ge.getRouter() + "," + ge.getStart().getName() + ")");
}
});
}
use of org.batfish.symbolic.GraphEdge in project batfish by batfish.
the class EncoderSlice method addTransferFunction.
/*
* Constraints that define relationships between various messages
* in the network. The same transfer function abstraction is used
* for both import and export constraints by relating different collections
* of variables.
*/
private void addTransferFunction() {
for (Entry<String, Configuration> entry : getGraph().getConfigurations().entrySet()) {
String router = entry.getKey();
Configuration conf = entry.getValue();
for (Protocol proto : getProtocols().get(router)) {
Boolean usedExport = false;
boolean hasEdge = false;
List<ArrayList<LogicalEdge>> les = _logicalGraph.getLogicalEdges().get(router, proto);
assert (les != null);
for (ArrayList<LogicalEdge> eList : les) {
for (LogicalEdge e : eList) {
GraphEdge ge = e.getEdge();
if (!getGraph().isEdgeUsed(conf, proto, ge)) {
continue;
}
hasEdge = true;
SymbolicRoute varsOther;
switch(e.getEdgeType()) {
case IMPORT:
varsOther = _logicalGraph.findOtherVars(e);
addImportConstraint(e, varsOther, conf, proto, ge, router);
break;
case EXPORT:
// OSPF export is tricky because it does not depend on being
// in the FIB. So it can come from either a redistributed route
// or another OSPF route. We always take the direct OSPF
SymbolicRoute ospfRedistribVars = null;
SymbolicRoute overallBest = null;
if (proto.isOspf()) {
varsOther = getBestNeighborPerProtocol(router, proto);
if (_ospfRedistributed.containsKey(router)) {
ospfRedistribVars = _ospfRedistributed.get(router);
overallBest = _symbolicDecisions.getBestNeighbor().get(router);
}
} else {
varsOther = _symbolicDecisions.getBestNeighbor().get(router);
}
Set<Prefix> originations = _originatedNetworks.get(router, proto);
assert varsOther != null;
assert originations != null;
addExportConstraint(e, varsOther, ospfRedistribVars, overallBest, conf, proto, ge, router, usedExport, originations);
usedExport = true;
break;
default:
break;
}
}
}
// If no edge used, then just set the best record to be false for that protocol
if (!hasEdge) {
SymbolicRoute protoBest;
if (_optimizations.getSliceHasSingleProtocol().contains(router)) {
protoBest = _symbolicDecisions.getBestNeighbor().get(router);
} else {
protoBest = _symbolicDecisions.getBestNeighborPerProtocol().get(router, proto);
}
assert protoBest != null;
add(mkNot(protoBest.getPermitted()));
}
}
}
}
use of org.batfish.symbolic.GraphEdge in project batfish by batfish.
the class EncoderSlice method addControlForwardingConstraints.
/*
* Constraints that define control-plane forwarding.
* If there is some valid import, then control plane forwarding
* will occur out an interface when this is the best choice.
* Otherwise, it will not occur.
*/
private void addControlForwardingConstraints() {
for (Entry<String, Configuration> entry : getGraph().getConfigurations().entrySet()) {
String router = entry.getKey();
Configuration conf = entry.getValue();
boolean someEdge = false;
SymbolicRoute best = _symbolicDecisions.getBestNeighbor().get(router);
Map<GraphEdge, BoolExpr> cfExprs = new HashMap<>();
Set<GraphEdge> constrained = new HashSet<>();
for (Protocol proto : getProtocols().get(router)) {
for (LogicalEdge e : collectAllImportLogicalEdges(router, conf, proto)) {
someEdge = true;
constrained.add(e.getEdge());
SymbolicRoute vars = correctVars(e);
BoolExpr choice = _symbolicDecisions.getChoiceVariables().get(router, proto, e);
BoolExpr isBest = mkAnd(choice, equal(conf, proto, best, vars, e, false));
GraphEdge ge = e.getEdge();
// Connected routes should only forward if not absorbed by interface
GraphEdge other = getGraph().getOtherEnd().get(ge);
BoolExpr connectedWillSend;
if (other == null || getGraph().isHost(ge.getPeer())) {
Ip ip = ge.getStart().getAddress().getIp();
BitVecExpr val = getCtx().mkBV(ip.asLong(), 32);
connectedWillSend = mkNot(mkEq(_symbolicPacket.getDstIp(), val));
} else {
Ip ip = other.getStart().getAddress().getIp();
BitVecExpr val = getCtx().mkBV(ip.asLong(), 32);
connectedWillSend = mkEq(_symbolicPacket.getDstIp(), val);
}
BoolExpr canSend = (proto.isConnected() ? connectedWillSend : mkTrue());
BoolExpr sends = mkAnd(canSend, isBest);
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
add(mkImplies(sends, cForward));
// record the negation as well
cfExprs.merge(ge, sends, (a, b) -> mkOr(a, b));
}
}
// For edges that are never used, we constraint them to not be forwarded out of
for (GraphEdge ge : getGraph().getEdgeMap().get(router)) {
if (!constrained.contains(ge)) {
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
add(mkNot(cForward));
}
}
// Handle the case that the router has no protocol running
if (!someEdge) {
for (GraphEdge ge : getGraph().getEdgeMap().get(router)) {
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
add(mkNot(cForward));
}
} else {
// If no best route, then no forwarding
Map<Protocol, List<ArrayList<LogicalEdge>>> map = _logicalGraph.getLogicalEdges().get(router);
Set<GraphEdge> seen = new HashSet<>();
for (List<ArrayList<LogicalEdge>> eList : map.values()) {
for (ArrayList<LogicalEdge> edges : eList) {
for (LogicalEdge le : edges) {
GraphEdge ge = le.getEdge();
if (seen.contains(ge)) {
continue;
}
seen.add(ge);
BoolExpr expr = cfExprs.get(ge);
BoolExpr cForward = _symbolicDecisions.getControlForwarding().get(router, ge);
assert (cForward != null);
if (expr != null) {
add(mkImplies(mkNot(expr), mkNot(cForward)));
} else {
add(mkNot(cForward));
}
}
}
}
}
}
}
use of org.batfish.symbolic.GraphEdge in project batfish by batfish.
the class EncoderSlice method addEnvironmentVariables.
/*
* Initialize all environment symbolic records for BGP.
*/
private void addEnvironmentVariables() {
// If not the main slice, just use the main slice
if (!isMainSlice()) {
Map<LogicalEdge, SymbolicRoute> envs = _logicalGraph.getEnvironmentVars();
EncoderSlice main = _encoder.getMainSlice();
LogicalGraph lg = main.getLogicalGraph();
Map<LogicalEdge, SymbolicRoute> existing = lg.getEnvironmentVars();
envs.putAll(existing);
return;
}
// Otherwise create it anew
for (String router : getGraph().getRouters()) {
for (Protocol proto : getProtocols().get(router)) {
if (proto.isBgp()) {
List<ArrayList<LogicalEdge>> les = _logicalGraph.getLogicalEdges().get(router, proto);
assert (les != null);
for (ArrayList<LogicalEdge> eList : les) {
for (LogicalEdge e : eList) {
if (e.getEdgeType() == EdgeType.IMPORT) {
GraphEdge ge = e.getEdge();
BgpNeighbor n = getGraph().getEbgpNeighbors().get(ge);
if (n != null && ge.getEnd() == null) {
if (!isMainSlice()) {
LogicalGraph lg = _encoder.getMainSlice().getLogicalGraph();
SymbolicRoute r = lg.getEnvironmentVars().get(e);
_logicalGraph.getEnvironmentVars().put(e, r);
} else {
String address;
if (n.getAddress() == null) {
address = "null";
} else {
address = n.getAddress().toString();
}
String ifaceName = "ENV-" + address;
String name = String.format("%d_%s%s_%s_%s_%s", _encoder.getId(), _sliceName, router, proto.name(), "EXPORT", ifaceName);
SymbolicRoute vars = new SymbolicRoute(this, name, router, proto, _optimizations, null, ge.isAbstract());
getAllSymbolicRecords().add(vars);
_logicalGraph.getEnvironmentVars().put(e, vars);
}
}
}
}
}
}
}
}
}
use of org.batfish.symbolic.GraphEdge in project batfish by batfish.
the class EncoderSlice method addSymbolicRecords.
/*
* Initialize all control-plane message symbolic records.
* Also maps each logical graph edge to its opposite edge.
*/
private void addSymbolicRecords() {
Map<String, Map<Protocol, Map<GraphEdge, ArrayList<LogicalEdge>>>> importInverseMap = new HashMap<>();
Map<String, Map<Protocol, Map<GraphEdge, ArrayList<LogicalEdge>>>> exportInverseMap = new HashMap<>();
Map<String, Map<Protocol, SymbolicRoute>> singleExportMap = new HashMap<>();
// add edge EXPORT and IMPORT state variables
for (Entry<String, List<GraphEdge>> entry : getGraph().getEdgeMap().entrySet()) {
String router = entry.getKey();
List<GraphEdge> edges = entry.getValue();
Map<Protocol, SymbolicRoute> singleProtoMap;
singleProtoMap = new HashMap<>();
Map<Protocol, Map<GraphEdge, ArrayList<LogicalEdge>>> importEnumMap;
importEnumMap = new HashMap<>();
Map<Protocol, Map<GraphEdge, ArrayList<LogicalEdge>>> exportEnumMap;
exportEnumMap = new HashMap<>();
singleExportMap.put(router, singleProtoMap);
importInverseMap.put(router, importEnumMap);
exportInverseMap.put(router, exportEnumMap);
for (Protocol proto : getProtocols().get(router)) {
// Add redistribution variables
Set<Protocol> r = _logicalGraph.getRedistributedProtocols().get(router, proto);
assert r != null;
if (proto.isOspf() && r.size() > 1) {
// Add the ospf redistributed record if needed
String rname = String.format("%d_%s%s_%s_%s", _encoder.getId(), _sliceName, router, proto.name(), "Redistributed");
SymbolicRoute rec = new SymbolicRoute(this, rname, router, proto, _optimizations, null, false);
_ospfRedistributed.put(router, rec);
getAllSymbolicRecords().add(rec);
}
Boolean useSingleExport = _optimizations.getSliceCanKeepSingleExportVar().get(router, proto);
assert (useSingleExport != null);
Map<GraphEdge, ArrayList<LogicalEdge>> importGraphEdgeMap = new HashMap<>();
Map<GraphEdge, ArrayList<LogicalEdge>> exportGraphEdgeMap = new HashMap<>();
importEnumMap.put(proto, importGraphEdgeMap);
exportEnumMap.put(proto, exportGraphEdgeMap);
for (GraphEdge e : edges) {
Configuration conf = getGraph().getConfigurations().get(router);
if (getGraph().isEdgeUsed(conf, proto, e)) {
ArrayList<LogicalEdge> importEdgeList = new ArrayList<>();
ArrayList<LogicalEdge> exportEdgeList = new ArrayList<>();
importGraphEdgeMap.put(e, importEdgeList);
exportGraphEdgeMap.put(e, exportEdgeList);
for (int len = 0; len <= BITS; len++) {
String ifaceName = e.getStart().getName();
if (!proto.isConnected() && !proto.isStatic()) {
// to reuse the existing variables instead of creating new ones
if (useSingleExport) {
SymbolicRoute singleVars = singleExportMap.get(router).get(proto);
SymbolicRoute ev1;
if (singleVars == null) {
String name = String.format("%d_%s%s_%s_%s_%s", _encoder.getId(), _sliceName, router, proto.name(), "SINGLE-EXPORT", "");
ev1 = new SymbolicRoute(this, name, router, proto, _optimizations, null, e.isAbstract());
singleProtoMap.put(proto, ev1);
getAllSymbolicRecords().add(ev1);
} else {
ev1 = singleVars;
}
LogicalEdge eExport = new LogicalEdge(e, EdgeType.EXPORT, ev1);
exportEdgeList.add(eExport);
} else {
String name = String.format("%d_%s%s_%s_%s_%s", _encoder.getId(), _sliceName, router, proto.name(), "EXPORT", ifaceName);
SymbolicRoute ev1 = new SymbolicRoute(this, name, router, proto, _optimizations, null, e.isAbstract());
LogicalEdge eExport = new LogicalEdge(e, EdgeType.EXPORT, ev1);
exportEdgeList.add(eExport);
getAllSymbolicRecords().add(ev1);
}
}
boolean notNeeded = _optimizations.getSliceCanCombineImportExportVars().get(router).get(proto).contains(e);
Interface i = e.getStart();
Prefix p = i.getAddress().getPrefix();
boolean doModel = !(proto.isConnected() && p != null && !relevantPrefix(p));
// PolicyQuotient: Don't model the connected interfaces that aren't relevant
if (doModel) {
if (notNeeded) {
String name = String.format("%d_%s%s_%s_%s_%s", _encoder.getId(), _sliceName, router, proto.name(), "IMPORT", ifaceName);
SymbolicRoute ev2 = new SymbolicRoute(name, proto);
LogicalEdge eImport = new LogicalEdge(e, EdgeType.IMPORT, ev2);
importEdgeList.add(eImport);
} else {
String name = String.format("%d_%s%s_%s_%s_%s", _encoder.getId(), _sliceName, router, proto.name(), "IMPORT", ifaceName);
SymbolicRoute ev2 = new SymbolicRoute(this, name, router, proto, _optimizations, null, e.isAbstract());
LogicalEdge eImport = new LogicalEdge(e, EdgeType.IMPORT, ev2);
importEdgeList.add(eImport);
getAllSymbolicRecords().add(ev2);
}
}
}
List<ArrayList<LogicalEdge>> es = _logicalGraph.getLogicalEdges().get(router, proto);
assert (es != null);
ArrayList<LogicalEdge> allEdges = new ArrayList<>();
allEdges.addAll(importEdgeList);
allEdges.addAll(exportEdgeList);
es.add(allEdges);
}
}
}
}
// Build a map to find the opposite of a given edge
_logicalGraph.getLogicalEdges().forEach((router, edgeLists) -> {
for (Protocol proto : getProtocols().get(router)) {
for (ArrayList<LogicalEdge> edgeList : edgeLists.get(proto)) {
for (LogicalEdge e : edgeList) {
GraphEdge edge = e.getEdge();
Map<GraphEdge, ArrayList<LogicalEdge>> m;
if (edge.getPeer() != null) {
if (e.getEdgeType() == EdgeType.IMPORT) {
m = exportInverseMap.get(edge.getPeer()).get(proto);
} else {
m = importInverseMap.get(edge.getPeer()).get(proto);
}
if (m != null) {
GraphEdge otherEdge = getGraph().getOtherEnd().get(edge);
ArrayList<LogicalEdge> list = m.get(otherEdge);
if (list == null) {
m.put(otherEdge, new ArrayList<>());
} else if (list.size() > 0) {
LogicalEdge other = list.get(0);
_logicalGraph.getOtherEnd().put(e, other);
}
}
}
}
}
}
});
}
Aggregations