use of org.batfish.symbolic.collections.Table2 in project batfish by batfish.
the class AbstractionBuilder method collectNeighborByAbstractId.
/*
* Collect concrete neighbors by their abstract ids
*/
private Table2<String, Integer, Set<String>> collectNeighborByAbstractId() {
// organize neighbors by abstract id
Table2<String, Integer, Set<String>> neighborByAbstractId = new Table2<>();
for (Entry<String, List<GraphEdge>> entry : _graph.getEdgeMap().entrySet()) {
String router = entry.getKey();
List<GraphEdge> edges = entry.getValue();
for (GraphEdge ge : edges) {
String peer = ge.getPeer();
if (peer != null) {
Integer j = _abstractGroups.getHandle(peer);
Set<String> existing = neighborByAbstractId.get(router, j);
if (existing != null) {
existing.add(peer);
} else {
Set<String> neighbors = new HashSet<>();
neighbors.add(peer);
neighborByAbstractId.put(router, j, neighbors);
}
}
}
}
return neighborByAbstractId;
}
use of org.batfish.symbolic.collections.Table2 in project batfish by batfish.
the class BatfishCompressor method compress.
public Map<String, Configuration> compress(HeaderSpace h) {
DestinationClasses dcs = DestinationClasses.create(_batfish, _graph, h, true);
ArrayList<Supplier<NetworkSlice>> ecs = NetworkSlice.allSlices(dcs, 0);
Optional<Map<GraphEdge, EquivalenceClassFilter>> opt = ecs.stream().map(Supplier::get).map(this::processSlice).reduce(this::mergeFilters);
if (!opt.isPresent()) {
return new HashMap<>();
}
Map<GraphEdge, EquivalenceClassFilter> filters = opt.get();
Table2<String, GraphEdge, EquivalenceClassFilter> filtersByRouter = new Table2<>();
for (Entry<GraphEdge, EquivalenceClassFilter> entry : filters.entrySet()) {
GraphEdge ge = entry.getKey();
filtersByRouter.put(ge.getRouter(), ge, entry.getValue());
}
return applyFilters(filtersByRouter);
}
use of org.batfish.symbolic.collections.Table2 in project batfish by batfish.
the class PropertyChecker method checkProperty.
/*
* General purpose logic for checking a property that holds that
* handles the various flags and parameters for a query with endpoints
*
* q is the question from the user.
* instrument instruments each router in the graph as needed to check the property.
* answer takes the result from Z3 and produces the answer for the user.
*
*/
private AnswerElement checkProperty(HeaderLocationQuestion q, TriFunction<Encoder, Set<String>, Set<GraphEdge>, Map<String, BoolExpr>> instrument, Function<VerifyParam, AnswerElement> answer) {
long totalTime = System.currentTimeMillis();
PathRegexes p = new PathRegexes(q);
Graph graph = new Graph(_batfish);
Set<GraphEdge> destPorts = findFinalInterfaces(graph, p);
List<String> sourceRouters = PatternUtils.findMatchingSourceNodes(graph, p);
if (destPorts.isEmpty()) {
throw new BatfishException("Set of valid destination interfaces is empty");
}
if (sourceRouters.isEmpty()) {
throw new BatfishException("Set of valid ingress nodes is empty");
}
inferDestinationHeaderSpace(graph, destPorts, q);
Set<GraphEdge> failOptions = failLinkSet(graph, q);
Tuple<Stream<Supplier<NetworkSlice>>, Long> ecs = findAllNetworkSlices(q, graph, true);
Stream<Supplier<NetworkSlice>> stream = ecs.getFirst();
Long timeAbstraction = ecs.getSecond();
AnswerElement[] answerElement = new AnswerElement[1];
VerificationResult[] result = new VerificationResult[2];
List<VerificationStats> ecStats = new ArrayList<>();
// Checks ECs in parallel, but short circuits when a counterexample is found
boolean hasCounterExample = stream.anyMatch(lazyEc -> {
long timeEc = System.currentTimeMillis();
NetworkSlice slice = lazyEc.get();
timeEc = System.currentTimeMillis() - timeEc;
synchronized (_lock) {
// Make sure the headerspace is correct
HeaderLocationQuestion question = new HeaderLocationQuestion(q);
question.setHeaderSpace(slice.getHeaderSpace());
// Get the EC graph and mapping
Graph g = slice.getGraph();
Set<String> srcRouters = mapConcreteToAbstract(slice, sourceRouters);
long timeEncoding = System.currentTimeMillis();
Encoder enc = new Encoder(_settings, g, question);
enc.computeEncoding();
timeEncoding = System.currentTimeMillis() - timeEncoding;
// Add environment constraints for base case
if (question.getDiffType() != null) {
if (question.getEnvDiff()) {
addEnvironmentConstraints(enc, question.getDeltaEnvironmentType());
}
} else {
addEnvironmentConstraints(enc, question.getBaseEnvironmentType());
}
Map<String, BoolExpr> prop = instrument.apply(enc, srcRouters, destPorts);
// If this is a equivalence query, we create a second copy of the network
Encoder enc2 = null;
Map<String, BoolExpr> prop2 = null;
if (question.getDiffType() != null) {
HeaderLocationQuestion q2 = new HeaderLocationQuestion(question);
q2.setFailures(0);
long timeDiffEncoding = System.currentTimeMillis();
enc2 = new Encoder(enc, g, q2);
enc2.computeEncoding();
timeDiffEncoding = System.currentTimeMillis() - timeDiffEncoding;
timeEncoding += timeDiffEncoding;
}
if (question.getDiffType() != null) {
assert (enc2 != null);
// create a map for enc2 to lookup a related environment variable from enc
Table2<GraphEdge, EdgeType, SymbolicRoute> relatedEnv = new Table2<>();
enc2.getMainSlice().getLogicalGraph().getEnvironmentVars().forEach((lge, r) -> relatedEnv.put(lge.getEdge(), lge.getEdgeType(), r));
BoolExpr related = enc.mkTrue();
addEnvironmentConstraints(enc2, question.getBaseEnvironmentType());
if (!question.getEnvDiff()) {
related = relateEnvironments(enc, enc2);
}
prop2 = instrument.apply(enc2, srcRouters, destPorts);
// Add diff constraints
BoolExpr required = enc.mkTrue();
for (String source : srcRouters) {
BoolExpr sourceProp1 = prop.get(source);
BoolExpr sourceProp2 = prop2.get(source);
BoolExpr val;
switch(q.getDiffType()) {
case INCREASED:
val = enc.mkImplies(sourceProp1, sourceProp2);
break;
case REDUCED:
val = enc.mkImplies(sourceProp2, sourceProp1);
break;
case ANY:
val = enc.mkEq(sourceProp1, sourceProp2);
break;
default:
throw new BatfishException("Missing case: " + q.getDiffType());
}
required = enc.mkAnd(required, val);
}
related = enc.mkAnd(related, relatePackets(enc, enc2));
enc.add(related);
enc.add(enc.mkNot(required));
} else {
// Not a differential query; just a query on a single version of the network.
BoolExpr allProp = enc.mkTrue();
for (String router : srcRouters) {
BoolExpr r = prop.get(router);
if (q.getNegate()) {
r = enc.mkNot(r);
}
allProp = enc.mkAnd(allProp, r);
}
enc.add(enc.mkNot(allProp));
}
addFailureConstraints(enc, destPorts, failOptions);
Tuple<VerificationResult, Model> tup = enc.verify();
VerificationResult res = tup.getFirst();
Model model = tup.getSecond();
if (q.getBenchmark()) {
VerificationStats stats = res.getStats();
stats.setAvgComputeEcTime(timeEc);
stats.setMaxComputeEcTime(timeEc);
stats.setMinComputeEcTime(timeEc);
stats.setAvgEncodingTime(timeEncoding);
stats.setMaxEncodingTime(timeEncoding);
stats.setMinEncodingTime(timeEncoding);
stats.setTimeCreateBdds((double) timeAbstraction);
synchronized (_lock) {
ecStats.add(stats);
}
}
if (!res.isVerified()) {
VerifyParam vp = new VerifyParam(res, model, srcRouters, enc, enc2, prop, prop2);
AnswerElement ae = answer.apply(vp);
synchronized (_lock) {
answerElement[0] = ae;
result[0] = res;
}
return true;
}
synchronized (_lock) {
result[1] = res;
}
return false;
}
});
totalTime = (System.currentTimeMillis() - totalTime);
VerificationResult res;
AnswerElement ae;
if (hasCounterExample) {
res = result[0];
ae = answerElement[0];
} else {
res = result[1];
VerifyParam vp = new VerifyParam(res, null, null, null, null, null, null);
ae = answer.apply(vp);
}
if (q.getBenchmark()) {
VerificationStats stats = VerificationStats.combineAll(ecStats, totalTime);
res.setStats(stats);
}
return ae;
}
use of org.batfish.symbolic.collections.Table2 in project batfish by batfish.
the class PropertyChecker method relateEnvironments.
private BoolExpr relateEnvironments(Encoder enc1, Encoder enc2) {
// create a map for enc2 to lookup a related environment variable from enc
Table2<GraphEdge, EdgeType, SymbolicRoute> relatedEnv = new Table2<>();
for (Entry<LogicalEdge, SymbolicRoute> entry : enc2.getMainSlice().getLogicalGraph().getEnvironmentVars().entrySet()) {
LogicalEdge lge = entry.getKey();
SymbolicRoute r = entry.getValue();
relatedEnv.put(lge.getEdge(), lge.getEdgeType(), r);
}
// relate environments if necessary
BoolExpr related = enc1.mkTrue();
Map<LogicalEdge, SymbolicRoute> map = enc1.getMainSlice().getLogicalGraph().getEnvironmentVars();
for (Map.Entry<LogicalEdge, SymbolicRoute> entry : map.entrySet()) {
LogicalEdge le = entry.getKey();
SymbolicRoute r1 = entry.getValue();
String router = le.getEdge().getRouter();
Configuration conf = enc1.getMainSlice().getGraph().getConfigurations().get(router);
// Lookup the same environment variable in the other copy
// The copy will have a different name but the same edge and type
SymbolicRoute r2 = relatedEnv.get(le.getEdge(), le.getEdgeType());
assert r2 != null;
BoolExpr x = equal(enc1, conf, r1, r2);
related = enc1.mkAnd(related, x);
}
return related;
}
use of org.batfish.symbolic.collections.Table2 in project batfish by batfish.
the class Graph method initIbgpNeighbors.
// TODO: very inefficient
/*
* Initialize iBGP neighbors by looking for nieghbors
* with the same AS number.
*/
private void initIbgpNeighbors() {
Map<String, Ip> ips = new HashMap<>();
Table2<String, String, BgpNeighbor> neighbors = new Table2<>();
// Match iBGP sessions with pairs of routers and BgpNeighbor
for (Entry<String, Configuration> entry : _configurations.entrySet()) {
String router = entry.getKey();
Configuration conf = entry.getValue();
BgpProcess p = conf.getDefaultVrf().getBgpProcess();
if (p != null) {
for (BgpNeighbor n : p.getNeighbors().values()) {
if (n.getLocalAs().equals(n.getRemoteAs())) {
ips.put(router, n.getLocalIp());
}
}
}
}
for (Entry<String, Configuration> entry : _configurations.entrySet()) {
String router = entry.getKey();
Configuration conf = entry.getValue();
BgpProcess p = conf.getDefaultVrf().getBgpProcess();
if (p != null) {
for (Entry<Prefix, BgpNeighbor> entry2 : p.getNeighbors().entrySet()) {
Prefix pfx = entry2.getKey();
BgpNeighbor n = entry2.getValue();
if (n.getLocalAs().equals(n.getRemoteAs())) {
for (Entry<String, Ip> ipEntry : ips.entrySet()) {
String r = ipEntry.getKey();
Ip ip = ipEntry.getValue();
if (!router.equals(r) && pfx.containsIp(ip)) {
neighbors.put(router, r, n);
}
}
}
}
}
}
// Add abstract graph edges for iBGP sessions
Table2<String, String, GraphEdge> reverse = new Table2<>();
neighbors.forEach((r1, r2, n1) -> {
Interface iface1 = createIbgpInterface(n1, r2);
BgpNeighbor n2 = neighbors.get(r2, r1);
GraphEdge ge;
if (n2 != null) {
Interface iface2 = createIbgpInterface(n2, r1);
ge = new GraphEdge(iface1, iface2, r1, r2, true, false);
} else {
ge = new GraphEdge(iface1, null, r1, null, true, false);
}
_allEdges.add(ge);
_ibgpNeighbors.put(ge, n1);
reverse.put(r1, r2, ge);
List<GraphEdge> edges = _edgeMap.get(r1);
if (edges != null) {
edges.add(ge);
} else {
edges = new ArrayList<>();
edges.add(ge);
_edgeMap.put(r1, edges);
}
});
// Add other end to ibgp edges
reverse.forEach((r1, r2, ge1) -> {
GraphEdge ge2 = reverse.get(r2, r1);
_otherEnd.put(ge1, ge2);
});
// Configure Route Reflector information
Integer[] id = new Integer[1];
id[0] = 1;
neighbors.forEach((r1, ns) -> {
if (!_originatorId.containsKey(r1)) {
_originatorId.put(r1, id[0]);
id[0]++;
}
Set<String> clients = new HashSet<>();
ns.forEach((r2, n) -> {
if (n.getRouteReflectorClient()) {
clients.add(r2);
_routeReflectorParent.put(r2, r1);
}
});
_routeReflectorClients.put(r1, clients);
});
}
Aggregations