X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=bgp%2Fpath-selection-mode%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fprotocol%2Fbgp%2Fmode%2Fimpl%2Fadd%2FAddPathAbstractRouteEntry.java;h=56eab86aeff32fc1cba342d1f7821663efb1e930;hb=0fdeddbe3d072a88428599421191f0f60b2864e4;hp=7dcebea5e5abf55770d171d0faaf9cc3ada1b49e;hpb=6eac726211a8c118b5067093a4d2b7c3b144bba0;p=bgpcep.git diff --git a/bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/AddPathAbstractRouteEntry.java b/bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/AddPathAbstractRouteEntry.java index 7dcebea5e5..56eab86aef 100644 --- a/bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/AddPathAbstractRouteEntry.java +++ b/bgp/path-selection-mode/src/main/java/org/opendaylight/protocol/bgp/mode/impl/add/AddPathAbstractRouteEntry.java @@ -7,331 +7,242 @@ */ package org.opendaylight.protocol.bgp.mode.impl.add; +import static com.google.common.base.Verify.verifyNotNull; +import static org.opendaylight.protocol.bgp.parser.spi.PathIdUtil.NON_PATH_ID; import static org.opendaylight.protocol.bgp.parser.spi.PathIdUtil.NON_PATH_ID_VALUE; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; -import com.google.common.primitives.UnsignedInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.protocol.bgp.mode.impl.BGPRouteEntryExportParametersImpl; -import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry; -import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker; -import org.opendaylight.protocol.bgp.rib.spi.Peer; +import java.util.stream.Collectors; +import org.opendaylight.protocol.bgp.mode.api.RouteEntry; +import org.opendaylight.protocol.bgp.mode.impl.BestPathStateImpl; import org.opendaylight.protocol.bgp.rib.spi.RIBSupport; -import org.opendaylight.protocol.bgp.rib.spi.RouterIds; -import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryDependenciesContainer; +import org.opendaylight.protocol.bgp.rib.spi.RouterId; +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.RouteEntryInfo; -import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryExportParameters; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.Route; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.Tables; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.TablesKey; +import org.opendaylight.protocol.bgp.rib.spi.entry.StaleBestPathRoute; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.PathId; +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.rib.Tables; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.ChoiceIn; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Uint32; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * A single route entry inside a route table. Maintains the attributes of - * from all contributing peers. The information is stored in arrays with a - * shared map of offsets for peers to allow lookups. This is needed to - * maintain low memory overhead in face of large number of routes and peers, - * where individual object overhead becomes the dominating factor. + * A single route entry inside a route table. Maintains the attributes from all contributing peers. The information is + * stored in arrays with a shared map of offsets for peers to allow lookups. This is needed to maintain low memory + * overhead in face of large number of routes and peers, where individual object overhead becomes the dominating factor. + * + *

+ * This class is NOT thread-safe. */ -@NotThreadSafe -public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry { +public abstract class AddPathAbstractRouteEntry, + S extends ChildOf, R extends Route & ChildOf & Identifiable, I extends Identifier> + implements RouteEntry { + private static final class Stale, + S extends ChildOf, R extends Route & ChildOf & Identifiable, + I extends Identifier> extends StaleBestPathRoute { + private final List addPathRouteKeyIdentifier; + private final List staleRouteKeyIdentifier; + private final boolean isNonAddPathBestPathNew; + + Stale(final RIBSupport ribSupport, final String routeKey, final List staleRoutesPathIds, + final List withdrawalRoutePathIds, final boolean isNonAddPathBestPathNew) { + super(ribSupport.createRouteListKey(routeKey)); + this.isNonAddPathBestPathNew = isNonAddPathBestPathNew; + + this.staleRouteKeyIdentifier = staleRoutesPathIds.stream() + .map(pathId -> ribSupport.createRouteListKey(pathId, routeKey)).collect(Collectors.toList()); + if (withdrawalRoutePathIds != null) { + this.addPathRouteKeyIdentifier = withdrawalRoutePathIds.stream() + .map(pathId -> ribSupport.createRouteListKey(pathId, routeKey)).collect(Collectors.toList()); + } else { + this.addPathRouteKeyIdentifier = Collections.emptyList(); + } + } - private static final Logger LOG = LoggerFactory.getLogger(AddPathAbstractRouteEntry.class); - private List bestPath; - private List bestPathRemoved; - protected OffsetMap offsets = OffsetMap.EMPTY; - protected Attributes[] values = new Attributes[0]; - protected Long[] pathsId = new Long[0]; - private long pathIdCounter = 0L; - private boolean oldNonAddPathBestPathTheSame; - private List newBestPathToBeAdvertised; - private List removedPaths; + @Override + public List getStaleRouteKeyIdentifiers() { + return this.staleRouteKeyIdentifier; + } + + @Override + public List getAddPathRouteKeyIdentifiers() { + return addPathRouteKeyIdentifier; + } - public AddPathAbstractRouteEntry(final BGPPeerTracker peerTracker) { - super(peerTracker); + @Override + public boolean isNonAddPathBestPathNew() { + return isNonAddPathBestPathNew; + } } - private static final class RemovedPath { - private final RouteKey key; - private final long pathId; + private static final Logger LOG = LoggerFactory.getLogger(AddPathAbstractRouteEntry.class); + private static final Uint32[] EMPTY_PATHS_ID = new Uint32[0]; + private static final Route[] EMPTY_VALUES = new Route[0]; - RemovedPath(final RouteKey key, final long pathId) { - this.key = key; - this.pathId = pathId; - } + private RouteKeyOffsets offsets = RouteKeyOffsets.EMPTY; + private R[] values = (R[]) EMPTY_VALUES; + private Uint32[] pathsId = EMPTY_PATHS_ID; + private List bestPath; + private List bestPathRemoved; + private List newBestPathToBeAdvertised; + private List removedPathsId; - long getPathId() { - return this.pathId; - } + private long pathIdCounter = 0L; + private boolean isNonAddPathBestPathNew; - UnsignedInteger getRouteId() { - return this.key.getRouteId(); - } + private R createRoute(final RIBSupport ribSup, final String routeKey, final AddPathBestPath path) { + final RouteKeyOffsets map = this.offsets; + final R route = map.getValue(this.values, map.offsetOf(path.getRouteKey())); + return ribSup.createRoute(route, ribSup.createRouteListKey(pathIdObj(path.getPathIdLong()), routeKey), + path.getAttributes()); } - protected int addRoute(final RouteKey key, final Attributes attributes) { + @Override + public final int addRoute(final RouterId routerId, final Uint32 remotePathId, final R route) { + final RouteKey key = new RouteKey(routerId, remotePathId); int offset = this.offsets.offsetOf(key); if (offset < 0) { - final OffsetMap newOffsets = this.offsets.with(key); + final RouteKeyOffsets newOffsets = this.offsets.with(key); offset = newOffsets.offsetOf(key); - final Attributes[] newAttributes = newOffsets.expand(this.offsets, this.values, offset); - final Long[] newPathsId = newOffsets.expand(this.offsets, this.pathsId, offset); - this.values = newAttributes; + final R[] newRoute = newOffsets.expand(this.offsets, this.values, offset); + final Uint32[] newPathsId = newOffsets.expand(this.offsets, this.pathsId, offset); + this.values = newRoute; this.offsets = newOffsets; this.pathsId = newPathsId; - this.offsets.setValue(this.pathsId, offset, ++this.pathIdCounter); + this.offsets.setValue(this.pathsId, offset, Uint32.valueOf(++this.pathIdCounter)); } - this.offsets.setValue(this.values, offset, attributes); - LOG.trace("Added route from {} attributes {}", key.getRouteId(), attributes); + this.offsets.setValue(this.values, offset, route); + LOG.trace("Added route {} from {}", route, routerId); return offset; } - /** - * Remove route. - * - * @param key RouteKey of removed route - * @param offset Offset of removed route - * @return true if it was the last route - */ - protected final boolean removeRoute(final RouteKey key, final int offset) { - final long pathId = this.offsets.getValue(this.pathsId, offset); - this.values = this.offsets.removeValue(this.values, offset); - this.pathsId = this.offsets.removeValue(this.pathsId, offset); + @Override + public final boolean removeRoute(final RouterId routerId, final Uint32 remotePathId) { + final RouteKey key = new RouteKey(routerId, remotePathId); + final int offset = this.offsets.offsetOf(key); + final Uint32 pathId = this.offsets.getValue(this.pathsId, offset); + this.values = this.offsets.removeValue(this.values, offset, (R[]) EMPTY_VALUES); + this.pathsId = this.offsets.removeValue(this.pathsId, offset, EMPTY_PATHS_ID); this.offsets = this.offsets.without(key); - if (this.removedPaths == null) { - this.removedPaths = new ArrayList<>(); + if (this.removedPathsId == null) { + this.removedPathsId = new ArrayList<>(); } - this.removedPaths.add(new RemovedPath(key, pathId)); - return isEmpty(); + this.removedPathsId.add(pathId); + return this.offsets.isEmpty(); } @Override - public void updateBestPaths( - final RouteEntryDependenciesContainer entryDependencies, - final Identifier routeKey, - final WriteTransaction tx) { - - final RIBSupport ribSupport = entryDependencies.getRibSupport(); - final KeyedInstanceIdentifier locRibTarget = entryDependencies.getLocRibTableTarget(); - if (this.bestPathRemoved != null) { - this.bestPathRemoved.forEach(path -> { - final Identifier newRouteKey = ribSupport.createNewRouteKey(path.getPathId(), routeKey); - final InstanceIdentifier routeTarget = ribSupport.createRouteIdentifier(locRibTarget, newRouteKey); - LOG.debug("Delete route from LocRib {}", routeTarget); - tx.delete(LogicalDatastoreType.OPERATIONAL, routeTarget); - }); - this.bestPathRemoved = null; - } - if (this.removedPaths != null) { - this.removedPaths.forEach(removedPath -> { - final Identifier routeKeyAddPath - = ribSupport.createNewRouteKey(removedPath.getPathId(), routeKey); - final Identifier routeKeyNonAddPath = ribSupport.createNewRouteKey(NON_PATH_ID_VALUE, routeKey); - fillAdjRibsOut(true, null, null, null, - routeKeyNonAddPath, routeKeyAddPath, - RouterIds.createPeerId(removedPath.getRouteId()), - entryDependencies.getLocalTablesKey(), entryDependencies, tx); - }); - this.removedPaths = null; + public final Optional> removeStalePaths(final RIBSupport ribSupport, + final String routeKey) { + final List stalePaths; + if (bestPathRemoved != null && !bestPathRemoved.isEmpty()) { + stalePaths = bestPathRemoved.stream().map(AddPathBestPath::getPathIdLong) + .map(AddPathAbstractRouteEntry::pathIdObj).collect(Collectors.toList()); + bestPathRemoved = null; + } else { + stalePaths = Collections.emptyList(); } - if (this.newBestPathToBeAdvertised != null) { - this.newBestPathToBeAdvertised.forEach(path -> addPathToDataStore(entryDependencies, path, - isFirstBestPath(this.bestPath.indexOf(path)), routeKey, tx)); - this.newBestPathToBeAdvertised = null; + List removedPaths; + if (removedPathsId != null) { + removedPaths = Lists.transform(removedPathsId, AddPathAbstractRouteEntry::pathIdObj); + this.removedPathsId = null; + } else { + removedPaths = Collections.emptyList(); } + + return stalePaths.isEmpty() && removedPaths.isEmpty() ? Optional.empty() + : Optional.of(new Stale<>(ribSupport, routeKey, stalePaths, removedPaths, isNonAddPathBestPathNew)); } @Override - public void initializeBestPaths(final RouteEntryDependenciesContainer entryDependencies, - final RouteEntryInfo entryInfo, final WriteTransaction tx) { - if (this.bestPath != null) { - final Peer toPeer = entryInfo.getToPeer(); - final TablesKey localTk = entryDependencies.getLocalTablesKey(); - final boolean destPeerSupAddPath = toPeer.supportsAddPathSupported(localTk); - for (final AddPathBestPath path : this.bestPath) { - if (!filterRoutes(path.getPeerId(), toPeer, localTk)) { - continue; - } - writeRoutePath(entryInfo, destPeerSupAddPath, path, localTk, entryDependencies, tx); - } + public final List> newBestPaths(final RIBSupport ribSupport, + final String routeKey) { + if (this.newBestPathToBeAdvertised == null || this.newBestPathToBeAdvertised.isEmpty()) { + return Collections.emptyList(); } - } - - @SuppressWarnings("unchecked") - private void writeRoutePath(final RouteEntryInfo entryInfo, - final boolean destPeerSupAddPath, final AddPathBestPath path, - final TablesKey localTK, final RouteEntryDependenciesContainer routeEntryDep, final WriteTransaction tx) { - final Identifier routeKey = entryInfo.getRouteKey(); - final RIBSupport ribSupport = routeEntryDep.getRibSupport(); - final BGPRouteEntryExportParameters baseExp = new BGPRouteEntryExportParametersImpl( - this.peerTracker.getPeer(path.getPeerId()), entryInfo.getToPeer()); - final Optional effAttrib = routeEntryDep.getRoutingPolicies() - .applyExportPolicies(baseExp, path.getAttributes()); - - Identifier newRouteKey = ribSupport.createNewRouteKey(destPeerSupAddPath - ? path.getPathId() : NON_PATH_ID_VALUE, routeKey); - final Peer toPeer = entryInfo.getToPeer(); - final Route route = createRoute(ribSupport, newRouteKey, destPeerSupAddPath - ? path.getPathId() : NON_PATH_ID_VALUE, path); - InstanceIdentifier ribOutIId = ribSupport.createRouteIdentifier(toPeer.getRibOutIId(localTK), newRouteKey); - if (effAttrib.isPresent() && route != null) { - LOG.debug("Write route {} to peer AdjRibsOut {}", route, toPeer.getPeerId()); - tx.put(LogicalDatastoreType.OPERATIONAL, ribOutIId, route); - tx.put(LogicalDatastoreType.OPERATIONAL, ribOutIId.child(Attributes.class), effAttrib.get()); + final List> advertized = new ArrayList<>(newBestPathToBeAdvertised.size()); + final AddPathBestPath firstBestPath = this.bestPath.isEmpty() ? null : this.bestPath.get(0); + for (final AddPathBestPath path : this.newBestPathToBeAdvertised) { + final R routeAddPath = createRoute(ribSupport, routeKey, path); + // FIXME: can we use identity check here? + final boolean isFirstBestPath = firstBestPath != null && firstBestPath.equals(path); + final AdvertizedRoute adv = new AdvertizedRoute<>(ribSupport, isFirstBestPath, + routeAddPath, path.getAttributes(), path.getPeerId(), path.isDepreferenced()); + advertized.add(adv); } + this.newBestPathToBeAdvertised = null; + return advertized; } - private void addPathToDataStore( - final RouteEntryDependenciesContainer entryDep, - final AddPathBestPath path, - final boolean isFirstBestPath, - final Identifier routeKey, - final WriteTransaction tx) { - final RIBSupport ribSup = entryDep.getRibSupport(); - final Identifier routeKeyAddPath = ribSup.createNewRouteKey(path.getPathId(), routeKey); - final Identifier routeKeyAddNonPath = ribSup.createNewRouteKey(NON_PATH_ID_VALUE, routeKey); - final Route routeAddPath = createRoute(ribSup, routeKeyAddPath, path.getPathId(), path); - final Route routeNonAddPath = createRoute(ribSup, routeKeyAddNonPath, NON_PATH_ID_VALUE, path); - - final KeyedInstanceIdentifier locRibTarget = entryDep.getLocRibTableTarget(); - final InstanceIdentifier routeTarget = ribSup.createRouteIdentifier(locRibTarget, routeKeyAddPath); - LOG.debug("Write route to LocRib {}", routeAddPath); - tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget, routeAddPath); - - fillAdjRibsOut(isFirstBestPath, path.getAttributes(), routeNonAddPath, routeAddPath, routeKeyAddNonPath, - routeKeyAddPath, path.getPeerId(), entryDep.getLocalTablesKey(), entryDep, tx); - } - - @SuppressWarnings("unchecked") - private void fillAdjRibsOut( - final boolean isFirstBestPath, - final Attributes attributes, - final Route routeNonAddPath, - final Route routeAddPath, - final Identifier routeKeyAddNonPath, - final Identifier routeKeyAddPath, - final PeerId fromPeerId, - final TablesKey localTK, - final RouteEntryDependenciesContainer routeEntryDep, - final WriteTransaction tx) { - /* - * We need to keep track of routers and populate adj-ribs-out, too. If we do not, we need to - * expose from which client a particular route was learned from in the local RIB, and have - * the listener perform filtering. - * - * We walk the policy set in order to minimize the amount of work we do for multiple peers: - * if we have two eBGP peers, for example, there is no reason why we should perform the translation - * multiple times. - */ - final RIBSupport ribSupport = routeEntryDep.getRibSupport(); - for (final Peer toPeer : this.peerTracker.getPeers()) { - if (!filterRoutes(fromPeerId, toPeer, localTK)) { - continue; - } - final boolean destPeerSupAddPath = toPeer.supportsAddPathSupported(localTK); - - if (toPeer.getPeerId().getValue().equals("bgp://127.0.0.5")) { - LOG.debug("Write route {} to peer AdjRibsOut {}", toPeer.getPeerId()); - } - if (peersSupportsAddPathOrIsFirstBestPath(destPeerSupAddPath, isFirstBestPath)) { - - Optional effAttrib = Optional.empty(); - final Peer fromPeer = this.peerTracker.getPeer(fromPeerId); - - if (fromPeer != null && attributes != null) { - final BGPRouteEntryExportParameters baseExp - = new BGPRouteEntryExportParametersImpl(fromPeer, toPeer); - effAttrib = routeEntryDep.getRoutingPolicies() - .applyExportPolicies(baseExp, attributes); - } - Route newRoute = null; - InstanceIdentifier ribOutRoute = null; - if (destPeerSupAddPath) { - newRoute = routeAddPath; - ribOutRoute - = ribSupport.createRouteIdentifier(toPeer.getRibOutIId(localTK), routeKeyAddPath); - } else if (!this.oldNonAddPathBestPathTheSame) { - ribOutRoute - = ribSupport.createRouteIdentifier(toPeer.getRibOutIId(localTK), routeKeyAddNonPath); - newRoute = routeNonAddPath; - } - - if (effAttrib.isPresent() && newRoute != null) { - LOG.debug("Write route {} to peer AdjRibsOut {}", newRoute, toPeer.getPeerId()); - tx.put(LogicalDatastoreType.OPERATIONAL, ribOutRoute, newRoute); - tx.put(LogicalDatastoreType.OPERATIONAL, ribOutRoute.child(Attributes.class), effAttrib.get()); - } else if (ribOutRoute != null) { - LOG.trace("Removing {} from transaction for peer {}", ribOutRoute, toPeer.getPeerId()); - tx.delete(LogicalDatastoreType.OPERATIONAL, ribOutRoute); - } - } + @Override + public final List> actualBestPaths(final RIBSupport ribSupport, + final RouteEntryInfo entryInfo) { + if (this.bestPath == null || this.bestPath.isEmpty()) { + return Collections.emptyList(); } + final List> preexistentRoutes = new ArrayList<>(); + for (final AddPathBestPath path : this.bestPath) { + final R route = createRoute(ribSupport, entryInfo.getRouteKey(), path); + final ActualBestPathRoutes adv = new ActualBestPathRoutes<>(ribSupport, route, path.getPeerId(), + path.getAttributes(), path.isDepreferenced()); + preexistentRoutes.add(adv); + } + return preexistentRoutes; } - - protected final OffsetMap getOffsets() { - return this.offsets; - } - - public final boolean isEmpty() { - return this.offsets.isEmpty(); + @Override + public final boolean selectBest(final long localAs) { + final int size; + return isBestPathNew((size = offsets.size()) == 0 ? ImmutableList.of() : selectBest(localAs, size)); } - private void selectBest(final RouteKey key, final AddPathSelector selector) { - final int offset = this.offsets.offsetOf(key); - final Attributes attributes = this.offsets.getValue(this.values, offset); - final long pathId = this.offsets.getValue(this.pathsId, offset); - LOG.trace("Processing router key {} attributes {}", key, attributes); - selector.processPath(attributes, key, offset, pathId); - } + protected abstract ImmutableList selectBest(long localAs, int size); /** - * Process best path selection. + * Process a specific route offset into specified selector. * - * @param localAs The local autonomous system number - * @param keyList List of RouteKey - * @return the best path inside offset map passed + * @param selector selector to update + * @param offset offset to process */ - protected AddPathBestPath selectBest(final long localAs, final List keyList) { - /* - * FIXME: optimize flaps by making sure we consider stability of currently-selected route. - */ - final AddPathSelector selector = new AddPathSelector(localAs); - Lists.reverse(keyList).forEach(key -> selectBest(key, selector)); - LOG.trace("Best path selected {}", this.bestPath); - return selector.result(); + protected final void processOffset(final AddPathSelector selector, final int offset) { + final RouteKey key = offsets.getKey(offset); + final R route = offsets.getValue(values, offset); + final Uint32 pathId = offsets.getValue(pathsId, offset); + LOG.trace("Processing router key {} route {}", key, route); + selector.processPath(route.getAttributes(), key, offset, pathId); } - private static boolean isFirstBestPath(final int bestPathPosition) { - return bestPathPosition == 0; + protected final AddPathBestPath bestPathAt(final int offset) { + final Route route = verifyNotNull(offsets.getValue(values, offset)); + return new AddPathBestPath(new BestPathStateImpl(route.getAttributes()), offsets.getKey(offset), + offsets.getValue(pathsId, offset), offset); } - private static boolean peersSupportsAddPathOrIsFirstBestPath(final boolean peerSupportsAddPath, - final boolean isFirstBestPath) { - return !(!peerSupportsAddPath && !isFirstBestPath); - } - - protected boolean isBestPathNew(final List newBestPathList) { - this.oldNonAddPathBestPathTheSame = isNonAddPathBestPathTheSame(newBestPathList); + private boolean isBestPathNew(final ImmutableList newBestPathList) { + this.isNonAddPathBestPathNew = !isNonAddPathBestPathTheSame(newBestPathList); filterRemovedPaths(newBestPathList); if (this.bestPathRemoved != null && !this.bestPathRemoved.isEmpty() || newBestPathList != null && !newBestPathList.equals(this.bestPath)) { - this.newBestPathToBeAdvertised = new ArrayList<>(newBestPathList); if (this.bestPath != null) { + this.newBestPathToBeAdvertised = new ArrayList<>(newBestPathList); this.newBestPathToBeAdvertised.removeAll(this.bestPath); + } else { + this.newBestPathToBeAdvertised = newBestPathList; } this.bestPath = newBestPathList; LOG.trace("Actual Best {}, removed best {}", this.bestPath, this.bestPathRemoved); @@ -361,4 +272,8 @@ public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry this.bestPathRemoved.remove(oldBest)); }); } + + private static PathId pathIdObj(final Uint32 pathId) { + return NON_PATH_ID_VALUE.equals(pathId) ? NON_PATH_ID : new PathId(pathId); + } }