import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils;
import org.opendaylight.protocol.bgp.rib.spi.Peer;
import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.protocol.bgp.rib.spi.entry.AbstractAdvertizedRoute;
import org.opendaylight.protocol.bgp.rib.spi.entry.ActualBestPathRoutes;
import org.opendaylight.protocol.bgp.rib.spi.entry.AdvertizedRoute;
import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryDependenciesContainer;
@Nullable final AsNumber localAs,
final IpAddress neighborAddress,
final Set<TablesKey> afiSafisAdvertized,
- final Set<TablesKey> afiSafisGracefulAdvertized) {
- super(rib.getInstanceIdentifier(), groupId, neighborAddress, afiSafisAdvertized, afiSafisGracefulAdvertized);
+ final Set<TablesKey> afiSafisGracefulAdvertized,
+ final Map<TablesKey, Integer> afiSafisLlGracefulAdvertized) {
+ super(rib.getInstanceIdentifier(), groupId, neighborAddress, afiSafisAdvertized, afiSafisGracefulAdvertized,
+ afiSafisLlGracefulAdvertized);
this.name = peerName;
this.peerRole = role;
this.clusterId = clusterId;
final IpAddress neighborAddress,
final Set<TablesKey> afiSafisGracefulAdvertized) {
this(rib, peerName, groupId, role, null, null, neighborAddress,
- rib.getLocalTablesKeys(), afiSafisGracefulAdvertized);
+ rib.getLocalTablesKeys(), afiSafisGracefulAdvertized, Collections.emptyMap());
}
final synchronized FluentFuture<? extends CommitInfo> removePeer(@Nullable final YangInstanceIdentifier peerPath) {
}
@Override
- public synchronized final PeerId getPeerId() {
+ public final synchronized PeerId getPeerId() {
return this.peerId;
}
}
@Override
- @SuppressWarnings("unchecked")
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 initializeRibOut(
- final RouteEntryDependenciesContainer entryDep,
- final List<ActualBestPathRoutes<C, S, R, I>> routesToStore) {
+ I extends Identifier<R>> void initializeRibOut(final RouteEntryDependenciesContainer entryDep,
+ final 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 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> initializingRoute :routesToStore) {
+ for (final ActualBestPathRoutes<C, S, R, I> initializingRoute : routesToStore) {
+ if (!supportsLLGR() && initializingRoute.isDepreferenced()) {
+ // Stale Long-lived Graceful Restart routes should not be propagated
+ continue;
+ }
+
final PeerId fromPeerId = initializingRoute.getFromPeerId();
- final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
if (!filterRoutes(fromPeerId, ribSupport.getTablesKey())) {
continue;
}
- final R route = initializingRoute.getRoute();
+ final R route = initializingRoute.getRoute();
+ final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer,
this, route.getRouteKey(), this.rtCache);
+
final Optional<Attributes> effAttr = entryDep.getRoutingPolicies()
.applyExportPolicies(routeEntry, initializingRoute.getAttributes(), entryDep.getAfiSafType());
final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
effAttr.ifPresent(attributes
- -> storeRoute(ribSupport, addPathSupported, tableRibout, initializingRoute, route, attributes, tx));
+ -> storeRoute(ribSupport, addPathSupported, tableRibout, initializingRoute, route, attributes, tx));
}
final FluentFuture<? extends CommitInfo> future = tx.commit();
final boolean addPathSupported = supportsAddPathSupported(tk);
final WriteTransaction tx = this.bindingChain.newWriteOnlyTransaction();
- for(final ActualBestPathRoutes<C,S,R,I> actualBestRoute :routesToStore) {
+ 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,
+ final R route = actualBestRoute.getRoute();
+ final Optional<Attributes> effAttr;
+ if (supportsLLGR() || !actualBestRoute.isDepreferenced()) {
+ final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
+ final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer,
this, route.getRouteKey(), this.rtCache);
- final Optional<Attributes> effAttr = entryDep.getRoutingPolicies()
- .applyExportPolicies(routeEntry, actualBestRoute.getAttributes(), entryDep.getAfiSafType());
+ effAttr = entryDep.getRoutingPolicies()
+ .applyExportPolicies(routeEntry, actualBestRoute.getAttributes(), entryDep.getAfiSafType());
+ } else {
+ // Stale Long-lived Graceful Restart routes should not be propagated
+ effAttr = Optional.empty();
+ }
+
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);
+ deleteRoute(ribSupport, addPathSupported, tableRibout, actualBestRoute, tx);
}
}
}
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,
- final List<AdvertizedRoute<C,S,R,I>> routes, final WriteTransaction tx) {
+ R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>> void installRouteRibOut(
+ final RouteEntryDependenciesContainer entryDep, final List<AdvertizedRoute<C, S, R, I>> routes,
+ final WriteTransaction tx) {
final TablesKey tk = entryDep.getRIBSupport().getTablesKey();
final BGPPeerTracker peerTracker = entryDep.getPeerTracker();
- final RIBSupport<C,S,R,I> ribSupport = entryDep.getRIBSupport();
+ final RIBSupport<C, S, R, I> ribSupport = entryDep.getRIBSupport();
final BGPRibRoutingPolicy routingPolicies = entryDep.getRoutingPolicies();
final boolean addPathSupported = supportsAddPathSupported(tk);
+ final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
- for (final AdvertizedRoute<C,S,R,I> advRoute:routes) {
+ for (final AdvertizedRoute<C, S, R, I> advRoute : routes) {
final PeerId fromPeerId = advRoute.getFromPeerId();
if (!filterRoutes(fromPeerId, tk) || !advRoute.isFirstBestPath() && !addPathSupported) {
continue;
}
+ if (!supportsLLGR() && advRoute.isDepreferenced()) {
+ // https://tools.ietf.org/html/draft-uttaro-idr-bgp-persistence-04#section-4.3
+ // o The route SHOULD NOT be advertised to any neighbor from which the
+ // Long-lived Graceful Restart Capability has not been received. The
+ // exception is described in the Optional Partial Deployment
+ // Procedure section (Section 4.7). Note that this requirement
+ // implies that such routes should be withdrawn from any such
+ // neighbor.
+ deleteRoute(ribSupport, addPathSupported, tableRibout, advRoute, tx);
+ continue;
+ }
+
final R route = advRoute.getRoute();
- final Attributes attributes = advRoute.getAttributes();
Optional<Attributes> effAttr = Optional.empty();
final Peer fromPeer = peerTracker.getPeer(fromPeerId);
+ final Attributes attributes = advRoute.getAttributes();
if (fromPeer != null && attributes != null) {
final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer,
this, route.getRouteKey(), this.rtCache);
effAttr = routingPolicies.applyExportPolicies(routeEntry, attributes, entryDep.getAfiSafType());
}
- final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
effAttr.ifPresent(attributes1
- -> storeRoute(ribSupport, addPathSupported, tableRibout, advRoute, route, attributes1, tx));
+ -> storeRoute(ribSupport, addPathSupported, tableRibout, advRoute, route, attributes1, tx));
}
}
final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
final boolean addPathSupported = supportsAddPathSupported(tk);
staleRoutesIid.forEach(staleRouteIid
- -> removeRoute(ribSupport, addPathSupported, tableRibout, staleRouteIid, tx));
+ -> removeRoute(ribSupport, addPathSupported, tableRibout, staleRouteIid, tx));
}
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 storeRoute(final RIBSupport<C, S, R, I> ribSupport, final boolean addPathSupported,
- final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout,
- final RouteKeyIdentifier<R, I> advRoute, final R route, final Attributes effAttr,
- final WriteTransaction tx) {
+ R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>> void storeRoute(
+ final RIBSupport<C, S, R, I> ribSupport, final boolean addPathSupported,
+ final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout,
+ final RouteKeyIdentifier<R, I> advRoute, final R route, final Attributes effAttr,
+ final WriteTransaction tx) {
final InstanceIdentifier<R> ribOut;
final I newKey;
if (!addPathSupported) {
}
}
+ // FIXME: why is this different from removeRoute()?
+ 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 deleteRoute(
+ final RIBSupport<C, S, R, I> ribSupport, final boolean addPathSupported,
+ final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout,
+ final AbstractAdvertizedRoute<C, S , R, I> advRoute, final WriteTransaction tx) {
+ final InstanceIdentifier<R> ribOutTarget = ribSupport.createRouteIdentifier(tableRibout,
+ addPathSupported ? advRoute.getAddPathRouteKeyIdentifier() : advRoute.getNonAddPathRouteKeyIdentifier());
+ LOG.trace("Removing {} from transaction for peer {}", ribOutTarget, getPeerId());
+ tx.delete(LogicalDatastoreType.OPERATIONAL, ribOutTarget);
+ }
+
final synchronized void releaseBindingChain() {
if (this.submitted != null) {
try {
this.domChain = null;
}
}
+
+ boolean supportsLLGR() {
+ return false;
+ }
}