Bump upstreams
[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 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.rib.Tables;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
22 import org.opendaylight.yangtools.yang.binding.ChildOf;
23 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.common.Uint32;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
27 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 final class BaseRouteEntry<C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
33         implements RouteEntry<C, S> {
34     private static final class Stale extends StaleBestPathRoute {
35         Stale(final NodeIdentifierWithPredicates nonAddPathRouteKeyIdentifier) {
36             super(nonAddPathRouteKeyIdentifier);
37         }
38
39         @Override
40         public List<NodeIdentifierWithPredicates> getStaleRouteKeyIdentifiers() {
41             return Collections.singletonList(getNonAddPathRouteKeyIdentifier());
42         }
43
44         @Override
45         public List<NodeIdentifierWithPredicates> getAddPathRouteKeyIdentifiers() {
46             return Collections.emptyList();
47         }
48
49         @Override
50         public boolean isNonAddPathBestPathNew() {
51             return true;
52         }
53     }
54
55     private static final Logger LOG = LoggerFactory.getLogger(BaseRouteEntry.class);
56     private static final MapEntryNode[] EMPTY_VALUES = new MapEntryNode[0];
57
58     private RouterIdOffsets offsets = RouterIdOffsets.EMPTY;
59     private MapEntryNode[] values = EMPTY_VALUES;
60     private BaseBestPath bestPath = null;
61     private BaseBestPath removedBestPath;
62
63     @Override
64     public boolean removeRoute(final RouterId routerId, final Uint32 remotePathId) {
65         final int offset = offsets.offsetOf(routerId);
66         values = offsets.removeValue(values, offset, EMPTY_VALUES);
67         offsets = offsets.without(routerId);
68         return offsets.isEmpty();
69     }
70
71     private MapEntryNode createRoute(final RIBSupport<C, S> ribSup, final String routeKey) {
72         final MapEntryNode route = offsets.getValue(values, offsets.offsetOf(bestPath.getRouterId()));
73         return ribSup.createRoute(route, ribSup.createRouteListArgument(routeKey), bestPath.getAttributes());
74     }
75
76     @Override
77     public boolean selectBest(final RIBSupport<C, S> ribSupport, final long localAs) {
78         /*
79          * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
80          */
81         final BasePathSelector selector = new BasePathSelector(localAs);
82
83         // Select the best route.
84         for (int i = 0; i < offsets.size(); ++i) {
85             final RouterId routerId = offsets.getKey(i);
86             final ContainerNode attributes = ribSupport.extractAttributes(offsets.getValue(values, i));
87             LOG.trace("Processing router id {} attributes {}", routerId, attributes);
88             selector.processPath(routerId, attributes);
89         }
90
91         // Get the newly-selected best path.
92         final BaseBestPath newBestPath = selector.result();
93         final boolean modified = newBestPath == null || !newBestPath.equals(bestPath);
94         if (modified) {
95             if (offsets.isEmpty()) {
96                 removedBestPath = bestPath;
97             }
98             LOG.trace("Previous best {}, current best {}", bestPath, newBestPath);
99             bestPath = newBestPath;
100         }
101         return modified;
102     }
103
104     @Override
105     public int addRoute(final RouterId routerId, final Uint32 remotePathId, final MapEntryNode route) {
106         int offset = offsets.offsetOf(routerId);
107         if (offset < 0) {
108             final RouterIdOffsets newOffsets = offsets.with(routerId);
109             offset = newOffsets.offsetOf(routerId);
110
111             values = newOffsets.expand(offsets, values, offset);
112             offsets = newOffsets;
113         }
114
115         offsets.setValue(values, offset, route);
116         LOG.trace("Added route {} from {}", route, routerId);
117         return offset;
118     }
119
120     @Override
121     public Optional<StaleBestPathRoute> removeStalePaths(final RIBSupport<C, S> ribSupport, final String routeKey) {
122         if (removedBestPath == null) {
123             return Optional.empty();
124         }
125         removedBestPath = null;
126         return Optional.of(new Stale(ribSupport.createRouteListArgument(routeKey)));
127     }
128
129     @Override
130     public List<AdvertizedRoute<C, S>> newBestPaths(final RIBSupport<C, S> ribSupport, final String routeKey) {
131         if (bestPath == null) {
132             return Collections.emptyList();
133         }
134         final MapEntryNode route = createRoute(ribSupport, routeKey);
135         final AdvertizedRoute<C, S> adv = new AdvertizedRoute<>(ribSupport, route, bestPath.getAttributes(),
136                 bestPath.getPeerId(), bestPath.isDepreferenced());
137         LOG.trace("Selected best route {}", route);
138         return Collections.singletonList(adv);
139     }
140
141     @Override
142     public List<ActualBestPathRoutes<C, S>> actualBestPaths(final RIBSupport<C, S> ribSupport,
143             final RouteEntryInfo entryInfo) {
144         if (bestPath == null) {
145             return Collections.emptyList();
146         }
147         final MapEntryNode route = createRoute(ribSupport, entryInfo.getRouteKey());
148         return Collections.singletonList(new ActualBestPathRoutes<>(ribSupport, route, bestPath.getPeerId(),
149                 bestPath.getAttributes(), bestPath.isDepreferenced()));
150     }
151 }