package org.batfish.bdp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.stream.Collectors;
import org.batfish.common.BatfishException;
import org.batfish.common.util.ComparableStructure;
import org.batfish.datamodel.AbstractRoute;
import org.batfish.datamodel.AsPath;
import org.batfish.datamodel.AsSet;
import org.batfish.datamodel.BgpAdvertisement;
import org.batfish.datamodel.BgpNeighbor;
import org.batfish.datamodel.BgpRoute;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.ConnectedRoute;
import org.batfish.datamodel.Edge;
import org.batfish.datamodel.GeneratedRoute;
import org.batfish.datamodel.Interface;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.OriginType;
import org.batfish.datamodel.OspfArea;
import org.batfish.datamodel.OspfExternalRoute;
import org.batfish.datamodel.OspfExternalType1Route;
import org.batfish.datamodel.OspfExternalType2Route;
import org.batfish.datamodel.OspfInterAreaRoute;
import org.batfish.datamodel.OspfIntraAreaRoute;
import org.batfish.datamodel.OspfMetricType;
import org.batfish.datamodel.OspfProcess;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.RouteFilterList;
import org.batfish.datamodel.RoutingProtocol;
import org.batfish.datamodel.StaticRoute;
import org.batfish.datamodel.Topology;
import org.batfish.datamodel.Vrf;
import org.batfish.datamodel.BgpAdvertisement.BgpAdvertisementType;
import org.batfish.datamodel.collections.AdvertisementSet;
import org.batfish.datamodel.collections.CommunitySet;
import org.batfish.datamodel.collections.EdgeSet;
import org.batfish.datamodel.routing_policy.RoutingPolicy;
public class VirtualRouter extends ComparableStructure<String> {
/**
*
*/
private static final long serialVersionUID = 1L;
BgpRib _baseEbgpRib;
BgpRib _baseIbgpRib;
BgpRib _bgpRib;
final Configuration _c;
ConnectedRib _connectedRib;
BgpRib _ebgpRib;
BgpRib _ebgpStagingRib;
Fib _fib;
Rib _generatedRib;
BgpRib _ibgpRib;
BgpRib _ibgpStagingRib;
Rib _independentRib;
Rib _mainRib;
private final Map<String, Node> _nodes;
OspfExternalType1Rib _ospfExternalType1Rib;
OspfExternalType1Rib _ospfExternalType1StagingRib;
OspfExternalType2Rib _ospfExternalType2Rib;
OspfExternalType2Rib _ospfExternalType2StagingRib;
OspfInterAreaRib _ospfInterAreaRib;
OspfInterAreaRib _ospfInterAreaStagingRib;
OspfIntraAreaRib _ospfIntraAreaRib;
OspfIntraAreaRib _ospfIntraAreaStagingRib;
OspfRib _ospfRib;
BgpRib _prevBgpRib;
BgpRib _prevEbgpRib;
BgpRib _prevIbgpRib;
Rib _prevMainRib;
OspfExternalType1Rib _prevOspfExternalType1Rib;
OspfExternalType2Rib _prevOspfExternalType2Rib;
StaticRib _staticInterfaceRib;
StaticRib _staticRib;
final Vrf _vrf;
public VirtualRouter(String name, Configuration c, Map<String, Node> nodes) {
super(name);
_c = c;
_nodes = nodes;
_vrf = c.getVrfs().get(name);
}
public boolean activateGeneratedRoutes() {
boolean changed = false;
for (GeneratedRoute gr : _vrf.getGeneratedRoutes()) {
boolean active = true;
String generationPolicyName = gr.getGenerationPolicy();
GeneratedRoute.Builder grb = new GeneratedRoute.Builder();
grb.setNetwork(gr.getNetwork());
grb.setAdmin(gr.getAdministrativeCost());
grb.setMetric(gr.getMetric() != null ? gr.getMetric() : 0);
grb.setAsPath(new AsPath());
grb.setAttributePolicy(gr.getAttributePolicy());
grb.setGenerationPolicy(gr.getGenerationPolicy());
boolean discard = gr.getDiscard();
grb.setDiscard(discard);
if (discard) {
grb.setNextHopInterface(Interface.NULL_INTERFACE_NAME);
}
if (generationPolicyName != null) {
RoutingPolicy generationPolicy = _c.getRoutingPolicies()
.get(generationPolicyName);
if (generationPolicy != null) {
active = false;
for (AbstractRoute contributingRoute : _prevMainRib
.getRoutes()) {
boolean accept = generationPolicy.process(contributingRoute,
grb, null, _key);
if (accept) {
if (!discard) {
grb.setNextHopIp(contributingRoute.getNextHopIp());
}
active = true;
break;
}
}
}
}
if (active) {
GeneratedRoute newGr = grb.build();
if (_generatedRib.mergeRoute(newGr)) {
changed = true;
}
}
}
return changed;
}
public boolean activateStaticRoutes() {
boolean changed = false;
for (StaticRoute sr : _staticRib.getRoutes()) {
Set<AbstractRoute> matchingRoutes = _prevMainRib
.longestPrefixMatch(sr.getNextHopIp());
Prefix prefix = sr.getNetwork();
for (AbstractRoute matchingRoute : matchingRoutes) {
Prefix matchingRoutePrefix = matchingRoute.getNetwork();
// check to make sure matching route's prefix does not totally
// contain this static route's prefix
if (matchingRoutePrefix.getAddress().asLong() > prefix.getAddress()
.asLong()
|| matchingRoutePrefix.getEndAddress().asLong() < prefix
.getEndAddress().asLong()) {
if (_mainRib.mergeRoute(sr)) {
changed = true;
}
break;
}
}
}
return changed;
}
public void computeFib() {
_fib = new Fib(_mainRib);
}
public boolean computeInterAreaSummaries() {
OspfProcess proc = _vrf.getOspfProcess();
boolean changed = false;
if (proc != null) {
int admin = RoutingProtocol.OSPF_IA
.getSummaryAdministrativeCost(_c.getConfigurationFormat());
for (Entry<Long, OspfArea> e : proc.getAreas().entrySet()) {
long areaNum = e.getKey();
OspfArea area = e.getValue();
for (Entry<Prefix, Boolean> e2 : area.getSummaries().entrySet()) {
Prefix prefix = e2.getKey();
boolean advertise = e2.getValue();
if (advertise) {
Integer metric = null;
for (OspfIntraAreaRoute contributingRoute : _ospfIntraAreaRib
.getRoutes()) {
if (contributingRoute.getArea() != areaNum) {
Prefix contributingRoutePrefix = contributingRoute
.getNetwork();
if (prefix.containsPrefix(contributingRoutePrefix)) {
int contributingRouteMetric = contributingRoute
.getMetric();
if (metric == null) {
metric = contributingRouteMetric;
}
else {
metric = Math.min(metric,
contributingRouteMetric);
}
}
}
}
for (OspfInterAreaRoute contributingRoute : _ospfInterAreaRib
.getRoutes()) {
if (contributingRoute.getArea() != areaNum) {
Prefix contributingRoutePrefix = contributingRoute
.getNetwork();
if (prefix.containsPrefix(contributingRoutePrefix)) {
int contributingRouteMetric = contributingRoute
.getMetric();
if (metric == null) {
metric = contributingRouteMetric;
}
else {
metric = Math.min(metric,
contributingRouteMetric);
}
}
}
}
if (metric != null) {
OspfInterAreaRoute summaryRoute = new OspfInterAreaRoute(
prefix, Ip.ZERO, admin, metric, areaNum);
if (_ospfInterAreaStagingRib.mergeRoute(summaryRoute)) {
changed = true;
}
}
}
}
}
}
return changed;
}
public <U extends AbstractRoute, T extends U> void importRib(
AbstractRib<U> importingRib, AbstractRib<T> exportingRib) {
for (T route : exportingRib.getRoutes()) {
importingRib.mergeRoute(route);
}
}
public void initBaseBgpRibs(AdvertisementSet externalAdverts,
Map<Ip, Set<String>> ipOwners) {
_bgpRib = new BgpRib(this);
_baseEbgpRib = new BgpRib(this);
_baseIbgpRib = new BgpRib(this);
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");
}
BgpRib 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();
CommunitySet communities = advert.getCommunities();
int localPreference = advert.getLocalPreference();
int 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);
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.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());
outgoingRouteBuilder
.setCommunities(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);
// TODO:
// outgoingRouteBuilder.setReceivedFromRouteReflectorClient(...);
outgoingRouteBuilder
.setSrcProtocol(advert.getSrcProtocol());
BgpRoute transformedOutgoingRoute = outgoingRouteBuilder
.build();
BgpRoute.Builder transformedIncomingRouteBuilder = new BgpRoute.Builder();
// Incoming originatorIp
transformedIncomingRouteBuilder.setOriginatorIp(
transformedOutgoingRoute.getOriginatorIp());
// Incoming clusterList
transformedIncomingRouteBuilder.getClusterList()
.addAll(transformedOutgoingRoute.getClusterList());
// Incoming receivedFromRouteReflectorClient
transformedIncomingRouteBuilder
.setReceivedFromRouteReflectorClient(
transformedOutgoingRoute
.getReceivedFromRouteReflectorClient());
// Incoming asPath
transformedIncomingRouteBuilder.getAsPath()
.addAll(transformedOutgoingRoute.getAsPath());
// 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 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();
// TODO: ensure there is always an import policy
if (ebgp
&& transformedOutgoingRoute.getAsPath()
.containsAs(neighbor.getLocalAs())
&& !neighbor.getAllowLocalAsIn()) {
// skip routes containing peer's AS unless
// 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);
}
}
if (acceptIncoming) {
BgpRoute transformedIncomingRoute = transformedIncomingRouteBuilder
.build();
targetRib.mergeRoute(transformedIncomingRoute);
}
}
}
}
}
}
_ebgpRib = new BgpRib(this);
importRib(_ebgpRib, _baseEbgpRib);
_ibgpRib = new BgpRib(this);
importRib(_ibgpRib, _baseIbgpRib);
}
public void initBaseOspfRoutes() {
if (_vrf.getOspfProcess() != null) {
// init intra-area routes from connected routes
_vrf.getOspfProcess().getAreas().forEach((areaNum, area) -> {
for (Interface iface : area.getInterfaces()) {
if (iface.getActive()) {
Set<Prefix> allNetworkPrefixes = iface.getAllPrefixes()
.stream().map(prefix -> prefix.getNetworkPrefix())
.collect(Collectors.toSet());
int cost = iface.getOspfCost();
for (Prefix prefix : allNetworkPrefixes) {
OspfIntraAreaRoute route = new OspfIntraAreaRoute(prefix,
null,
RoutingProtocol.OSPF.getDefaultAdministrativeCost(
_c.getConfigurationFormat()),
cost, areaNum);
_ospfIntraAreaRib.addRoute(route);
}
}
}
});
}
}
public void initBgpAggregateRoutes() {
// first import aggregates
switch (_c.getConfigurationFormat()) {
case JUNIPER:
case JUNIPER_SWITCH:
return;
// $CASES-OMITTED$
default:
break;
}
for (AbstractRoute grAbstract : _generatedRib.getRoutes()) {
GeneratedRoute gr = (GeneratedRoute) grAbstract;
BgpRoute.Builder b = new BgpRoute.Builder();
b.setAdmin(gr.getAdministrativeCost());
b.setAsPath(gr.getAsPath());
b.setMetric(gr.getMetric());
b.setSrcProtocol(RoutingProtocol.AGGREGATE);
b.setProtocol(RoutingProtocol.AGGREGATE);
b.setNetwork(gr.getNetwork());
b.setLocalPreference(BgpRoute.DEFAULT_LOCAL_PREFERENCE);
BgpRoute br = b.build();
br.setNonRouting(true);
_bgpRib.mergeRoute(br);
}
}
public void initConnectedRib() {
for (Interface i : _vrf.getInterfaces().values()) {
if (i.getActive()) {
for (Prefix ifacePrefix : i.getAllPrefixes()) {
Prefix prefix = ifacePrefix.getNetworkPrefix();
ConnectedRoute cr = new ConnectedRoute(prefix, i.getName());
_connectedRib.addRoute(cr);
}
}
}
}
public void initEbgpTopology(BdpDataPlane dp) {
if (_vrf.getBgpProcess() != null) {
for (BgpNeighbor neighbor : _vrf.getBgpProcess().getNeighbors()
.values()) {
if (!neighbor.getRemoteAs().equals(neighbor.getLocalAs())) {
BgpNeighbor remoteNeighbor = neighbor.getRemoteBgpNeighbor();
if (remoteNeighbor != null) {
if (dp.getIpOwners().get(neighbor.getLocalIp())
.contains(_c.getHostname())
&& dp.getIpOwners().get(remoteNeighbor.getLocalIp())
.contains(
remoteNeighbor.getOwner().getHostname())) {
// pretty confident we have a bgp connection here
// for now, just leave it alone
}
else {
neighbor.setRemoteBgpNeighbor(null);
remoteNeighbor.setRemoteBgpNeighbor(null);
}
}
}
}
}
}
public void initIbgpTopology(BdpDataPlane dp) {
// TODO: implement
}
public void initOspfExports() {
if (_vrf.getOspfProcess() != null) {
// init ospf exports
String exportPolicyName = _vrf.getOspfProcess().getExportPolicy();
if (exportPolicyName != null) {
RoutingPolicy exportPolicy = _c.getRoutingPolicies()
.get(exportPolicyName);
if (exportPolicy != null) {
for (AbstractRoute potentialExport : _prevMainRib.getRoutes()) {
OspfExternalRoute.Builder outputRouteBuilder = new OspfExternalRoute.Builder();
boolean accept = exportPolicy.process(potentialExport,
outputRouteBuilder, null, _key);
if (accept) {
outputRouteBuilder.setAdmin(outputRouteBuilder
.getOspfMetricType().toRoutingProtocol()
.getDefaultAdministrativeCost(
_c.getConfigurationFormat()));
outputRouteBuilder
.setNetwork(potentialExport.getNetwork());
outputRouteBuilder.setCostToAdvertiser(0);
OspfExternalRoute outputRoute = outputRouteBuilder.build();
outputRoute.setNonRouting(true);
// shouldn't be null
if (outputRoute.getOspfMetricType() == OspfMetricType.E1) {
_ospfExternalType1Rib
.addRoute((OspfExternalType1Route) outputRoute);
}
else {
_ospfExternalType2Rib
.addRoute((OspfExternalType2Route) outputRoute);
}
}
}
}
}
}
}
public void initRibs() {
_bgpRib = new BgpRib(this);
_connectedRib = new ConnectedRib(this);
_ebgpRib = new BgpRib(this);
_ebgpStagingRib = new BgpRib(this);
_ibgpRib = new BgpRib(this);
_ibgpStagingRib = new BgpRib(this);
_independentRib = new Rib(this);
_mainRib = new Rib(this);
_ospfExternalType1Rib = new OspfExternalType1Rib(this);
_ospfExternalType2Rib = new OspfExternalType2Rib(this);
_ospfExternalType1StagingRib = new OspfExternalType1Rib(this);
_ospfExternalType2StagingRib = new OspfExternalType2Rib(this);
_ospfInterAreaRib = new OspfInterAreaRib(this);
_ospfInterAreaStagingRib = new OspfInterAreaRib(this);
_ospfIntraAreaRib = new OspfIntraAreaRib(this);
_ospfIntraAreaStagingRib = new OspfIntraAreaRib(this);
_ospfRib = new OspfRib(this);
_staticRib = new StaticRib(this);
_staticInterfaceRib = new StaticRib(this);
}
public void initStaticRib() {
for (StaticRoute sr : _vrf.getStaticRoutes()) {
String nextHopInt = sr.getNextHopInterface();
if (nextHopInt != null
&& !Interface.NULL_INTERFACE_NAME.equals(nextHopInt)
&& !_vrf.getInterfaces().get(nextHopInt).getActive()) {
continue;
}
// interface route
if (sr.getNextHopIp() == null) {
_staticInterfaceRib.addRoute(sr);
}
else {
_staticRib.addRoute(sr);
}
}
}
public int propagateBgpRoutes(Map<String, Node> nodes,
Map<Ip, Set<String>> ipOwners) {
int numRoutes = 0;
if (_vrf.getBgpProcess() != null) {
int ebgpAdmin = RoutingProtocol.BGP
.getDefaultAdministrativeCost(_c.getConfigurationFormat());
int ibgpAdmin = RoutingProtocol.IBGP
.getDefaultAdministrativeCost(_c.getConfigurationFormat());
for (BgpNeighbor neighbor : _vrf.getBgpProcess().getNeighbors()
.values()) {
Ip localIp = neighbor.getLocalIp();
Set<String> localIpOwners = ipOwners.get(localIp);
String hostname = _c.getHostname();
if (localIpOwners == null || !localIpOwners.contains(hostname)) {
continue;
}
BgpNeighbor remoteBgpNeighbor = neighbor.getRemoteBgpNeighbor();
if (remoteBgpNeighbor != null) {
int localAs = neighbor.getLocalAs();
int remoteAs = neighbor.getRemoteAs();
Configuration remoteConfig = remoteBgpNeighbor.getOwner();
String remoteHostname = remoteConfig.getHostname();
String remoteVrfName = remoteBgpNeighbor.getVrf();
Vrf remoteVrf = remoteConfig.getVrfs().get(remoteVrfName);
VirtualRouter remoteVirtualRouter = _nodes
.get(remoteHostname)._virtualRouters.get(remoteVrfName);
RoutingPolicy remoteExportPolicy = remoteConfig
.getRoutingPolicies()
.get(remoteBgpNeighbor.getExportPolicy());
boolean ebgp = localAs != remoteAs;
BgpRib targetRib = ebgp ? _ebgpStagingRib : _ibgpStagingRib;
RoutingProtocol targetProtocol = ebgp ? RoutingProtocol.BGP
: RoutingProtocol.IBGP;
List<AbstractRoute> remoteCandidateRoutes = new ArrayList<>();
remoteCandidateRoutes
.addAll(remoteVirtualRouter._prevMainRib.getRoutes());
// bgp advertise-external
if (!ebgp && remoteBgpNeighbor.getAdvertiseExternal()) {
remoteCandidateRoutes
.addAll(remoteVirtualRouter._prevEbgpRib.getRoutes());
}
// bgp advertise-inactive
if (remoteBgpNeighbor.getAdvertiseInactive()) {
remoteCandidateRoutes
.addAll(remoteVirtualRouter._prevBgpRib.getRoutes());
}
for (AbstractRoute remoteRoute : remoteCandidateRoutes) {
BgpRoute.Builder transformedOutgoingRouteBuilder = new BgpRoute.Builder();
RoutingProtocol remoteRouteProtocol = remoteRoute
.getProtocol();
boolean remoteRouteIsBgp = remoteRouteProtocol == RoutingProtocol.IBGP
|| remoteRouteProtocol == RoutingProtocol.BGP;
// originatorIP
Ip originatorIp = null;
if (!ebgp) {
Ip remoteOriginatorIp = null;
if (remoteRouteIsBgp) {
BgpRoute bgpRemoteRoute = (BgpRoute) remoteRoute;
remoteOriginatorIp = bgpRemoteRoute.getOriginatorIp();
}
if (remoteRouteProtocol.equals(RoutingProtocol.IBGP)) {
originatorIp = remoteOriginatorIp;
}
else {
originatorIp = remoteVrf.getBgpProcess().getRouterId();
}
}
transformedOutgoingRouteBuilder.setOriginatorIp(originatorIp);
// clusterList, receivedFromRouteReflectorClient
if (remoteRouteIsBgp) {
BgpRoute bgpRemoteRoute = (BgpRoute) remoteRoute;
if (ebgp
&& bgpRemoteRoute.getAsPath()
.containsAs(remoteBgpNeighbor.getRemoteAs())
&& !remoteBgpNeighbor.getAllowRemoteAsOut()) {
// skip routes containing peer's AS unless
// disable-peer-as-check (getAllowRemoteAsOut) is set
continue;
}
/*
* route reflection: reflect everything received from
* clients to clients and non-clients. reflect everything
* received from non-clients to clients. Do not reflect to
* originator
*/
Ip remoteOriginatorIp = bgpRemoteRoute.getOriginatorIp();
// don't accept routes whose originator ip is my BGP id
if (remoteOriginatorIp != null && _vrf.getBgpProcess()
.getRouterId().equals(remoteOriginatorIp)) {
continue;
}
if (remoteRouteProtocol.equals(RoutingProtocol.IBGP)
&& !ebgp) {
boolean remoteRouteReceivedFromRouteReflectorClient = bgpRemoteRoute
.getReceivedFromRouteReflectorClient();
boolean sendingToRouteReflectorClient = remoteBgpNeighbor
.getRouteReflectorClient();
boolean newRouteReceivedFromRouteReflectorClient = neighbor
.getRouteReflectorClient();
transformedOutgoingRouteBuilder
.setReceivedFromRouteReflectorClient(
newRouteReceivedFromRouteReflectorClient);
transformedOutgoingRouteBuilder.getClusterList()
.addAll(bgpRemoteRoute.getClusterList());
if (!remoteRouteReceivedFromRouteReflectorClient
&& !sendingToRouteReflectorClient) {
continue;
}
if (sendingToRouteReflectorClient) {
// sender adds its local cluster id to clusterlist of
// new route
transformedOutgoingRouteBuilder.getClusterList()
.add(remoteBgpNeighbor.getClusterId());
}
if (transformedOutgoingRouteBuilder.getClusterList()
.contains(neighbor.getClusterId())) {
// receiver will reject new route if it contains its
// local cluster id
continue;
}
}
}
// Outgoing asPath
// Outgoing communities
if (remoteRouteIsBgp) {
BgpRoute bgpRemoteRoute = (BgpRoute) remoteRoute;
transformedOutgoingRouteBuilder.getAsPath()
.addAll(bgpRemoteRoute.getAsPath());
if (remoteBgpNeighbor.getSendCommunity()) {
transformedOutgoingRouteBuilder.getCommunities()
.addAll(bgpRemoteRoute.getCommunities());
}
}
if (ebgp) {
AsSet newAsPathElement = new AsSet();
newAsPathElement.add(remoteAs);
transformedOutgoingRouteBuilder.getAsPath().add(0,
newAsPathElement);
}
// Outgoing protocol
transformedOutgoingRouteBuilder.setProtocol(targetProtocol);
transformedOutgoingRouteBuilder
.setNetwork(remoteRoute.getNetwork());
// Outgoing metric
if (remoteRouteIsBgp) {
transformedOutgoingRouteBuilder
.setMetric(remoteRoute.getMetric());
}
// Outgoing nextHopIp
// Outgoing localPreference
Ip nextHopIp;
int localPreference;
if (ebgp || !remoteRouteIsBgp) {
nextHopIp = remoteBgpNeighbor.getLocalIp();
localPreference = BgpRoute.DEFAULT_LOCAL_PREFERENCE;
}
else {
nextHopIp = remoteRoute.getNextHopIp();
BgpRoute remoteIbgpRoute = (BgpRoute) remoteRoute;
localPreference = remoteIbgpRoute.getLocalPreference();
}
if (nextHopIp == null) {
// should only happen for ibgp
String nextHopInterface = remoteRoute
.getNextHopInterface();
Prefix nextHopPrefix = remoteVrf.getInterfaces()
.get(nextHopInterface).getPrefix();
if (nextHopPrefix == null) {
throw new BatfishException(
"remote route's nextHopInterface has no address");
}
nextHopIp = nextHopPrefix.getAddress();
}
transformedOutgoingRouteBuilder.setNextHopIp(nextHopIp);
transformedOutgoingRouteBuilder
.setLocalPreference(localPreference);
// Outgoing srcProtocol
transformedOutgoingRouteBuilder
.setSrcProtocol(remoteRoute.getProtocol());
/*
* CREATE OUTGOING ROUTE
*/
boolean acceptOutgoing = remoteExportPolicy.process(
remoteRoute, transformedOutgoingRouteBuilder, localIp,
remoteVrfName);
if (acceptOutgoing) {
BgpRoute transformedOutgoingRoute = transformedOutgoingRouteBuilder
.build();
BgpRoute.Builder transformedIncomingRouteBuilder = new BgpRoute.Builder();
// Incoming originatorIp
transformedIncomingRouteBuilder.setOriginatorIp(
transformedOutgoingRoute.getOriginatorIp());
// Incoming clusterList
transformedIncomingRouteBuilder.getClusterList()
.addAll(transformedOutgoingRoute.getClusterList());
// Incoming receivedFromRouteReflectorClient
transformedIncomingRouteBuilder
.setReceivedFromRouteReflectorClient(
transformedOutgoingRoute
.getReceivedFromRouteReflectorClient());
// Incoming asPath
transformedIncomingRouteBuilder.getAsPath()
.addAll(transformedOutgoingRoute.getAsPath());
// Incoming communities
transformedIncomingRouteBuilder.getCommunities()
.addAll(transformedOutgoingRoute.getCommunities());
// Incoming protocol
transformedIncomingRouteBuilder
.setProtocol(targetProtocol);
// Incoming network
transformedIncomingRouteBuilder
.setNetwork(remoteRoute.getNetwork());
// Incoming nextHopIp
if (ebgp) {
transformedIncomingRouteBuilder.setNextHopIp(nextHopIp);
}
else {
transformedIncomingRouteBuilder.setNextHopIp(
transformedOutgoingRoute.getNextHopIp());
}
// 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();
// TODO: ensure there is always an import policy
if (ebgp
&& transformedOutgoingRoute.getAsPath()
.containsAs(neighbor.getLocalAs())
&& !neighbor.getAllowLocalAsIn()) {
// skip routes containing peer's AS unless
// 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,
remoteBgpNeighbor.getLocalIp(), _key);
}
}
if (acceptIncoming) {
BgpRoute transformedIncomingRoute = transformedIncomingRouteBuilder
.build();
if (targetRib.mergeRoute(transformedIncomingRoute)) {
numRoutes++;
}
}
}
}
}
}
}
return numRoutes;
}
public boolean propagateOspfExternalRoutes(Map<String, Node> nodes,
Topology topology) {
boolean changed = false;
String node = _c.getHostname();
if (_vrf.getOspfProcess() != null) {
int admin = RoutingProtocol.OSPF
.getDefaultAdministrativeCost(_c.getConfigurationFormat());
EdgeSet edges = topology.getNodeEdges().get(node);
if (edges == null) {
// there are no edges, so OSPF won't produce anything
return false;
}
for (Edge edge : edges) {
if (!edge.getNode1().equals(node)) {
continue;
}
String connectingInterfaceName = edge.getInt1();
Interface connectingInterface = _vrf.getInterfaces()
.get(connectingInterfaceName);
if (connectingInterface == null) {
// wrong vrf, so skip
continue;
}
String neighborName = edge.getNode2();
Node neighbor = nodes.get(neighborName);
String neighborInterfaceName = edge.getInt2();
OspfArea area = connectingInterface.getOspfArea();
Configuration nc = neighbor._c;
Interface neighborInterface = nc.getInterfaces()
.get(neighborInterfaceName);
String neighborVrfName = neighborInterface.getVrfName();
VirtualRouter neighborVirtualRouter = _nodes
.get(neighborName)._virtualRouters.get(neighborVrfName);
OspfArea neighborArea = neighborInterface.getOspfArea();
if (connectingInterface.getOspfEnabled()
&& !connectingInterface.getOspfPassive()
&& neighborInterface.getOspfEnabled()
&& !neighborInterface.getOspfPassive() && area != null
&& neighborArea != null) {
/*
* We have an ospf neighbor relationship on this edge. So we
* should add all ospf external type 1(2) routes from this
* neighbor into our ospf external type 1(2) staging rib. For
* type 1, the cost of the route increases each time. For type 2,
* the cost remains constant, but we must keep track of cost to
* advertiser as a tie-breaker.
*/
int connectingInterfaceCost = connectingInterface.getOspfCost();
for (OspfExternalType1Route neighborRoute : neighborVirtualRouter._prevOspfExternalType1Rib
.getRoutes()) {
int newMetric = neighborRoute.getMetric()
+ connectingInterfaceCost;
OspfExternalType1Route newRoute = new OspfExternalType1Route(
neighborRoute.getNetwork(),
neighborInterface.getPrefix().getAddress(), admin,
newMetric, neighborRoute.getAdvertiser());
if (_ospfExternalType1StagingRib.mergeRoute(newRoute)) {
changed = true;
}
}
for (OspfExternalType2Route neighborRoute : neighborVirtualRouter._prevOspfExternalType2Rib
.getRoutes()) {
int newCostToAdvertiser = neighborRoute.getCostToAdvertiser()
+ connectingInterfaceCost;
OspfExternalType2Route newRoute = new OspfExternalType2Route(
neighborRoute.getNetwork(),
neighborInterface.getPrefix().getAddress(), admin,
neighborRoute.getMetric(), newCostToAdvertiser,
neighborRoute.getAdvertiser());
if (_ospfExternalType2StagingRib.mergeRoute(newRoute)) {
changed = true;
}
}
}
}
}
return changed;
}
public boolean propagateOspfInternalRoutes(Map<String, Node> nodes,
Topology topology) {
boolean changed = false;
String node = _c.getHostname();
if (_vrf.getOspfProcess() != null) {
int admin = RoutingProtocol.OSPF
.getDefaultAdministrativeCost(_c.getConfigurationFormat());
EdgeSet edges = topology.getNodeEdges().get(node);
if (edges == null) {
// there are no edges, so OSPF won't produce anything
return false;
}
for (Edge edge : edges) {
if (!edge.getNode1().equals(node)) {
continue;
}
String connectingInterfaceName = edge.getInt1();
Interface connectingInterface = _vrf.getInterfaces()
.get(connectingInterfaceName);
if (connectingInterface == null) {
// wrong vrf, so skip
continue;
}
String neighborName = edge.getNode2();
Node neighbor = nodes.get(neighborName);
String neighborInterfaceName = edge.getInt2();
OspfArea area = connectingInterface.getOspfArea();
Configuration nc = neighbor._c;
Interface neighborInterface = nc.getInterfaces()
.get(neighborInterfaceName);
String neighborVrfName = neighborInterface.getVrfName();
VirtualRouter neighborVirtualRouter = _nodes
.get(neighborName)._virtualRouters.get(neighborVrfName);
OspfArea neighborArea = neighborInterface.getOspfArea();
if (connectingInterface.getOspfEnabled()
&& !connectingInterface.getOspfPassive()
&& neighborInterface.getOspfEnabled()
&& !neighborInterface.getOspfPassive() && area != null
&& neighborArea != null) {
if (area.getName().equals(neighborArea.getName())) {
/*
* We have an ospf intra-area neighbor relationship on this
* edge. So we should add all ospf routes from this neighbor
* into our ospf intra-area staging rib, adding the cost of
* the connecting interface, and using the neighborInterface's
* address as the next hop ip
*/
int connectingInterfaceCost = connectingInterface
.getOspfCost();
long areaNum = area.getName();
for (OspfIntraAreaRoute neighborRoute : neighborVirtualRouter._ospfIntraAreaRib
.getRoutes()) {
int newCost = neighborRoute.getMetric()
+ connectingInterfaceCost;
Ip nextHopIp = neighborInterface.getPrefix().getAddress();
OspfIntraAreaRoute newRoute = new OspfIntraAreaRoute(
neighborRoute.getNetwork(), nextHopIp, admin,
newCost, areaNum);
if (_ospfIntraAreaStagingRib.mergeRoute(newRoute)) {
changed = true;
}
}
// we also propagate inter-area routes that have already made
// it into this area, unless they originate in this area
for (OspfInterAreaRoute neighborRoute : neighborVirtualRouter._ospfInterAreaRib
.getRoutes()) {
long neighborRouteArea = neighborRoute.getArea();
if (neighborRouteArea != areaNum) {
Prefix neighborRouteNetwork = neighborRoute
.getNetwork();
String neighborSummaryFilterName = neighborArea
.getSummaryFilter();
boolean hasSummaryFilter = neighborSummaryFilterName != null;
boolean allowed = !hasSummaryFilter;
if (hasSummaryFilter) {
RouteFilterList neighborSummaryFilter = neighbor._c
.getRouteFilterLists()
.get(neighborSummaryFilterName);
allowed = neighborSummaryFilter
.permits(neighborRouteNetwork);
}
if (allowed) {
int newCost = neighborRoute.getMetric()
+ connectingInterfaceCost;
Ip nextHopIp = neighborInterface.getPrefix()
.getAddress();
OspfInterAreaRoute newRoute = new OspfInterAreaRoute(
neighborRouteNetwork, nextHopIp, admin,
newCost, areaNum);
if (_ospfInterAreaStagingRib.mergeRoute(newRoute)) {
changed = true;
}
}
}
}
}
else if (area.getName().equals(0l)
|| neighborArea.getName().equals(0l)) {
/*
* We have an ospf inter-area neighbor relationship on this
* edge. So we should add all ospf routes from this neighbor
* into our ospf inter-area staging rib, adding the cost of
* the connecting interface, and using the neighborInterface's
* address as the next hop ip
*
*/
int connectingInterfaceCost = connectingInterface
.getOspfCost();
long areaNum = area.getName();
// inter-area routes can only be sent FROM area 0 when sender
// is in different area, unless the route is from the
// neighbor's area
for (OspfInterAreaRoute neighborRoute : neighborVirtualRouter._ospfInterAreaRib
.getRoutes()) {
// do not receive inter-area routes that originally came
// from this area
long neighborRouteArea = neighborRoute.getArea();
if (areaNum != neighborRouteArea
&& (neighborArea.getName().equals(0l) || neighborArea
.getName().equals(neighborRouteArea))) {
Prefix neighborRouteNetwork = neighborRoute
.getNetwork();
String neighborSummaryFilterName = neighborArea
.getSummaryFilter();
boolean hasSummaryFilter = neighborSummaryFilterName != null;
boolean allowed = !hasSummaryFilter;
if (hasSummaryFilter) {
RouteFilterList neighborSummaryFilter = neighbor._c
.getRouteFilterLists()
.get(neighborSummaryFilterName);
allowed = neighborSummaryFilter
.permits(neighborRouteNetwork);
}
if (allowed) {
int newCost = neighborRoute.getMetric()
+ connectingInterfaceCost;
Ip nextHopIp = neighborInterface.getPrefix()
.getAddress();
OspfIntraAreaRoute newRoute = new OspfIntraAreaRoute(
neighborRouteNetwork, nextHopIp, admin,
newCost, areaNum);
if (_ospfIntraAreaStagingRib.mergeRoute(newRoute)) {
changed = true;
}
}
}
}
// intra-area routes may be turned into inter-area routes
// going either to or from area 0
for (OspfInterAreaRoute neighborRoute : neighborVirtualRouter._ospfInterAreaRib
.getRoutes()) {
String neighborSummaryFilterName = neighborArea
.getSummaryFilter();
boolean hasSummaryFilter = neighborSummaryFilterName != null;
boolean allowed = !hasSummaryFilter;
Prefix neighborRouteNetwork = neighborRoute.getNetwork();
if (hasSummaryFilter) {
RouteFilterList neighborSummaryFilter = neighbor._c
.getRouteFilterLists()
.get(neighborSummaryFilterName);
allowed = neighborSummaryFilter
.permits(neighborRouteNetwork);
}
if (allowed) {
int newCost = neighborRoute.getMetric()
+ connectingInterfaceCost;
Ip nextHopIp = neighborInterface.getPrefix()
.getAddress();
OspfInterAreaRoute newRoute = new OspfInterAreaRoute(
neighborRouteNetwork, nextHopIp, admin, newCost,
areaNum);
if (_ospfInterAreaStagingRib.mergeRoute(newRoute)) {
changed = true;
}
}
}
}
}
}
}
return changed;
}
public void unstageBgpRoutes() {
for (BgpRoute route : _ebgpStagingRib.getRoutes()) {
_ebgpRib.mergeRoute(route);
}
for (BgpRoute route : _ibgpStagingRib.getRoutes()) {
_ibgpRib.mergeRoute(route);
}
}
public void unstageOspfExternalRoutes() {
for (OspfExternalType1Route route : _ospfExternalType1StagingRib
.getRoutes()) {
_ospfExternalType1Rib.mergeRoute(route);
}
for (OspfExternalType2Route route : _ospfExternalType2StagingRib
.getRoutes()) {
_ospfExternalType2Rib.mergeRoute(route);
}
}
public void unstageOspfInternalRoutes() {
for (OspfIntraAreaRoute route : _ospfIntraAreaStagingRib.getRoutes()) {
_ospfIntraAreaRib.mergeRoute(route);
}
for (OspfInterAreaRoute route : _ospfInterAreaStagingRib.getRoutes()) {
_ospfInterAreaRib.mergeRoute(route);
}
}
}