package org.batfish.bdp; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.batfish.common.BatfishException; import org.batfish.datamodel.AbstractRoute; import org.batfish.datamodel.Ip; import org.batfish.datamodel.Prefix; public class Fib implements Serializable { private static final int MAX_DEPTH = 10; /** * */ private static final long serialVersionUID = 1L; private final Map<AbstractRoute, Map<String, Set<AbstractRoute>>> _nextHopInterfaces; private final Rib _rib; public Fib(Rib rib) { _rib = rib; _nextHopInterfaces = new HashMap<>(); for (AbstractRoute route : rib.getRoutes()) { Map<String, Set<AbstractRoute>> nextHopInterfaces = new TreeMap<>(); collectNextHopInterfaces(route, nextHopInterfaces, new HashSet<>(), 0); _nextHopInterfaces.put(route, nextHopInterfaces); } } private void collectNextHopInterfaces(AbstractRoute route, Map<String, Set<AbstractRoute>> nextHopInterfaces, Set<Prefix> seenNetworks, int depth) { Prefix network = route.getNetwork(); if (seenNetworks.contains(network)) { return; } Set<Prefix> newSeenNetworks = new HashSet<>(seenNetworks); newSeenNetworks.add(network); if (depth > MAX_DEPTH) { throw new BatfishException( "Exceeded max route recursion depth: " + MAX_DEPTH); } Ip nextHopIp = route.getNextHopIp(); if (nextHopIp != null) { Set<AbstractRoute> nextHopLongestPrefixMatchRoutes = _rib .longestPrefixMatch(nextHopIp); for (AbstractRoute nextHopLongestPrefixMatchRoute : nextHopLongestPrefixMatchRoutes) { collectNextHopInterfaces(nextHopLongestPrefixMatchRoute, nextHopInterfaces, newSeenNetworks, depth + 1); } } else { String nextHopInterface = route.getNextHopInterface(); if (nextHopInterface != null) { Set<AbstractRoute> nextHopInterfaceRoutes = nextHopInterfaces .get(nextHopInterface); if (nextHopInterfaceRoutes == null) { nextHopInterfaceRoutes = new TreeSet<>(); nextHopInterfaces.put(nextHopInterface, nextHopInterfaceRoutes); } nextHopInterfaceRoutes.add(route); } else { throw new BatfishException( "Encountered route with neither nextHopIp nor nextHopInterface"); } } } public Map<String, Set<AbstractRoute>> getNextHopInterfaces(Ip ip) { Map<String, Set<AbstractRoute>> nextHopInterfaces = new TreeMap<>(); Set<AbstractRoute> nextHopRoutes = _rib.longestPrefixMatch(ip); for (AbstractRoute nextHopRoute : nextHopRoutes) { Map<String, Set<AbstractRoute>> currentNextHopInterfaces = _nextHopInterfaces .get(nextHopRoute); currentNextHopInterfaces .forEach((nextHopInterface, currentNextHopInterfaceRoutes) -> { Set<AbstractRoute> nextHopInterfaceRoutes = nextHopInterfaces .get(nextHopInterface); if (nextHopInterfaceRoutes == null) { nextHopInterfaceRoutes = new TreeSet<>(); nextHopInterfaces.put(nextHopInterface, nextHopInterfaceRoutes); } nextHopInterfaceRoutes.addAll(currentNextHopInterfaceRoutes); }); } return nextHopInterfaces; } public Map<AbstractRoute, Set<String>> getNextHopInterfacesByRoute( Ip dstIp) { Map<AbstractRoute, Set<String>> nextHopInterfacesByRoute = new HashMap<>(); Set<AbstractRoute> nextHopRoutes = _rib.longestPrefixMatch(dstIp); for (AbstractRoute nextHopRoute : nextHopRoutes) { Set<String> nextHopInterfaces = _nextHopInterfaces.get(nextHopRoute) .keySet(); nextHopInterfacesByRoute.put(nextHopRoute, nextHopInterfaces); } return nextHopInterfacesByRoute; } }