2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.mode.impl.base;
10 import java.util.Collections;
11 import java.util.List;
12 import java.util.Optional;
13 import org.opendaylight.protocol.bgp.mode.api.RouteEntry;
14 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
15 import org.opendaylight.protocol.bgp.rib.spi.RouterId;
16 import org.opendaylight.protocol.bgp.rib.spi.entry.ActualBestPathRoutes;
17 import org.opendaylight.protocol.bgp.rib.spi.entry.AdvertizedRoute;
18 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryInfo;
19 import org.opendaylight.protocol.bgp.rib.spi.entry.StaleBestPathRoute;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
23 import org.opendaylight.yangtools.yang.binding.ChildOf;
24 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.Identifiable;
27 import org.opendaylight.yangtools.yang.binding.Identifier;
28 import org.opendaylight.yangtools.yang.common.Uint32;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 final class BaseRouteEntry<C extends Routes & DataObject & ChoiceIn<Tables>,
36 S extends ChildOf<? super C>, R extends Route & ChildOf<? super S> & Identifiable<I>,
37 I extends Identifier<R>> implements RouteEntry<C, S, R, I> {
38 private static final class Stale<C extends Routes & DataObject & ChoiceIn<Tables>,
39 S extends ChildOf<? super C>, R extends Route & ChildOf<? super S> & Identifiable<I>,
40 I extends Identifier<R>> extends StaleBestPathRoute<C, S, R, I> {
41 Stale(final NodeIdentifierWithPredicates nonAddPathRouteKeyIdentifier) {
42 super(nonAddPathRouteKeyIdentifier);
46 public List<NodeIdentifierWithPredicates> getStaleRouteKeyIdentifiers() {
47 return Collections.singletonList(getNonAddPathRouteKeyIdentifier());
51 public List<NodeIdentifierWithPredicates> getAddPathRouteKeyIdentifiers() {
52 return Collections.emptyList();
56 public boolean isNonAddPathBestPathNew() {
61 private static final Logger LOG = LoggerFactory.getLogger(BaseRouteEntry.class);
62 private static final MapEntryNode[] EMPTY_VALUES = new MapEntryNode[0];
64 private RouterIdOffsets offsets = RouterIdOffsets.EMPTY;
65 private MapEntryNode[] values = EMPTY_VALUES;
66 private BaseBestPath bestPath;
67 private BaseBestPath removedBestPath;
73 public boolean removeRoute(final RouterId routerId, final Uint32 remotePathId) {
74 final int offset = this.offsets.offsetOf(routerId);
75 this.values = this.offsets.removeValue(this.values, offset, EMPTY_VALUES);
76 this.offsets = this.offsets.without(routerId);
77 return this.offsets.isEmpty();
80 private MapEntryNode createRoute(final RIBSupport<C, S, R, I> ribSup, final String routeKey) {
81 final MapEntryNode route = this.offsets.getValue(this.values, this.offsets.offsetOf(bestPath.getRouterId()));
82 return ribSup.createRoute(route, ribSup.createRouteListArgument(routeKey), bestPath.getAttributes());
86 public boolean selectBest(final RIBSupport<C, S, R, I> ribSupport, final long localAs) {
88 * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
90 final BasePathSelector selector = new BasePathSelector(localAs);
92 // Select the best route.
93 for (int i = 0; i < this.offsets.size(); ++i) {
94 final RouterId routerId = this.offsets.getKey(i);
95 final ContainerNode attributes = ribSupport.extractAttributes(this.offsets.getValue(this.values, i));
96 LOG.trace("Processing router id {} attributes {}", routerId, attributes);
97 selector.processPath(routerId, attributes);
100 // Get the newly-selected best path.
101 final BaseBestPath newBestPath = selector.result();
102 final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
104 if (this.offsets.isEmpty()) {
105 this.removedBestPath = this.bestPath;
107 LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
108 this.bestPath = newBestPath;
114 public int addRoute(final RouterId routerId, final Uint32 remotePathId, final MapEntryNode route) {
115 int offset = this.offsets.offsetOf(routerId);
117 final RouterIdOffsets newOffsets = this.offsets.with(routerId);
118 offset = newOffsets.offsetOf(routerId);
120 this.values = newOffsets.expand(this.offsets, this.values, offset);
121 this.offsets = newOffsets;
124 this.offsets.setValue(this.values, offset, route);
125 LOG.trace("Added route {} from {}", route, routerId);
130 public Optional<StaleBestPathRoute<C, S, R, I>> removeStalePaths(final RIBSupport<C, S, R, I> ribSupport,
131 final String routeKey) {
132 if (removedBestPath == null) {
133 return Optional.empty();
135 removedBestPath = null;
136 return Optional.of(new Stale<C, S, R, I>(ribSupport.createRouteListArgument(routeKey)));
140 public List<AdvertizedRoute<C, S, R, I>> newBestPaths(final RIBSupport<C, S, R, I> ribSupport,
141 final String routeKey) {
142 if (this.bestPath == null) {
143 return Collections.emptyList();
145 final MapEntryNode route = createRoute(ribSupport, routeKey);
146 final AdvertizedRoute<C, S, R, I> adv = new AdvertizedRoute<>(ribSupport, route, this.bestPath.getAttributes(),
147 this.bestPath.getPeerId(), this.bestPath.isDepreferenced());
148 LOG.trace("Selected best route {}", route);
149 return Collections.singletonList(adv);
153 public List<ActualBestPathRoutes<C, S, R, I>> actualBestPaths(final RIBSupport<C, S, R, I> ribSupport,
154 final RouteEntryInfo entryInfo) {
155 if (this.bestPath == null) {
156 return Collections.emptyList();
158 final MapEntryNode route = createRoute(ribSupport, entryInfo.getRouteKey());
159 return Collections.singletonList(new ActualBestPathRoutes<>(ribSupport, route, this.bestPath.getPeerId(),
160 this.bestPath.getAttributes(), this.bestPath.isDepreferenced()));