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 javax.annotation.concurrent.NotThreadSafe;
14 import org.opendaylight.protocol.bgp.mode.api.RouteEntry;
15 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
16 import org.opendaylight.protocol.bgp.rib.spi.RouterId;
17 import org.opendaylight.protocol.bgp.rib.spi.entry.ActualBestPathRoutes;
18 import org.opendaylight.protocol.bgp.rib.spi.entry.AdvertizedRoute;
19 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryInfo;
20 import org.opendaylight.protocol.bgp.rib.spi.entry.StaleBestPathRoute;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
25 import org.opendaylight.yangtools.yang.binding.ChildOf;
26 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.binding.Identifiable;
29 import org.opendaylight.yangtools.yang.binding.Identifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 final class BaseRouteEntry<C extends Routes & DataObject & ChoiceIn<Tables>,
35 S extends ChildOf<? super C>,
36 R extends Route & ChildOf<? super S> & Identifiable<I>,
37 I extends Identifier<R>> implements RouteEntry<C,S,R,I> {
38 private static final Logger LOG = LoggerFactory.getLogger(BaseRouteEntry.class);
39 private static final Route[] EMPTY_VALUES = new Route[0];
41 private OffsetMap offsets = OffsetMap.EMPTY;
42 private R[] values = (R[]) EMPTY_VALUES;
43 private BaseBestPath bestPath;
44 private BaseBestPath removedBestPath;
50 public boolean removeRoute(final RouterId routerId, final Long remotePathId) {
51 final int offset = this.offsets.offsetOf(routerId);
52 this.values = this.offsets.removeValue(this.values, offset, (R[]) EMPTY_VALUES);
53 this.offsets = this.offsets.without(routerId);
54 return this.offsets.isEmpty();
57 private R createRoute(final RIBSupport<C, S, R, I> ribSup, final String routeKey) {
58 final I key = ribSup.createRouteListKey(routeKey);
59 final R route = this.offsets.getValue(this.values, this.offsets.offsetOf(bestPath.getRouterId()));
60 return ribSup.createRoute(route, key, bestPath.getAttributes());
64 public boolean selectBest(final long localAs) {
66 * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
68 final BasePathSelector selector = new BasePathSelector(localAs);
70 // Select the best route.
71 for (int i = 0; i < this.offsets.size(); ++i) {
72 final RouterId routerId = this.offsets.getRouterKey(i);
73 final Attributes attributes = this.offsets.getValue(this.values, i).getAttributes();
74 LOG.trace("Processing router id {} attributes {}", routerId, attributes);
75 selector.processPath(routerId, attributes);
78 // Get the newly-selected best path.
79 final BaseBestPath newBestPath = selector.result();
80 final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
82 if (this.offsets.isEmpty()) {
83 this.removedBestPath = this.bestPath;
85 LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
86 this.bestPath = newBestPath;
92 public int addRoute(final RouterId routerId, final Long remotePathId, final R route) {
93 int offset = this.offsets.offsetOf(routerId);
95 final OffsetMap newOffsets = this.offsets.with(routerId);
96 offset = newOffsets.offsetOf(routerId);
98 this.values = newOffsets.expand(this.offsets, this.values, offset);
99 this.offsets = newOffsets;
102 this.offsets.setValue(this.values, offset, route);
103 LOG.trace("Added route {} from {}", route, routerId);
108 public Optional<StaleBestPathRoute<C, S, R, I>> removeStalePaths(final RIBSupport<C, S, R, I> ribSupport,
109 final String routeKey) {
110 if (this.removedBestPath == null) {
111 return Optional.empty();
113 final StaleBestPathRoute<C, S, R, I> stale = new StaleBestPathRoute<>(ribSupport, routeKey);
114 this.removedBestPath = null;
115 return Optional.of(stale);
119 public List<AdvertizedRoute<C, S, R, I>> newBestPaths(final RIBSupport<C, S, R, I> ribSupport,
120 final String routeKey) {
121 if (this.bestPath == null) {
122 return Collections.emptyList();
124 final R route = createRoute(ribSupport, routeKey);
125 final AdvertizedRoute<C, S, R, I> adv = new AdvertizedRoute<>(ribSupport, route, this.bestPath.getAttributes(),
126 this.bestPath.getPeerId(), this.bestPath.isDepreferenced());
127 LOG.trace("Selected best route {}", route);
128 return Collections.singletonList(adv);
132 public List<ActualBestPathRoutes<C, S, R, I>> actualBestPaths(final RIBSupport<C, S, R, I> ribSupport,
133 final RouteEntryInfo entryInfo) {
134 if (this.bestPath == null) {
135 return Collections.emptyList();
137 final R route = createRoute(ribSupport, entryInfo.getRouteKey());
138 return Collections.singletonList(new ActualBestPathRoutes<>(ribSupport, route, this.bestPath.getPeerId(),
139 this.bestPath.getAttributes(), this.bestPath.isDepreferenced()));