Convert LocRibWriter to DOM APIs
[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.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;
34
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);
43         }
44
45         @Override
46         public List<NodeIdentifierWithPredicates> getStaleRouteKeyIdentifiers() {
47             return Collections.singletonList(getNonAddPathRouteKeyIdentifier());
48         }
49
50         @Override
51         public List<NodeIdentifierWithPredicates> getAddPathRouteKeyIdentifiers() {
52             return Collections.emptyList();
53         }
54
55         @Override
56         public boolean isNonAddPathBestPathNew() {
57             return true;
58         }
59     }
60
61     private static final Logger LOG = LoggerFactory.getLogger(BaseRouteEntry.class);
62     private static final MapEntryNode[] EMPTY_VALUES = new MapEntryNode[0];
63
64     private RouterIdOffsets offsets = RouterIdOffsets.EMPTY;
65     private MapEntryNode[] values = EMPTY_VALUES;
66     private BaseBestPath bestPath;
67     private BaseBestPath removedBestPath;
68
69     BaseRouteEntry() {
70     }
71
72     @Override
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();
78     }
79
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());
83     }
84
85     @Override
86     public boolean selectBest(final RIBSupport<C, S, R, I> ribSupport, final long localAs) {
87         /*
88          * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
89          */
90         final BasePathSelector selector = new BasePathSelector(localAs);
91
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);
98         }
99
100         // Get the newly-selected best path.
101         final BaseBestPath newBestPath = selector.result();
102         final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
103         if (modified) {
104             if (this.offsets.isEmpty()) {
105                 this.removedBestPath = this.bestPath;
106             }
107             LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
108             this.bestPath = newBestPath;
109         }
110         return modified;
111     }
112
113     @Override
114     public int addRoute(final RouterId routerId, final Uint32 remotePathId, final MapEntryNode route) {
115         int offset = this.offsets.offsetOf(routerId);
116         if (offset < 0) {
117             final RouterIdOffsets newOffsets = this.offsets.with(routerId);
118             offset = newOffsets.offsetOf(routerId);
119
120             this.values = newOffsets.expand(this.offsets, this.values, offset);
121             this.offsets = newOffsets;
122         }
123
124         this.offsets.setValue(this.values, offset, route);
125         LOG.trace("Added route {} from {}", route, routerId);
126         return offset;
127     }
128
129     @Override
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();
134         }
135         removedBestPath = null;
136         return Optional.of(new Stale<C, S, R, I>(ribSupport.createRouteListArgument(routeKey)));
137     }
138
139     @Override
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();
144         }
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);
150     }
151
152     @Override
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();
157         }
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()));
161     }
162 }