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=7725180ceb3612caa039e9b9400e47c686181916;hpb=94f7f6bee9c8467cdd240aac4702c3e49f5306e1;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 7725180ceb..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,237 +7,243 @@
*/
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 java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
-import javax.annotation.concurrent.NotThreadSafe;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.protocol.bgp.mode.api.BestPath;
-import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry;
-import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
-import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
-import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup;
-import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup.PeerExporTuple;
+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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+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.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.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 super C>, R extends Route & ChildOf super S> & Identifiable, I extends Identifier>
+ implements RouteEntry {
+ private static final class Stale,
+ S extends ChildOf super C>, R extends Route & ChildOf super S> & 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();
+ }
+ }
+
+ @Override
+ public List getStaleRouteKeyIdentifiers() {
+ return this.staleRouteKeyIdentifier;
+ }
+
+ @Override
+ public List getAddPathRouteKeyIdentifiers() {
+ return addPathRouteKeyIdentifier;
+ }
+
+ @Override
+ public boolean isNonAddPathBestPathNew() {
+ return isNonAddPathBestPathNew;
+ }
+ }
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];
+
+ private RouteKeyOffsets offsets = RouteKeyOffsets.EMPTY;
+ private R[] values = (R[]) EMPTY_VALUES;
+ private Uint32[] pathsId = EMPTY_PATHS_ID;
private List bestPath;
private List bestPathRemoved;
- protected OffsetMap offsets = OffsetMap.EMPTY;
- protected ContainerNode[] values = new ContainerNode[0];
- protected Long[] pathsId = new Long[0];
+ private List newBestPathToBeAdvertised;
+ private List removedPathsId;
+
private long pathIdCounter = 0L;
+ private boolean isNonAddPathBestPathNew;
- private int addRoute(final RouteKey key, final ContainerNode attributes) {
+ 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());
+ }
+
+ @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 ContainerNode[] 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;
}
- protected int addRoute(final RouteKey key, final NodeIdentifier attributesIdentifier, final NormalizedNode, ?> data) {
- LOG.trace("Find {} in {}", attributesIdentifier, data);
- final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(data, attributesIdentifier).orNull();
- return addRoute(key, advertisedAttrs);
- }
-
- /**
- * 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) {
- this.values = this.offsets.removeValue(this.values, offset);
- this.pathsId = this.offsets.removeValue(this.pathsId, offset);
- this.offsets = this.offsets.without(key);
- return isEmpty();
- }
-
@Override
- public void updateRoute(final TablesKey localTK, final ExportPolicyPeerTracker peerPT, final YangInstanceIdentifier locRibTarget, final RIBSupport ribSup,
- final CacheDisconnectedPeers discPeers, final DOMDataWriteTransaction tx, final PathArgument routeIdPA) {
- if(this.bestPathRemoved != null) {
- this.bestPathRemoved.forEach(path -> removePathFromDataStore(path, isFirstBestPath(bestPathRemoved.indexOf(path)), routeIdPA, locRibTarget, ribSup,
- peerPT, localTK, discPeers, tx));
- this.bestPathRemoved = null;
- }
-
- if(this.bestPath != null) {
- this.bestPath.forEach(path -> addPathToDataStore(path, isFirstBestPath(this.bestPath.indexOf(path)), routeIdPA, locRibTarget, ribSup,
- peerPT, localTK, discPeers, tx));
+ 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.removedPathsId == null) {
+ this.removedPathsId = new ArrayList<>();
}
+ this.removedPathsId.add(pathId);
+ return this.offsets.isEmpty();
}
@Override
- public void writeRoute(final PeerId destPeer, final PathArgument routeId, final YangInstanceIdentifier rootPath, final PeerExportGroup peerGroup,
- final TablesKey localTK, final ExportPolicyPeerTracker peerPT, final RIBSupport ribSup, final CacheDisconnectedPeers discPeers,
- final DOMDataWriteTransaction tx) {
- final boolean destPeerSupAddPath = peerPT.isAddPathSupportedByPeer(destPeer);
- if(this.bestPath != null) {
- this.bestPath.stream().filter(path -> filterRoutes(path.getPeerId(), destPeer, peerPT, localTK, discPeers) &&
- peersSupportsAddPathOrIsFirstBestPath(destPeerSupAddPath, isFirstBestPath(this.bestPath.indexOf(path))))
- .forEach(path -> writeRoutePath(destPeer, routeId, peerPT, peerGroup, destPeerSupAddPath, path, rootPath, localTK, ribSup, tx));
+ 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();
}
- }
- private void writeRoutePath(final PeerId destPeer, final PathArgument routeId, final ExportPolicyPeerTracker peerPT,
- final PeerExportGroup peerGroup, final boolean destPeerSupAddPath,
- final BestPath path, final YangInstanceIdentifier rootPath, final TablesKey localTK, final RIBSupport ribSup, final DOMDataWriteTransaction tx) {
- final PathArgument routeIdAddPath = ribSup.getRouteIdAddPath(path.getPathId(), routeId);
- final ContainerNode effectiveAttributes = peerGroup.effectiveAttributes(getRoutePeerIdRole(peerPT,path.getPeerId()), path.getAttributes());
- if (destPeerSupAddPath) {
- writeRoute(destPeer, getAdjRibOutYII(ribSup, rootPath, routeIdAddPath, localTK), effectiveAttributes, createValue(routeIdAddPath, path), ribSup, tx);
+ List removedPaths;
+ if (removedPathsId != null) {
+ removedPaths = Lists.transform(removedPathsId, AddPathAbstractRouteEntry::pathIdObj);
+ this.removedPathsId = null;
} else {
- writeRoute(destPeer, getAdjRibOutYII(ribSup, rootPath, routeId, localTK), effectiveAttributes, createValue(routeId, path), ribSup, tx);
+ removedPaths = Collections.emptyList();
}
- }
-
- private void addPathToDataStore(final BestPath path, final boolean isFirstBestPath, final PathArgument routeIdPA, final YangInstanceIdentifier locRibTarget,
- final RIBSupport ribSup, final ExportPolicyPeerTracker peerPT, final TablesKey localTK, final CacheDisconnectedPeers discPeers,
- final DOMDataWriteTransaction tx) {
- final PathArgument routeIdAddPath = ribSup.getRouteIdAddPath(path.getPathId(), routeIdPA);
- final YangInstanceIdentifier pathAddPathTarget = ribSup.routePath(locRibTarget.node(ROUTES_IDENTIFIER), routeIdAddPath);
- final MapEntryNode addPathValue = createValue(routeIdAddPath, path);
- final MapEntryNode value = createValue(routeIdPA, path);
- LOG.trace("Selected best value {}", addPathValue);
- fillLocRib(pathAddPathTarget, addPathValue, tx);
- fillAdjRibsOut(isFirstBestPath, path.getAttributes(), value, addPathValue, routeIdPA, routeIdAddPath, path.getPeerId(), peerPT, localTK,
- ribSup, discPeers, tx);
- }
-
- private void removePathFromDataStore(final BestPath path, final boolean isFirstBestPath, final PathArgument routeIdPA,
- final YangInstanceIdentifier locRibTarget, final RIBSupport ribSup, final ExportPolicyPeerTracker peerPT, final TablesKey localTK,
- final CacheDisconnectedPeers discPeers, final DOMDataWriteTransaction tx) {
- LOG.trace("Best Path removed {}", path);
- final PathArgument routeIdAddPath = ribSup.getRouteIdAddPath(path.getPathId(), routeIdPA);
- final YangInstanceIdentifier pathAddPathTarget = ribSup.routePath(locRibTarget.node(ROUTES_IDENTIFIER), routeIdAddPath);
- fillLocRib(pathAddPathTarget, null, tx);
- fillAdjRibsOut(isFirstBestPath, null, null, null, routeIdPA, routeIdAddPath, path.getPeerId(), peerPT, localTK, ribSup, discPeers, tx);
+ return stalePaths.isEmpty() && removedPaths.isEmpty() ? Optional.empty()
+ : Optional.of(new Stale<>(ribSupport, routeKey, stalePaths, removedPaths, isNonAddPathBestPathNew));
}
- private void fillAdjRibsOut(final boolean isFirstBestPath, final ContainerNode attributes, final NormalizedNode, ?> value, final MapEntryNode addPathValue,
- final PathArgument routeId, final PathArgument routeIdAddPath, final PeerId routePeerId, final ExportPolicyPeerTracker peerPT, final TablesKey
- localTK, final RIBSupport ribSup, final CacheDisconnectedPeers discPeers, final DOMDataWriteTransaction 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.
- */
- for (final PeerRole role : PeerRole.values()) {
- final PeerExportGroup peerGroup = peerPT.getPeerGroup(role);
- if (peerGroup != null) {
- final ContainerNode effectiveAttributes = peerGroup.effectiveAttributes(getRoutePeerIdRole(peerPT, routePeerId), attributes);
- for (final Map.Entry pid : peerGroup.getPeers()) {
- final PeerId destPeer = pid.getKey();
- final boolean destPeerSupAddPath = peerPT.isAddPathSupportedByPeer(destPeer);
- if (filterRoutes(routePeerId, destPeer, peerPT, localTK, discPeers) && peersSupportsAddPathOrIsFirstBestPath(destPeerSupAddPath, isFirstBestPath)) {
- if (destPeerSupAddPath) {
- update(destPeer, getAdjRibOutYII(ribSup, pid.getValue().getYii(), routeIdAddPath, localTK), effectiveAttributes,
- addPathValue,
- ribSup, tx);
- } else {
- update(destPeer, getAdjRibOutYII(ribSup, pid.getValue().getYii(), routeId, localTK), effectiveAttributes, value, ribSup, tx);
- }
- }
- }
- }
+ @Override
+ public final List> newBestPaths(final RIBSupport ribSupport,
+ final String routeKey) {
+ if (this.newBestPathToBeAdvertised == null || this.newBestPathToBeAdvertised.isEmpty()) {
+ return Collections.emptyList();
}
- }
-
- private void update(final PeerId destPeer, final YangInstanceIdentifier routeTarget, final ContainerNode effAttr, final NormalizedNode, ?> value,
- final RIBSupport ribSup, final DOMDataWriteTransaction tx) {
- if (!writeRoute(destPeer, routeTarget, effAttr, value, ribSup, tx)) {
- LOG.trace("Removing {} from transaction for peer {}", routeTarget, destPeer);
- tx.delete(LogicalDatastoreType.OPERATIONAL, routeTarget);
+ 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;
}
- protected final OffsetMap getOffsets() {
- return this.offsets;
+ @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;
}
- 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 ContainerNode 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 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 boolean peersSupportsAddPathOrIsFirstBestPath(final boolean peerSupportsAddPath, final boolean isFirstBestPath) {
- return !(!peerSupportsAddPath && !isFirstBestPath);
- }
-
- protected boolean isBestPathNew(final List 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)) {
+ if (this.bestPathRemoved != null && !this.bestPathRemoved.isEmpty()
+ || newBestPathList != null
+ && !newBestPathList.equals(this.bestPath)) {
+ 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);
return true;
@@ -245,17 +251,29 @@ public abstract class AddPathAbstractRouteEntry extends AbstractRouteEntry {
return false;
}
+ private boolean isNonAddPathBestPathTheSame(final List newBestPathList) {
+ return !(isEmptyOrNull(this.bestPath) || isEmptyOrNull(newBestPathList))
+ && this.bestPath.get(0).equals(newBestPathList.get(0));
+ }
+
+ private static boolean isEmptyOrNull(final List pathList) {
+ return pathList == null || pathList.isEmpty();
+ }
+
private void filterRemovedPaths(final List newBestPathList) {
- if(this.bestPath == null) {
+ if (this.bestPath == null) {
return;
}
this.bestPathRemoved = new ArrayList<>(this.bestPath);
this.bestPath.forEach(oldBest -> {
final Optional present = newBestPathList.stream()
- .filter(newBest -> newBest.getPathId() == oldBest.getPathId() && newBest.getRouteKey() == oldBest.getRouteKey()).findAny();
- if(present.isPresent()) {
- this.bestPathRemoved.remove(oldBest);
- }
+ .filter(newBest -> newBest.getPathId() == oldBest.getPathId()
+ && newBest.getRouteKey() == oldBest.getRouteKey()).findAny();
+ present.ifPresent(addPathBestPath -> this.bestPathRemoved.remove(oldBest));
});
}
+
+ private static PathId pathIdObj(final Uint32 pathId) {
+ return NON_PATH_ID_VALUE.equals(pathId) ? NON_PATH_ID : new PathId(pathId);
+ }
}