use of org.batfish.datamodel.Prefix in project batfish by batfish.
the class CommonUtil method synthesizeTopology.
public static Topology synthesizeTopology(Map<String, Configuration> configurations) {
SortedSet<Edge> edges = new TreeSet<>();
Map<Prefix, Set<NodeInterfacePair>> prefixInterfaces = new HashMap<>();
configurations.forEach((nodeName, node) -> {
for (Entry<String, Interface> e : node.getInterfaces().entrySet()) {
String ifaceName = e.getKey();
Interface iface = e.getValue();
if (!iface.isLoopback(node.getConfigurationFormat()) && iface.getActive()) {
for (InterfaceAddress address : iface.getAllAddresses()) {
if (address.getNetworkBits() < Prefix.MAX_PREFIX_LENGTH) {
Prefix prefix = address.getPrefix();
NodeInterfacePair pair = new NodeInterfacePair(nodeName, ifaceName);
Set<NodeInterfacePair> interfaceBucket = prefixInterfaces.computeIfAbsent(prefix, k -> new HashSet<>());
interfaceBucket.add(pair);
}
}
}
}
});
for (Set<NodeInterfacePair> bucket : prefixInterfaces.values()) {
for (NodeInterfacePair p1 : bucket) {
for (NodeInterfacePair p2 : bucket) {
if (!p1.equals(p2)) {
Edge edge = new Edge(p1, p2);
edges.add(edge);
}
}
}
}
return new Topology(edges);
}
use of org.batfish.datamodel.Prefix in project batfish by batfish.
the class SelfNextHop method getNextHopIp.
@Override
public Ip getNextHopIp(Environment environment) {
// TODO: make work for dynamic sessions
Prefix prefix = new Prefix(environment.getPeerAddress(), Prefix.MAX_PREFIX_LENGTH);
BgpNeighbor neighbor = environment.getVrf().getBgpProcess().getNeighbors().get(prefix);
Ip localIp = neighbor.getLocalIp();
return localIp;
}
use of org.batfish.datamodel.Prefix in project batfish by batfish.
the class AbstractRib method nextHopIpsByPrefix.
@Override
public final Map<Prefix, Set<Ip>> nextHopIpsByPrefix() {
Map<Prefix, Set<Ip>> map = new TreeMap<>();
for (AbstractRoute route : getRoutes()) {
Prefix prefix = route.getNetwork();
Ip nextHopIp = route.getNextHopIp();
Set<Ip> nextHopIps = map.computeIfAbsent(prefix, k -> new TreeSet<>());
nextHopIps.add(nextHopIp);
}
return map;
}
use of org.batfish.datamodel.Prefix in project batfish by batfish.
the class BdpEngine method computeFixedPoint.
/**
* Attempt to compute the fixed point of the data plane.
*
* @param nodes A dictionary of configuration-wrapping Bdp nodes keyed by name
* @param topology The topology representing physical adjacencies between interface of the nodes
* @param dp The output data plane
* @param externalAdverts Optional external BGP advertisements fed into the data plane computation
* @param ae The output answer element in which to store a report of the computation. Also
* contains the current recovery iteration.
* @param recoveryIterationHashCodes Dependent-route computation iteration hash-code dictionaries,
* themselves keyed by outer recovery iteration.
* @return true iff the computation is oscillating
*/
private boolean computeFixedPoint(SortedMap<String, Node> nodes, Topology topology, BdpDataPlane dp, Set<BgpAdvertisement> externalAdverts, BdpAnswerElement ae, SortedMap<Integer, SortedMap<Integer, Integer>> recoveryIterationHashCodes, SortedMap<Integer, SortedSet<Prefix>> iterationOscillatingPrefixes) {
try (ActiveSpan computeFixedPointSpan = GlobalTracer.get().buildSpan("Computing fixed point").startActive()) {
// avoid unused warning
assert computeFixedPointSpan != null;
SortedSet<Prefix> oscillatingPrefixes = ae.getOscillatingPrefixes();
// BEGIN DONE ONCE (except main rib)
// For each virtual router, setup the initial easy-to-do routes and init protocol-based RIBs:
AtomicInteger initialCompleted = _newBatch.apply("Compute initial connected and static routes, ospf setup, bgp setup", nodes.size());
try (ActiveSpan initRibsBdpSpan = GlobalTracer.get().buildSpan("Initializing easy routes for BDP").startActive()) {
// avoid unused warning
assert initRibsBdpSpan != null;
nodes.values().parallelStream().forEach(n -> {
for (VirtualRouter vr : n._virtualRouters.values()) {
vr.initRibsForBdp(dp.getIpOwners(), externalAdverts);
}
initialCompleted.incrementAndGet();
});
}
// OSPF internal routes
int numOspfInternalIterations;
try (ActiveSpan ospfInternalRoutesSpan = GlobalTracer.get().buildSpan("Initializing OSPF internal routes").startActive()) {
assert ospfInternalRoutesSpan != null;
numOspfInternalIterations = initOspfInternalRoutes(nodes, topology);
}
// RIP internal routes
try (ActiveSpan ripInternalRoutesSpan = GlobalTracer.get().buildSpan("Initializing RIP internal routes").startActive()) {
assert ripInternalRoutesSpan != null;
initRipInternalRoutes(nodes, topology);
}
// Prep for traceroutes
nodes.values().parallelStream().forEach(n -> n._virtualRouters.values().forEach(vr -> {
vr.importRib(vr._mainRib, vr._independentRib);
// Needed for activateStaticRoutes
vr._prevMainRib = vr._mainRib;
vr.activateStaticRoutes();
}));
// Update bgp neighbors with reachability
dp.setNodes(nodes);
computeFibs(nodes);
dp.setTopology(topology);
initRemoteBgpNeighbors(nodes.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, e -> e.getValue().getConfiguration())), dp.getIpOwners(), true, this, dp);
// END DONE ONCE
/*
* Setup maps to track iterations. We need this for oscillation detection.
* Specifically, if we detect that an iteration hashcode (a hash of all the nodes' RIBs)
* has been previously encountered, we go into recovery mode.
* Recovery mode means enabling "lockstep route propagation" for oscillating prefixes.
*
* Lockstep route propagation only allows one of the neighbors to propagate routes for
* oscillating prefixes in a given iteration.
* E.g., lexicographically lower neighbor propagates routes during
* odd iterations, and lex-higher neighbor during even iterations.
*/
Map<Integer, SortedSet<Integer>> iterationsByHashCode = new HashMap<>();
SortedMap<Integer, Integer> iterationHashCodes = new TreeMap<>();
Map<Integer, SortedSet<Route>> iterationRoutes = null;
Map<Integer, SortedMap<String, SortedMap<String, SortedSet<AbstractRoute>>>> iterationAbstractRoutes = null;
if (_settings.getBdpRecordAllIterations()) {
if (_settings.getBdpDetail()) {
iterationAbstractRoutes = new TreeMap<>();
} else {
iterationRoutes = new TreeMap<>();
}
} else if (_maxRecordedIterations > 0) {
if (_settings.getBdpDetail()) {
iterationAbstractRoutes = new LRUMap<>(_maxRecordedIterations);
} else {
iterationRoutes = new LRUMap<>(_maxRecordedIterations);
}
}
AtomicBoolean dependentRoutesChanged = new AtomicBoolean(false);
AtomicBoolean evenDependentRoutesChanged = new AtomicBoolean(false);
AtomicBoolean oddDependentRoutesChanged = new AtomicBoolean(false);
int numDependentRoutesIterations = 0;
// Go into iteration mode, until the routes converge (or oscillation is detected)
do {
numDependentRoutesIterations++;
AtomicBoolean currentChangedMonitor;
if (oscillatingPrefixes.isEmpty()) {
currentChangedMonitor = dependentRoutesChanged;
} else if (numDependentRoutesIterations % 2 == 0) {
currentChangedMonitor = evenDependentRoutesChanged;
} else {
currentChangedMonitor = oddDependentRoutesChanged;
}
currentChangedMonitor.set(false);
computeDependentRoutesIteration(nodes, topology, dp, numDependentRoutesIterations, oscillatingPrefixes);
/* Collect sizes of certain RIBs this iteration */
computeIterationStatistics(nodes, ae, numDependentRoutesIterations);
recordIterationDebugInfo(nodes, dp, iterationRoutes, iterationAbstractRoutes, numDependentRoutesIterations);
// Check to see if hash has changed
AtomicInteger checkFixedPointCompleted = _newBatch.apply("Iteration " + numDependentRoutesIterations + ": Check if fixed-point reached", nodes.size());
// This hashcode uniquely identifies the iteration (i.e., network state)
int iterationHashCode = computeIterationHashCode(nodes);
SortedSet<Integer> iterationsWithThisHashCode = iterationsByHashCode.computeIfAbsent(iterationHashCode, h -> new TreeSet<>());
iterationHashCodes.put(numDependentRoutesIterations, iterationHashCode);
int minNumberOfUnchangedIterationsForConvergence = oscillatingPrefixes.isEmpty() ? 1 : 2;
if (iterationsWithThisHashCode.isEmpty() || (!oscillatingPrefixes.isEmpty() && iterationsWithThisHashCode.equals(Collections.singleton(numDependentRoutesIterations - 1)))) {
iterationsWithThisHashCode.add(numDependentRoutesIterations);
} else if (!iterationsWithThisHashCode.contains(numDependentRoutesIterations - minNumberOfUnchangedIterationsForConvergence)) {
int lowestIterationWithThisHashCode = iterationsWithThisHashCode.first();
int completedOscillationRecoveryAttempts = ae.getCompletedOscillationRecoveryAttempts();
if (!oscillatingPrefixes.isEmpty()) {
completedOscillationRecoveryAttempts++;
ae.setCompletedOscillationRecoveryAttempts(completedOscillationRecoveryAttempts);
}
recoveryIterationHashCodes.put(completedOscillationRecoveryAttempts, iterationHashCodes);
handleOscillation(recoveryIterationHashCodes, iterationRoutes, iterationAbstractRoutes, lowestIterationWithThisHashCode, numDependentRoutesIterations, iterationOscillatingPrefixes, ae);
return true;
}
compareToPreviousIteration(nodes, currentChangedMonitor, checkFixedPointCompleted);
computeFibs(nodes);
initRemoteBgpNeighbors(nodes.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, e -> e.getValue().getConfiguration())), dp.getIpOwners(), true, this, dp);
} while (checkDependentRoutesChanged(dependentRoutesChanged, evenDependentRoutesChanged, oddDependentRoutesChanged, oscillatingPrefixes, numDependentRoutesIterations));
AtomicInteger computeBgpAdvertisementsToOutsideCompleted = _newBatch.apply("Compute BGP advertisements sent to outside", nodes.size());
nodes.values().parallelStream().forEach(n -> {
for (VirtualRouter vr : n._virtualRouters.values()) {
vr.computeBgpAdvertisementsToOutside(dp.getIpOwners());
}
computeBgpAdvertisementsToOutsideCompleted.incrementAndGet();
});
// Set iteration stats in the answer
ae.setOspfInternalIterations(numOspfInternalIterations);
ae.setDependentRoutesIterations(numDependentRoutesIterations);
return false;
}
}
use of org.batfish.datamodel.Prefix in project batfish by batfish.
the class VirtualRouter method initBaseBgpRibs.
public void initBaseBgpRibs(Set<BgpAdvertisement> externalAdverts, Map<Ip, Set<String>> ipOwners) {
if (_vrf.getBgpProcess() != null) {
int ebgpAdmin = RoutingProtocol.BGP.getDefaultAdministrativeCost(_c.getConfigurationFormat());
int ibgpAdmin = RoutingProtocol.IBGP.getDefaultAdministrativeCost(_c.getConfigurationFormat());
for (BgpAdvertisement advert : externalAdverts) {
if (advert.getDstNode().equals(_c.getHostname())) {
Ip dstIp = advert.getDstIp();
Set<String> dstIpOwners = ipOwners.get(dstIp);
String hostname = _c.getHostname();
if (dstIpOwners == null || !dstIpOwners.contains(hostname)) {
continue;
}
Ip srcIp = advert.getSrcIp();
// TODO: support passive bgp connections
Prefix srcPrefix = new Prefix(srcIp, Prefix.MAX_PREFIX_LENGTH);
BgpNeighbor neighbor = _vrf.getBgpProcess().getNeighbors().get(srcPrefix);
if (neighbor != null) {
BgpAdvertisementType type = advert.getType();
BgpRoute.Builder outgoingRouteBuilder = new BgpRoute.Builder();
boolean ebgp;
boolean received;
switch(type) {
case EBGP_RECEIVED:
ebgp = true;
received = true;
break;
case EBGP_SENT:
ebgp = true;
received = false;
break;
case IBGP_RECEIVED:
ebgp = false;
received = true;
break;
case IBGP_SENT:
ebgp = false;
received = false;
break;
case EBGP_ORIGINATED:
case IBGP_ORIGINATED:
default:
throw new BatfishException("Missing or invalid bgp advertisement type");
}
BgpMultipathRib targetRib = ebgp ? _baseEbgpRib : _baseIbgpRib;
RoutingProtocol targetProtocol = ebgp ? RoutingProtocol.BGP : RoutingProtocol.IBGP;
if (received) {
int admin = ebgp ? ebgpAdmin : ibgpAdmin;
AsPath asPath = advert.getAsPath();
SortedSet<Long> clusterList = advert.getClusterList();
SortedSet<Long> communities = new TreeSet<>(advert.getCommunities());
int localPreference = advert.getLocalPreference();
long metric = advert.getMed();
Prefix network = advert.getNetwork();
Ip nextHopIp = advert.getNextHopIp();
Ip originatorIp = advert.getOriginatorIp();
OriginType originType = advert.getOriginType();
RoutingProtocol srcProtocol = advert.getSrcProtocol();
int weight = advert.getWeight();
BgpRoute.Builder builder = new BgpRoute.Builder();
builder.setAdmin(admin);
builder.setAsPath(asPath.getAsSets());
builder.setClusterList(clusterList);
builder.setCommunities(communities);
builder.setLocalPreference(localPreference);
builder.setMetric(metric);
builder.setNetwork(network);
builder.setNextHopIp(nextHopIp);
builder.setOriginatorIp(originatorIp);
builder.setOriginType(originType);
builder.setProtocol(targetProtocol);
// TODO: support external route reflector clients
builder.setReceivedFromIp(advert.getSrcIp());
builder.setReceivedFromRouteReflectorClient(false);
builder.setSrcProtocol(srcProtocol);
// TODO: possibly suppport setting tag
builder.setWeight(weight);
BgpRoute route = builder.build();
targetRib.mergeRoute(route);
} else {
int localPreference;
if (ebgp) {
localPreference = BgpRoute.DEFAULT_LOCAL_PREFERENCE;
} else {
localPreference = advert.getLocalPreference();
}
outgoingRouteBuilder.setAsPath(advert.getAsPath().getAsSets());
outgoingRouteBuilder.setCommunities(new TreeSet<>(advert.getCommunities()));
outgoingRouteBuilder.setLocalPreference(localPreference);
outgoingRouteBuilder.setMetric(advert.getMed());
outgoingRouteBuilder.setNetwork(advert.getNetwork());
outgoingRouteBuilder.setNextHopIp(advert.getNextHopIp());
outgoingRouteBuilder.setOriginatorIp(advert.getOriginatorIp());
outgoingRouteBuilder.setOriginType(advert.getOriginType());
outgoingRouteBuilder.setProtocol(targetProtocol);
outgoingRouteBuilder.setReceivedFromIp(advert.getSrcIp());
// TODO:
// outgoingRouteBuilder.setReceivedFromRouteReflectorClient(...);
outgoingRouteBuilder.setSrcProtocol(advert.getSrcProtocol());
BgpRoute transformedOutgoingRoute = outgoingRouteBuilder.build();
BgpRoute.Builder transformedIncomingRouteBuilder = new BgpRoute.Builder();
// Incoming originatorIp
transformedIncomingRouteBuilder.setOriginatorIp(transformedOutgoingRoute.getOriginatorIp());
// Incoming receivedFromIp
transformedIncomingRouteBuilder.setReceivedFromIp(transformedOutgoingRoute.getReceivedFromIp());
// Incoming clusterList
transformedIncomingRouteBuilder.getClusterList().addAll(transformedOutgoingRoute.getClusterList());
// Incoming receivedFromRouteReflectorClient
transformedIncomingRouteBuilder.setReceivedFromRouteReflectorClient(transformedOutgoingRoute.getReceivedFromRouteReflectorClient());
// Incoming asPath
transformedIncomingRouteBuilder.setAsPath(transformedOutgoingRoute.getAsPath().getAsSets());
// Incoming communities
transformedIncomingRouteBuilder.getCommunities().addAll(transformedOutgoingRoute.getCommunities());
// Incoming protocol
transformedIncomingRouteBuilder.setProtocol(targetProtocol);
// Incoming network
transformedIncomingRouteBuilder.setNetwork(transformedOutgoingRoute.getNetwork());
// Incoming nextHopIp
transformedIncomingRouteBuilder.setNextHopIp(transformedOutgoingRoute.getNextHopIp());
// Incoming originType
transformedIncomingRouteBuilder.setOriginType(transformedOutgoingRoute.getOriginType());
// Incoming localPreference
transformedIncomingRouteBuilder.setLocalPreference(transformedOutgoingRoute.getLocalPreference());
// Incoming admin
int admin = ebgp ? ebgpAdmin : ibgpAdmin;
transformedIncomingRouteBuilder.setAdmin(admin);
// Incoming metric
transformedIncomingRouteBuilder.setMetric(transformedOutgoingRoute.getMetric());
// Incoming srcProtocol
transformedIncomingRouteBuilder.setSrcProtocol(targetProtocol);
String importPolicyName = neighbor.getImportPolicy();
if (ebgp && transformedOutgoingRoute.getAsPath().containsAs(neighbor.getLocalAs()) && !neighbor.getAllowLocalAsIn()) {
// disable-peer-as-check (getAllowRemoteAsOut) is set
continue;
}
/*
* CREATE INCOMING ROUTE
*/
boolean acceptIncoming = true;
if (importPolicyName != null) {
RoutingPolicy importPolicy = _c.getRoutingPolicies().get(importPolicyName);
if (importPolicy != null) {
acceptIncoming = importPolicy.process(transformedOutgoingRoute, transformedIncomingRouteBuilder, advert.getSrcIp(), _key, Direction.IN);
}
}
if (acceptIncoming) {
BgpRoute transformedIncomingRoute = transformedIncomingRouteBuilder.build();
targetRib.mergeRoute(transformedIncomingRoute);
}
}
}
}
}
}
importRib(_ebgpMultipathRib, _baseEbgpRib);
importRib(_ebgpBestPathRib, _baseEbgpRib);
importRib(_bgpBestPathRib, _baseEbgpRib);
importRib(_ibgpMultipathRib, _baseIbgpRib);
importRib(_ibgpBestPathRib, _baseIbgpRib);
importRib(_bgpBestPathRib, _baseIbgpRib);
}
Aggregations