Pass PathIds to StaleBestRoute
[bgpcep.git] / bgp / path-selection-mode / src / main / java / org / opendaylight / protocol / bgp / mode / impl / base / BaseRouteEntry.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.mode.impl.base;
9
10 import static org.opendaylight.protocol.bgp.parser.spi.PathIdUtil.NON_PATH_ID;
11
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.Optional;
15 import javax.annotation.concurrent.NotThreadSafe;
16 import org.opendaylight.protocol.bgp.mode.api.RouteEntry;
17 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
18 import org.opendaylight.protocol.bgp.rib.spi.RouterId;
19 import org.opendaylight.protocol.bgp.rib.spi.entry.ActualBestPathRoutes;
20 import org.opendaylight.protocol.bgp.rib.spi.entry.AdvertizedRoute;
21 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryInfo;
22 import org.opendaylight.protocol.bgp.rib.spi.entry.StaleBestPathRoute;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
27 import org.opendaylight.yangtools.yang.binding.ChildOf;
28 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.opendaylight.yangtools.yang.binding.Identifiable;
31 import org.opendaylight.yangtools.yang.binding.Identifier;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 @NotThreadSafe
36 final class BaseRouteEntry<C extends Routes & DataObject & ChoiceIn<Tables>,
37         S extends ChildOf<? super C>,
38         R extends Route & ChildOf<? super S> & Identifiable<I>,
39         I extends Identifier<R>> implements RouteEntry<C,S,R,I> {
40     private static final Logger LOG = LoggerFactory.getLogger(BaseRouteEntry.class);
41     private static final Route[] EMPTY_VALUES = new Route[0];
42
43     private RouterIdOffsets offsets = RouterIdOffsets.EMPTY;
44     private R[] values = (R[]) EMPTY_VALUES;
45     private BaseBestPath bestPath;
46     private BaseBestPath removedBestPath;
47
48     BaseRouteEntry() {
49     }
50
51     @Override
52     public boolean removeRoute(final RouterId routerId, final Long remotePathId) {
53         final int offset = this.offsets.offsetOf(routerId);
54         this.values = this.offsets.removeValue(this.values, offset, (R[]) EMPTY_VALUES);
55         this.offsets = this.offsets.without(routerId);
56         return this.offsets.isEmpty();
57     }
58
59     private R createRoute(final RIBSupport<C, S, R, I> ribSup, final String routeKey) {
60         final I key = ribSup.createRouteListKey(routeKey);
61         final R route = this.offsets.getValue(this.values, this.offsets.offsetOf(bestPath.getRouterId()));
62         return ribSup.createRoute(route, key, bestPath.getAttributes());
63     }
64
65     @Override
66     public boolean selectBest(final long localAs) {
67         /*
68          * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
69          */
70         final BasePathSelector selector = new BasePathSelector(localAs);
71
72         // Select the best route.
73         for (int i = 0; i < this.offsets.size(); ++i) {
74             final RouterId routerId = this.offsets.getKey(i);
75             final Attributes attributes = this.offsets.getValue(this.values, i).getAttributes();
76             LOG.trace("Processing router id {} attributes {}", routerId, attributes);
77             selector.processPath(routerId, attributes);
78         }
79
80         // Get the newly-selected best path.
81         final BaseBestPath newBestPath = selector.result();
82         final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
83         if (modified) {
84             if (this.offsets.isEmpty()) {
85                 this.removedBestPath = this.bestPath;
86             }
87             LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
88             this.bestPath = newBestPath;
89         }
90         return modified;
91     }
92
93     @Override
94     public int addRoute(final RouterId routerId, final Long remotePathId, final R route) {
95         int offset = this.offsets.offsetOf(routerId);
96         if (offset < 0) {
97             final RouterIdOffsets newOffsets = this.offsets.with(routerId);
98             offset = newOffsets.offsetOf(routerId);
99
100             this.values = newOffsets.expand(this.offsets, this.values, offset);
101             this.offsets = newOffsets;
102         }
103
104         this.offsets.setValue(this.values, offset, route);
105         LOG.trace("Added route {} from {}", route, routerId);
106         return offset;
107     }
108
109     @Override
110     public Optional<StaleBestPathRoute<C, S, R, I>> removeStalePaths(final RIBSupport<C, S, R, I> ribSupport,
111             final String routeKey) {
112         if (this.removedBestPath == null) {
113             return Optional.empty();
114         }
115         final StaleBestPathRoute<C, S, R, I> stale = new StaleBestPathRoute<>(ribSupport, routeKey,
116                 Collections.singletonList(NON_PATH_ID), Collections.emptyList(), true);
117         this.removedBestPath = null;
118         return Optional.of(stale);
119     }
120
121     @Override
122     public List<AdvertizedRoute<C, S, R, I>> newBestPaths(final RIBSupport<C, S, R, I> ribSupport,
123             final String routeKey) {
124         if (this.bestPath == null) {
125             return Collections.emptyList();
126         }
127         final R route = createRoute(ribSupport, routeKey);
128         final AdvertizedRoute<C, S, R, I> adv = new AdvertizedRoute<>(ribSupport, route, this.bestPath.getAttributes(),
129                 this.bestPath.getPeerId(), this.bestPath.isDepreferenced());
130         LOG.trace("Selected best route {}", route);
131         return Collections.singletonList(adv);
132     }
133
134     @Override
135     public List<ActualBestPathRoutes<C, S, R, I>> actualBestPaths(final RIBSupport<C, S, R, I> ribSupport,
136             final RouteEntryInfo entryInfo) {
137         if (this.bestPath == null) {
138             return Collections.emptyList();
139         }
140         final R route = createRoute(ribSupport, entryInfo.getRouteKey());
141         return Collections.singletonList(new ActualBestPathRoutes<>(ribSupport, route, this.bestPath.getPeerId(),
142                 this.bestPath.getAttributes(), this.bestPath.isDepreferenced()));
143     }
144 }