use of org.batfish.datamodel.BgpUnnumberedPeerConfig in project batfish by batfish.
the class BgpTopologyUtils method addUnnumberedPeerEdges.
private static void addUnnumberedPeerEdges(BgpPeerConfigId neighborId, MutableValueGraph<BgpPeerConfigId, BgpSessionProperties> graph, NetworkConfigurations nc, L3Adjacencies l3Adjacencies) {
// neighbor will be null if neighborId has no peer interface defined
BgpUnnumberedPeerConfig neighbor = nc.getBgpUnnumberedPeerConfig(neighborId);
if (neighbor == null || neighbor.getLocalAs() == null || neighbor.getRemoteAsns().isEmpty()) {
return;
}
Set<BgpPeerConfigId> alreadyEstablished = graph.adjacentNodes(neighborId);
String hostname = neighborId.getHostname();
NodeInterfacePair peerNip = NodeInterfacePair.of(hostname, neighborId.getPeerInterface());
graph.nodes().stream().filter(candidateId -> !alreadyEstablished.contains(candidateId) && // Ensure candidate is unnumbered and has compatible local/remote AS
bgpCandidatePassesSanityChecks(neighborId, neighbor, candidateId, nc) && // Check layer 2 connectivity
l3Adjacencies.inSamePointToPointDomain(peerNip, NodeInterfacePair.of(candidateId.getHostname(), candidateId.getPeerInterface()))).forEach(remoteId -> addEdges(neighbor, neighborId, neighbor.getLocalIp(), remoteId, graph, nc));
}
use of org.batfish.datamodel.BgpUnnumberedPeerConfig in project batfish by batfish.
the class BgpTopologyUtils method initBgpTopology.
/**
* Compute the BGP topology -- a network of {@link BgpPeerConfigId}s connected by {@link
* BgpSessionProperties}.
*
* @param configurations node configurations, keyed by hostname
* @param ipVrfOwners network Ip owners (see {@link IpOwners#computeIpNodeOwners(Map, boolean)}
* for reference)
* @param keepInvalid whether to keep improperly configured neighbors. If performing configuration
* checks, you probably want this set to {@code true}, otherwise (e.g., computing dataplane)
* you want this to be {@code false}.
* @param checkReachability whether to perform dataplane-level checks to ensure that neighbors are
* reachable and sessions can be established correctly. <b>Note:</b> this is different from
* {@code keepInvalid=false}, which only does filters invalid neighbors at the control-plane
* level
* @param tracerouteEngine an instance of {@link TracerouteEngine} for doing reachability checks.
* @param l3Adjacencies {@link L3Adjacencies} of the network, for checking BGP unnumbered
* reachability.
* @return A graph ({@link Network}) representing all BGP peerings.
*/
@Nonnull
public static BgpTopology initBgpTopology(Map<String, Configuration> configurations, Map<Ip, Map<String, Set<String>>> ipVrfOwners, boolean keepInvalid, boolean checkReachability, @Nullable TracerouteEngine tracerouteEngine, Map<String, Map<String, Fib>> fibs, L3Adjacencies l3Adjacencies) {
checkArgument(!checkReachability || !keepInvalid, "Cannot check reachability while keeping invalid peers");
checkArgument(!checkReachability || tracerouteEngine != null, "Cannot check reachability without a traceroute engine");
// TODO: handle duplicate ips on different vrfs
NetworkConfigurations networkConfigurations = NetworkConfigurations.of(configurations);
/*
* First pass: identify all addresses "owned" by BgpNeighbors, add neighbor ids as vertices to
* the graph; dynamically determine local IPs as needed
*/
MutableValueGraph<BgpPeerConfigId, BgpSessionProperties> graph = ValueGraphBuilder.directed().allowsSelfLoops(false).build();
/*
* Multimap of active peers' BgpPeerConfigIds to all IPs that each peer may use as local IP
* when initiating a session. For a peer with an explicitly configured local IP, that IP is
* the only value associated with the peer in this map. Otherwise:
* - If FIBs are provided, the map contains all local IPs with which the peer may initiate,
* as inferred by getPotentialSrcIps().
* - Else no IPs are associated with the peer.
*/
ImmutableSetMultimap.Builder<BgpPeerConfigId, Ip> localIpsBuilder = ImmutableSetMultimap.builder();
for (Configuration node : configurations.values()) {
String hostname = node.getHostname();
for (Vrf vrf : node.getVrfs().values()) {
String vrfName = vrf.getName();
BgpProcess proc = vrf.getBgpProcess();
if (proc == null) {
// nothing to do if no bgp process on this VRF
continue;
}
Fib fib = fibs.getOrDefault(hostname, ImmutableMap.of()).get(vrfName);
for (Entry<Ip, BgpActivePeerConfig> e : proc.getActiveNeighbors().entrySet()) {
Ip peerAddress = e.getKey();
BgpActivePeerConfig config = e.getValue();
if (!keepInvalid && !bgpConfigPassesSanityChecks(config, hostname, vrfName, ipVrfOwners)) {
continue;
}
BgpPeerConfigId neighborId = new BgpPeerConfigId(hostname, vrfName, peerAddress.toPrefix(), false);
graph.addNode(neighborId);
if (config.getLocalIp() != null) {
localIpsBuilder.put(neighborId, config.getLocalIp());
} else if (fib != null) {
// No explicitly configured local IP. Check for dynamically resolvable local IPs.
localIpsBuilder.putAll(neighborId, getPotentialSrcIps(peerAddress, fib, node));
}
}
// Dynamic peers: map of prefix to BgpPassivePeerConfig
proc.getPassiveNeighbors().entrySet().stream().filter(entry -> keepInvalid || bgpConfigPassesSanityChecks(entry.getValue(), hostname, vrfName, ipVrfOwners)).forEach(entry -> graph.addNode(new BgpPeerConfigId(hostname, vrfName, entry.getKey(), true)));
// Unnumbered BGP peers: map of interface name to BgpUnnumberedPeerConfig
proc.getInterfaceNeighbors().entrySet().stream().filter(e -> keepInvalid || bgpConfigPassesSanityChecks(e.getValue(), hostname, vrfName, ipVrfOwners)).forEach(e -> graph.addNode(new BgpPeerConfigId(hostname, vrf.getName(), e.getKey())));
}
}
// Second pass: add edges to the graph. Note, these are directed edges.
Map<String, Multimap<String, BgpPeerConfigId>> receivers = new HashMap<>();
for (BgpPeerConfigId peer : graph.nodes()) {
if (peer.getType() == BgpPeerConfigType.UNNUMBERED) {
// Unnumbered configs only form sessions with each other
continue;
}
Multimap<String, BgpPeerConfigId> vrf = receivers.computeIfAbsent(peer.getHostname(), name -> LinkedListMultimap.create());
vrf.put(peer.getVrfName(), peer);
}
SetMultimap<BgpPeerConfigId, Ip> localIps = localIpsBuilder.build();
for (BgpPeerConfigId neighborId : graph.nodes()) {
switch(neighborId.getType()) {
case DYNAMIC:
// Passive end of the peering cannot initiate a connection
continue;
case ACTIVE:
addActivePeerEdges(neighborId, graph, networkConfigurations, ipVrfOwners, receivers, localIps.get(neighborId), checkReachability, tracerouteEngine);
break;
case UNNUMBERED:
addUnnumberedPeerEdges(neighborId, graph, networkConfigurations, l3Adjacencies);
break;
default:
throw new IllegalArgumentException(String.format("Unrecognized peer type: %s", neighborId));
}
}
return new BgpTopology(graph);
}
use of org.batfish.datamodel.BgpUnnumberedPeerConfig in project batfish by batfish.
the class IspModelingUtilsTest method testIsValidBgpPeerForBorderInterfaceInfo_unnumbered.
@Test
public void testIsValidBgpPeerForBorderInterfaceInfo_unnumbered() {
// missing remote ASN
BgpUnnumberedPeerConfig invalidPeer = BgpUnnumberedPeerConfig.builder().setPeerInterface("iface").setLocalIp(LINK_LOCAL_IP).setLocalAs(2L).setIpv4UnicastAddressFamily(Ipv4UnicastAddressFamily.builder().build()).build();
BgpUnnumberedPeerConfig validPeer = BgpUnnumberedPeerConfig.builder().setPeerInterface("iface").setRemoteAs(1L).setLocalIp(LINK_LOCAL_IP).setLocalAs(2L).setIpv4UnicastAddressFamily(Ipv4UnicastAddressFamily.builder().build()).build();
assertFalse(isValidBgpPeerForBorderInterfaceInfo(invalidPeer, ImmutableSet.of(), ImmutableSet.of(), ALL_AS_NUMBERS));
assertTrue(isValidBgpPeerForBorderInterfaceInfo(validPeer, ImmutableSet.of(), ImmutableSet.of(), ALL_AS_NUMBERS));
}
use of org.batfish.datamodel.BgpUnnumberedPeerConfig in project batfish by batfish.
the class IspModelingUtilsTest method testConnectIspToSnapshot_unnumbered.
@Test
public void testConnectIspToSnapshot_unnumbered() {
BgpUnnumberedPeerConfig remotePeerConfig = BgpUnnumberedPeerConfig.builder().setPeerInterface(_snapshotInterfaceName).setRemoteAs(_ispAsn).setLocalIp(LINK_LOCAL_IP).setLocalAs(_snapshotAsn).setIpv4UnicastAddressFamily(Ipv4UnicastAddressFamily.builder().build()).build();
String ispIfaceName = ispToSnapshotInterfaceName(_snapshotHostname, _snapshotInterfaceName);
IspModel ispModel = IspModel.builder().setAsn(_ispAsn).setSnapshotConnections(new SnapshotConnection(ImmutableList.of(new IspInterface(ispIfaceName, LINK_LOCAL_ADDRESS, new Layer1Node(_snapshotHostname, _snapshotInterfaceName), null)), IspBgpUnnumberedPeer.create(remotePeerConfig, ispIfaceName))).build();
Configuration ispConfiguration = createIspNode(ispModel, _logger).get();
Set<Layer1Edge> layer1Edges = connectIspToSnapshot(ispModel, ispConfiguration, _logger);
assertThat(ispConfiguration, allOf(hasInterface(ispToSnapshotInterfaceName(_snapshotHostname, _snapshotInterfaceName), hasAllAddresses(equalTo(ImmutableSet.of(LINK_LOCAL_ADDRESS))))));
// compute the reverse config
BgpProcess bgpProcess = testBgpProcess(Ip.ZERO);
addBgpPeerToIsp(IspBgpUnnumberedPeer.create(remotePeerConfig, ispToSnapshotInterfaceName(_snapshotHostname, _snapshotInterfaceName)), bgpProcess, ispModel.getRole());
BgpUnnumberedPeerConfig expectedIspPeerConfig = getOnlyElement(bgpProcess.getInterfaceNeighbors().values());
assertThat(getOnlyElement(ispConfiguration.getVrfs().get(DEFAULT_VRF_NAME).getBgpProcess().getInterfaceNeighbors().values()), equalTo(expectedIspPeerConfig));
assertThat(ispConfiguration.getRoutingPolicies(), hasKey(EXPORT_POLICY_ON_ISP_TO_CUSTOMERS));
assertThat(layer1Edges, equalTo(ImmutableSet.of(new Layer1Edge(_snapshotHostname, _snapshotInterfaceName, _ispName, ispToSnapshotInterfaceName(_snapshotHostname, _snapshotInterfaceName)), new Layer1Edge(_ispName, ispToSnapshotInterfaceName(_snapshotHostname, _snapshotInterfaceName), _snapshotHostname, _snapshotInterfaceName))));
}
use of org.batfish.datamodel.BgpUnnumberedPeerConfig in project batfish by batfish.
the class BgpSessionCompatibilityAnswerer method getRows.
/**
* Return the answer for {@link BgpSessionCompatibilityQuestion} -- a set of BGP sessions and
* their compatibility.
*/
private List<Row> getRows(NetworkSnapshot snapshot, BgpSessionCompatibilityQuestion question) {
Map<String, Configuration> configurations = _batfish.loadConfigurations(snapshot);
NetworkConfigurations nc = NetworkConfigurations.of(configurations);
SpecifierContext specifierContext = _batfish.specifierContext(snapshot);
Set<String> nodes = question.getNodeSpecifier().resolve(specifierContext);
Set<String> remoteNodes = question.getRemoteNodeSpecifier().resolve(specifierContext);
L3Adjacencies l3Adjacencies = _batfish.getTopologyProvider().getInitialL3Adjacencies(snapshot);
Map<Ip, Map<String, Set<String>>> ipVrfOwners = _batfish.getTopologyProvider().getInitialIpOwners(snapshot).getIpVrfOwners();
ValueGraph<BgpPeerConfigId, BgpSessionProperties> configuredTopology = BgpTopologyUtils.initBgpTopology(configurations, ipVrfOwners, true, l3Adjacencies).getGraph();
// Generate answer row for each BGP peer (or rows, for dynamic peers with multiple remotes)
return configuredTopology.nodes().stream().flatMap(peerId -> {
switch(peerId.getType()) {
case ACTIVE:
BgpActivePeerConfig activePeer = nc.getBgpPointToPointPeerConfig(peerId);
assert activePeer != null;
return Stream.of(getActivePeerRow(peerId, activePeer, ipVrfOwners, configuredTopology));
case DYNAMIC:
BgpPassivePeerConfig passivePeer = nc.getBgpDynamicPeerConfig(peerId);
assert passivePeer != null;
return getPassivePeerRows(peerId, passivePeer, nc, configuredTopology).stream();
case UNNUMBERED:
BgpUnnumberedPeerConfig unnumPeer = nc.getBgpUnnumberedPeerConfig(peerId);
assert unnumPeer != null;
return Stream.of(getUnnumberedPeerRow(peerId, unnumPeer, configuredTopology));
default:
throw new BatfishException(String.format("Unsupported type of BGP peer config: %s", peerId.getType()));
}
}).filter(row -> matchesQuestionFilters(row, nodes, remoteNodes, question)).collect(ImmutableList.toImmutableList());
}
Aggregations