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=5c6b7cf7e9284242c1902f9696fad1ffaf27d8df;hpb=8f4ca9f10562f34e496a32e432d4217f9130a2a8;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 5c6b7cf7e9..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,21 +7,26 @@ */ 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 java.util.stream.Collectors; -import javax.annotation.concurrent.NotThreadSafe; 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.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; @@ -30,56 +35,94 @@ 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, - S extends ChildOf, - R extends Route & ChildOf & Identifiable, I extends Identifier> + 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(); + } + } + + @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 Long[] EMPTY_PATHS_ID = new Long[0]; + private static final Uint32[] EMPTY_PATHS_ID = new Uint32[0]; private static final Route[] EMPTY_VALUES = new Route[0]; - protected OffsetMap offsets = OffsetMap.EMPTY; - protected R[] values = (R[]) EMPTY_VALUES; - protected Long[] pathsId = EMPTY_PATHS_ID; + 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; + private long pathIdCounter = 0L; private boolean isNonAddPathBestPathNew; - private List newBestPathToBeAdvertised; - private List removedPathsId; - private R createRoute(final RIBSupport ribSup, final String routeKey, - final long pathId, final AddPathBestPath path) { - final OffsetMap map = getOffsets(); + 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, routeKey, pathId, path.getAttributes()); + return ribSup.createRoute(route, ribSup.createRouteListKey(pathIdObj(path.getPathIdLong()), routeKey), + path.getAttributes()); } @Override - public final int addRoute(final UnsignedInteger routerId, final long remotePathId, final R route) { + 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 R[] newRoute = newOffsets.expand(this.offsets, this.values, offset); - final Long[] newPathsId = newOffsets.expand(this.offsets, this.pathsId, 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, route); LOG.trace("Added route {} from {}", route, routerId); @@ -87,10 +130,10 @@ public abstract class AddPathAbstractRouteEntry(); } this.removedPathsId.add(pathId); - return isEmpty(); + return this.offsets.isEmpty(); } @Override public final Optional> removeStalePaths(final RIBSupport ribSupport, final String routeKey) { - if ((this.bestPathRemoved == null || this.bestPathRemoved.isEmpty()) && this.removedPathsId == null) { - return Optional.empty(); + 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(); } - List stalePaths = Collections.emptyList(); - if (this.bestPathRemoved != null && !this.bestPathRemoved.isEmpty()) { - stalePaths = this.bestPathRemoved.stream().map(AddPathBestPath::getPathId).collect(Collectors.toList()); - this.bestPathRemoved = null; + + List removedPaths; + if (removedPathsId != null) { + removedPaths = Lists.transform(removedPathsId, AddPathAbstractRouteEntry::pathIdObj); + this.removedPathsId = null; + } else { + removedPaths = Collections.emptyList(); } - final StaleBestPathRoute stale = new StaleBestPathRoute<>(ribSupport, routeKey, stalePaths, - this.removedPathsId, this.isNonAddPathBestPathNew); - this.removedPathsId = null; - return Optional.of(stale); + + return stalePaths.isEmpty() && removedPaths.isEmpty() ? Optional.empty() + : Optional.of(new Stale<>(ribSupport, routeKey, stalePaths, removedPaths, isNonAddPathBestPathNew)); } @Override @@ -127,7 +177,7 @@ public abstract class AddPathAbstractRouteEntry> 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.getPathId(), path); + 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, @@ -146,7 +196,7 @@ public abstract class AddPathAbstractRouteEntry> preexistentRoutes = new ArrayList<>(); for (final AddPathBestPath path : this.bestPath) { - final R route = createRoute(ribSupport, entryInfo.getRouteKey(), path.getPathId(), path); + final R route = createRoute(ribSupport, entryInfo.getRouteKey(), path); final ActualBestPathRoutes adv = new ActualBestPathRoutes<>(ribSupport, route, path.getPeerId(), path.getAttributes(), path.isDepreferenced()); preexistentRoutes.add(adv); @@ -154,40 +204,35 @@ public abstract class AddPathAbstractRouteEntry selectBest(long localAs, int size); - private void selectBest(final RouteKey key, final AddPathSelector selector) { - final int offset = this.offsets.offsetOf(key); - final R route = this.offsets.getValue(this.values, offset); - final long pathId = this.offsets.getValue(this.pathsId, offset); + /** + * Process a specific route offset into specified selector. + * + * @param selector selector to update + * @param offset offset to process + */ + 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); } - /** - * Process best path selection. - * - * @param localAs The local autonomous system number - * @param keyList List of RouteKey - * @return the best path inside offset map passed - */ - 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 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); } - protected boolean isBestPathNew(final ImmutableList newBestPathList) { + private boolean isBestPathNew(final ImmutableList newBestPathList) { this.isNonAddPathBestPathNew = !isNonAddPathBestPathTheSame(newBestPathList); filterRemovedPaths(newBestPathList); if (this.bestPathRemoved != null && !this.bestPathRemoved.isEmpty() @@ -227,4 +272,8 @@ public abstract class AddPathAbstractRouteEntry this.bestPathRemoved.remove(oldBest)); }); } + + private static PathId pathIdObj(final Uint32 pathId) { + return NON_PATH_ID_VALUE.equals(pathId) ? NON_PATH_ID : new PathId(pathId); + } }