<groupId>${project.groupId}</groupId>
<artifactId>bgp-inet</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>bgp-route-target</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>bgp-parser-api</artifactId>
}, MoreExecutors.directExecutor());
}
+ public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
+ R extends Route & ChildOf<? super S> & Identifiable<I>,
+ I extends Identifier<R>> void reEvaluateAdvertizement(
+ final RouteEntryDependenciesContainer entryDep,
+ List<ActualBestPathRoutes<C, S, R, I>> routesToStore) {
+ if (this.bindingChain == null) {
+ LOG.debug("Session closed, skip changes to peer AdjRibsOut {}", getPeerId());
+ return;
+ }
+
+ final RIBSupport<C,S,R,I> ribSupport = entryDep.getRIBSupport();
+ final TablesKey tk = entryDep.getRIBSupport().getTablesKey();
+ final boolean addPathSupported = supportsAddPathSupported(tk);
+
+ final WriteTransaction tx = this.bindingChain.newWriteOnlyTransaction();
+ for(final ActualBestPathRoutes<C,S,R,I> actualBestRoute :routesToStore) {
+ final PeerId fromPeerId = actualBestRoute.getFromPeerId();
+ final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
+ if (!filterRoutes(fromPeerId, ribSupport.getTablesKey())) {
+ continue;
+ }
+ final R route = actualBestRoute.getRoute();
+
+ final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer, this);
+ final Optional<Attributes> effAttr = entryDep.getRoutingPolicies()
+ .applyExportPolicies(routeEntry, actualBestRoute.getAttributes(), entryDep.getAfiSafType());
+ final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
+ if (effAttr.isPresent()) {
+ storeRoute(ribSupport, addPathSupported, tableRibout, actualBestRoute, route, effAttr.get(), tx);
+ } else {
+ final InstanceIdentifier<R> ribOut;
+ if (!addPathSupported) {
+ ribOut = ribSupport.createRouteIdentifier(tableRibout,
+ actualBestRoute.getNonAddPathRouteKeyIdentifier());
+ } else {
+ ribOut = ribSupport.createRouteIdentifier(tableRibout,
+ actualBestRoute.getAddPathRouteKeyIdentifier());
+ }
+ LOG.debug("Write advRoute {} to peer AdjRibsOut {}", actualBestRoute, getPeerId());
+ tx.delete(LogicalDatastoreType.OPERATIONAL, ribOut);
+ }
+ }
+
+ final FluentFuture<? extends CommitInfo> future = tx.commit();
+ this.submitted = future;
+ future.addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ LOG.trace("Successful update commit");
+ }
+
+ @Override
+ public void onFailure(final Throwable trw) {
+ LOG.error("Failed update commit", trw);
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
private <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>>
void installRouteRibOut(final RouteEntryDependenciesContainer entryDep,
this.adjRibInWriter = this.adjRibInWriter.transform(this.peerId, this.peerPath, context, localTables,
Collections.emptyMap(), registerAppPeerListener);
this.effectiveRibInWriter = new EffectiveRibInWriter(this, this.rib,
- this.rib.createPeerChain(this), this.peerIId, localTables, this.tableTypeRegistry
- );
+ this.rib.createPeerChain(this), this.peerIId, localTables, this.tableTypeRegistry,
+ Collections.emptyList());
this.effectiveRibInWriter.init();
this.bgpSessionState.registerMessagesCounter(this);
this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this);
this.tables = ImmutableSet.copyOf(setTables);
this.effRibInWriter = new EffectiveRibInWriter(this, this.rib,
this.rib.createPeerChain(this),
- peerIId, this.tables, this.tableTypeRegistry);
+ peerIId, this.tables, this.tableTypeRegistry, rtMemberships);
registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
this.peerRibOutIId = peerIId.child(AdjRibOut.class);
this.effRibInWriter.init();
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
+import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesInstalledCounters;
import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesReceivedCounters;
import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv4AddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv6AddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.MplsLabeledVpnSubsequentAddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.RouteTarget;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.ChoiceIn;
private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
static final NodeIdentifier TABLE_ROUTES = new NodeIdentifier(Routes.QNAME);
-
+ private static final TablesKey IVP4_VPN_TABLE_KEY = new TablesKey(Ipv4AddressFamily.class,
+ MplsLabeledVpnSubsequentAddressFamily.class);
+ private static final TablesKey IVP6_VPN_TABLE_KEY = new TablesKey(Ipv6AddressFamily.class,
+ MplsLabeledVpnSubsequentAddressFamily.class);
private final RIBSupportContextRegistry registry;
private final KeyedInstanceIdentifier<Peer, PeerKey> peerIId;
private final InstanceIdentifier<EffectiveRibIn> effRibTables;
private final DataBroker databroker;
+ private final List<RouteTarget> rtMemberships;
+ private final RibOutRefresh vpnTableRefresher;
private ListenerRegistration<?> reg;
private BindingTransactionChain chain;
private final Map<TablesKey, LongAdder> prefixesReceived;
private final BGPTableTypeRegistryConsumer tableTypeRegistry;
@GuardedBy("this")
private FluentFuture<? extends CommitInfo> submitted;
+ private boolean rtMembershipsUpdated;
EffectiveRibInWriter(
final BGPRouteEntryImportParameters peer,
final BindingTransactionChain chain,
final KeyedInstanceIdentifier<Peer, PeerKey> peerIId,
final Set<TablesKey> tables,
- final BGPTableTypeRegistryConsumer tableTypeRegistry
- ) {
+ final BGPTableTypeRegistryConsumer tableTypeRegistry,
+ final List<RouteTarget> rtMemberships) {
this.registry = requireNonNull(rib.getRibSupportContext());
this.chain = requireNonNull(chain);
this.peerIId = requireNonNull(peerIId);
this.databroker = requireNonNull(rib.getDataBroker());
this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
this.peerImportParameters = peer;
+ this.rtMemberships = rtMemberships;
+ this.vpnTableRefresher = rib;
}
public void init() {
}
}, MoreExecutors.directExecutor());
}
+
+ //Refresh VPN Table if RT Memberships were updated
+ if (this.rtMembershipsUpdated) {
+ this.vpnTableRefresher.refreshTable(IVP4_VPN_TABLE_KEY, this.peerImportParameters.getFromPeerId());
+ this.vpnTableRefresher.refreshTable(IVP6_VPN_TABLE_KEY, this.peerImportParameters.getFromPeerId());
+ this.rtMembershipsUpdated = false;
+ }
}
@SuppressWarnings("unchecked")
.applyImportPolicies(this.peerImportParameters, route.getAttributes(),
tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey()).get());
if (effAtt.isPresent()) {
+ final Optional<RouteTarget> rtMembership = RouteTargetMembeshipUtil.getRT(route);
+ if (rtMembership.isPresent()) {
+ this.rtMemberships.add(rtMembership.get());
+ this.rtMembershipsUpdated = true;
+ }
CountersUtil.increment(this.prefixesInstalled.get(tk), tk);
tx.put(LogicalDatastoreType.OPERATIONAL, routeIID, route);
tx.put(LogicalDatastoreType.OPERATIONAL, routeIID.child(Attributes.class), effAtt.get());
} else {
+ final Optional<RouteTarget> rtMembership = RouteTargetMembeshipUtil.getRT(route);
+ if (rtMembership.isPresent()) {
+ this.rtMemberships.remove(rtMembership.get());
+ this.rtMembershipsUpdated = true;
+ }
tx.delete(LogicalDatastoreType.OPERATIONAL, routeIID);
}
}
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
import org.opendaylight.protocol.bgp.mode.api.RouteEntry;
+import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
import org.opendaylight.protocol.bgp.rib.impl.state.rib.TotalPathsCounter;
import org.opendaylight.protocol.bgp.rib.impl.state.rib.TotalPrefixesCounter;
import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.AfiSafiType;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
@NotThreadSafe
final class LocRibWriter<C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>>
- implements AutoCloseable, TotalPrefixesCounter, TotalPathsCounter,
+ implements AutoCloseable, RibOutRefresh, TotalPrefixesCounter, TotalPathsCounter,
ClusteredDataTreeChangeListener<Tables> {
private static final Logger LOG = LoggerFactory.getLogger(LocRibWriter.class);
}
@SuppressWarnings("unchecked")
- private Map<RouteUpdateKey, RouteEntry<C,S,R,I>> update(final WriteTransaction tx,
+ private Map<RouteUpdateKey, RouteEntry<C, S, R, I>> update(final WriteTransaction tx,
final Collection<DataTreeModification<Tables>> changes) {
- final Map<RouteUpdateKey, RouteEntry<C,S,R,I>> ret = new HashMap<>();
+ final Map<RouteUpdateKey, RouteEntry<C, S, R, I>> ret = new HashMap<>();
for (final DataTreeModification<Tables> tc : changes) {
final DataObjectModification<Tables> table = tc.getRootNode();
final DataTreeIdentifier<Tables> rootPath = tc.getRootPath();
= this.peerTracker.getPeer(peerKIid.getKey().getPeerId());
if (toPeer != null && toPeer.supportsTable(this.entryDep.getLocalTablesKey())) {
LOG.debug("Peer {} table has been created, inserting existent routes", toPeer.getPeerId());
- final List<ActualBestPathRoutes<C,S,R,I>> routesToStore = new ArrayList<>();
- for (final Map.Entry<String, RouteEntry<C,S,R,I>> entry:this.routeEntries.entrySet()) {
- final List<ActualBestPathRoutes<C,S,R,I>> filteredRoute = entry.getValue()
+ final List<ActualBestPathRoutes<C, S, R, I>> routesToStore = new ArrayList<>();
+ for (final Map.Entry<String, RouteEntry<C, S, R, I>> entry : this.routeEntries.entrySet()) {
+ final List<ActualBestPathRoutes<C, S, R, I>> filteredRoute = entry.getValue()
.actualBestPaths(this.ribSupport, new RouteEntryInfoImpl(toPeer, entry.getKey()));
routesToStore.addAll(filteredRoute);
}
TablesKey getTableKey() {
return this.tk;
}
+
+ @Override
+ public synchronized void refreshTable(final TablesKey tk, final PeerId peerId) {
+ final org.opendaylight.protocol.bgp.rib.spi.Peer toPeer = this.peerTracker.getPeer(peerId);
+ if (toPeer != null && toPeer.supportsTable(this.entryDep.getLocalTablesKey())) {
+ LOG.debug("Peer {} table has been created, inserting existent routes", toPeer.getPeerId());
+ final List<ActualBestPathRoutes<C, S, R, I>> routesToStore = new ArrayList<>();
+ for (final Map.Entry<String, RouteEntry<C, S, R, I>> entry : this.routeEntries.entrySet()) {
+ final List<ActualBestPathRoutes<C, S, R, I>> filteredRoute = entry.getValue()
+ .actualBestPaths(this.ribSupport, new RouteEntryInfoImpl(toPeer, entry.getKey()));
+ routesToStore.addAll(filteredRoute);
+ }
+ toPeer.reEvaluateAdvertizement(this.entryDep, routesToStore);
+ }
+ }
}
import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
+import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
private DOMTransactionChain domChain;
@GuardedBy("this")
private boolean isServiceInstantiated;
+ private Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
public RIBImpl(
final BGPTableTypeRegistryConsumer tableTypeRegistry,
this.ribPolicies,
this.peerTracker,
pathSelectionStrategy);
+ this.vpnTableRefresher.put(key, locRibWriter);
registerTotalPathCounter(key, locRibWriter);
registerTotalPrefixesCounter(key, locRibWriter);
this.txChainToLocRibWriter.put(txChain, locRibWriter);
return this.peerTracker;
}
+ @Override
+ public void refreshTable(final TablesKey tk, final PeerId peerId) {
+ this.vpnTableRefresher.get(tk).refreshTable(tk, peerId);
+ }
+
@Override
public DOMDataTreeChangeService getService() {
return (DOMDataTreeChangeService) this.domService;
--- /dev/null
+/*
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.protocol.bgp.rib.impl;
+
+import java.util.Optional;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.RouteTargetConstrainChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.route.target.constrain.choice.RouteTargetConstrainAs4ExtendedCommunityCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.route.target.constrain.choice.RouteTargetConstrainDefaultCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.route.target.constrain.choice.RouteTargetConstrainIpv4RouteCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.route.target.constrain.choice.RouteTargetConstrainRouteCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.routes.route.target.constrain.routes.RouteTargetConstrainRoute;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.RouteTarget;
+
+/**
+ * @author Claudio D. Gasparini
+ */
+public final class RouteTargetMembeshipUtil {
+ private RouteTargetMembeshipUtil() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static <R extends Route> Optional<RouteTarget> getRT(final R route) {
+ if (!(route instanceof RouteTargetConstrainRoute)) {
+ return Optional.empty();
+ }
+
+ final RouteTargetConstrainChoice rtc = ((RouteTargetConstrainRoute) route).getRouteTargetConstrainChoice();
+ RouteTarget rt;
+ if (rtc instanceof RouteTargetConstrainDefaultCase) {
+ rt = ((RouteTargetConstrainDefaultCase) rtc).getRouteTargetConstrainDefaultRoute();
+ } else if (rtc instanceof RouteTargetConstrainAs4ExtendedCommunityCase) {
+ rt = ((RouteTargetConstrainAs4ExtendedCommunityCase) rtc).getAs4RouteTargetExtendedCommunity();
+ } else if (rtc instanceof RouteTargetConstrainIpv4RouteCase) {
+ rt = ((RouteTargetConstrainIpv4RouteCase) rtc).getRouteTargetIpv4();
+ } else {
+ rt = ((RouteTargetConstrainRouteCase) rtc).getRouteTargetExtendedCommunity();
+ }
+ return Optional.of(rt);
+ }
+}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
this.ribImpl.instantiateServiceInstance();
}
}
+
+ @Override
+ public void refreshTable(final TablesKey tk, final PeerId peerId) {
+ this.ribImpl.refreshTable(tk, peerId);
+ }
}
/**
* Internal reference to a RIB instance.
*/
-public interface RIB extends RibReference {
+public interface RIB extends RibReference, RibOutRefresh {
/**
* RIB AS.
*
--- /dev/null
+/*
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.protocol.bgp.rib.impl.spi;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
+
+/**
+ * Forces a reevaluation of paths and update on peer ribout.
+ */
+public interface RibOutRefresh {
+ /**
+ * Triggers the reevaluation.
+ *
+ * @param tk table key of table route paths to be reevaluated
+ * @param peerId peer to advertize / withdraw paths after reevaluation
+ */
+ void refreshTable(TablesKey tk, PeerId peerId);
+}
I extends Identifier<R>> void initializeRibOut(
@Nonnull RouteEntryDependenciesContainer entryDep,
@Nonnull List<ActualBestPathRoutes<C, S, R, I>> routes);
+
+ /**
+ * Applies all policies through all present routes, and advertize/withdraws based on new results.
+ * Scenario would be for example a removal of RT membership. And reprocess VPN routes.
+ *
+ * @param entryDep RouteEntryDependenciesContainer
+ * @param routes routes to be updated.
+ */
+ <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
+ R extends Route & ChildOf<? super S> & Identifiable<I>,
+ I extends Identifier<R>> void reEvaluateAdvertizement(@Nonnull RouteEntryDependenciesContainer entryDep,
+ @Nonnull List<ActualBestPathRoutes<C, S, R, I>> routes);
}