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 com.google.common.annotations.VisibleForTesting;
11 import com.google.common.primitives.UnsignedInteger;
12 import java.util.Optional;
13 import javax.annotation.Nullable;
14 import javax.annotation.concurrent.NotThreadSafe;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.protocol.bgp.mode.impl.BGPRouteEntryExportParametersImpl;
18 import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry;
19 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
20 import org.opendaylight.protocol.bgp.rib.spi.Peer;
21 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
22 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryDependenciesContainer;
23 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryInfo;
24 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
25 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryExportParameters;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
31 import org.opendaylight.yangtools.yang.binding.Identifier;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 abstract class BaseAbstractRouteEntry extends AbstractRouteEntry<BaseBestPath> {
39 private static final Logger LOG = LoggerFactory.getLogger(BaseAbstractRouteEntry.class);
40 private static final Attributes[] EMPTY_ATTRIBUTES = new Attributes[0];
41 private OffsetMap offsets = OffsetMap.EMPTY;
42 private Attributes[] values = EMPTY_ATTRIBUTES;
43 private BaseBestPath bestPath;
44 private BaseBestPath removedBestPath;
46 BaseAbstractRouteEntry(final BGPPeerTracker peerTracker) {
53 * @param routerId router ID in unsigned integer
54 * @param offset of removed route
55 * @return true if its the last route
57 protected final boolean removeRoute(final UnsignedInteger routerId, final int offset) {
58 this.values = this.offsets.removeValue(this.values, offset);
59 this.offsets = this.offsets.without(routerId);
60 return this.offsets.isEmpty();
64 public final 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 UnsignedInteger routerId = this.offsets.getRouterKey(i);
73 final Attributes attributes = this.offsets.getValue(this.values, i);
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 UnsignedInteger routerId, final long remotePathId, final Route route) {
93 final Attributes advertisedAttrs = route.getAttributes();
94 int offset = this.offsets.offsetOf(routerId);
96 final OffsetMap newOffsets = this.offsets.with(routerId);
97 offset = newOffsets.offsetOf(routerId);
99 this.values = newOffsets.expand(this.offsets, this.values, offset);
100 this.offsets = newOffsets;
103 this.offsets.setValue(this.values, offset, advertisedAttrs);
104 LOG.trace("Added route from {} attributes {}", routerId, advertisedAttrs);
109 public void updateBestPaths(
110 final RouteEntryDependenciesContainer entryDependencies,
111 final String routeKey,
112 final WriteTransaction tx) {
113 if (this.removedBestPath != null) {
114 removePathFromDataStore(entryDependencies, routeKey, tx);
115 this.removedBestPath = null;
117 if (this.bestPath != null) {
118 addPathToDataStore(entryDependencies, routeKey, tx);
123 @SuppressWarnings("unchecked")
124 public void initializeBestPaths(
125 final RouteEntryDependenciesContainer entryDep,
126 final RouteEntryInfo entryInfo,
127 final WriteTransaction tx) {
128 if (this.bestPath == null) {
131 final TablesKey localTK = entryDep.getLocalTablesKey();
132 final Peer toPeer = entryInfo.getToPeer();
133 if (!filterRoutes(this.bestPath.getPeerId(), toPeer, localTK)) {
136 final RIBSupport ribSupport = entryDep.getRibSupport();
137 Identifier routeIdentifier = ribSupport.createRouteListKey(this.bestPath.getPathId(), entryInfo.getRouteKey());
138 final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(
139 this.peerTracker.getPeer(this.bestPath.getPeerId()), toPeer);
140 final Optional<Attributes> effAttrib = entryDep.getRoutingPolicies()
141 .applyExportPolicies(routeEntry, this.bestPath.getAttributes());
142 final Route route = createRoute(ribSupport, entryInfo.getRouteKey(), this.bestPath.getPathId(), this.bestPath);
143 InstanceIdentifier ribOutIId = ribSupport.createRouteIdentifier(toPeer.getRibOutIId(localTK), routeIdentifier);
144 if (effAttrib.isPresent() && route != null) {
145 LOG.debug("Write route {} to peer AdjRibsOut {}", route, toPeer.getPeerId());
146 tx.put(LogicalDatastoreType.OPERATIONAL, ribOutIId, route);
147 tx.put(LogicalDatastoreType.OPERATIONAL, ribOutIId.child(Attributes.class), effAttrib.get());
151 @SuppressWarnings("unchecked")
152 private void removePathFromDataStore(final RouteEntryDependenciesContainer entryDep,
153 final String routeKey, final WriteTransaction tx) {
154 LOG.trace("Best Path removed {}", this.removedBestPath);
155 final KeyedInstanceIdentifier<Tables, TablesKey> locRibTarget = entryDep.getLocRibTableTarget();
156 final RIBSupport ribSup = entryDep.getRibSupport();
157 Identifier routeIdentifier = ribSup.createRouteListKey(this.removedBestPath.getPathId(), routeKey);
158 final InstanceIdentifier routeTarget = ribSup.createRouteIdentifier(locRibTarget, routeIdentifier);
159 LOG.debug("Delete route from LocRib {}", routeTarget);
160 tx.delete(LogicalDatastoreType.OPERATIONAL, routeTarget);
161 fillAdjRibsOut(null, null, routeIdentifier, this.removedBestPath.getPeerId(),
165 @SuppressWarnings("unchecked")
166 private void addPathToDataStore(final RouteEntryDependenciesContainer entryDep,
167 final String routeKey, final WriteTransaction tx) {
168 final RIBSupport ribSup = entryDep.getRibSupport();
169 final Route route = createRoute(ribSup, routeKey, this.bestPath.getPathId(), this.bestPath);
170 LOG.trace("Selected best route {}", route);
172 Identifier routeIdentifier = ribSup.createRouteListKey(this.bestPath.getPathId(), routeKey);
173 final KeyedInstanceIdentifier<Tables, TablesKey> locRibTarget = entryDep.getLocRibTableTarget();
174 final InstanceIdentifier routeTarget = ribSup.createRouteIdentifier(locRibTarget, routeIdentifier);
175 LOG.debug("Write route to LocRib {}", route);
176 tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget, route);
177 fillAdjRibsOut(this.bestPath.getAttributes(), route, routeIdentifier, this.bestPath.getPeerId(),
181 final OffsetMap getOffsets() {
186 @SuppressWarnings("unchecked")
187 private void fillAdjRibsOut(
188 @Nullable final Attributes attributes,
189 @Nullable final Route route,
190 final Identifier routeKey, final PeerId fromPeerId,
191 final RouteEntryDependenciesContainer routeEntryDep,
192 final WriteTransaction tx) {
194 * We need to keep track of routers and populate adj-ribs-out, too. If we do not, we need to
195 * expose from which client a particular route was learned from in the local RIB, and have
196 * the listener perform filtering.
198 * We walk the policy set in order to minimize the amount of work we do for multiple peers:
199 * if we have two eBGP peers, for example, there is no reason why we should perform the translation
202 final TablesKey localTK = routeEntryDep.getLocalTablesKey();
203 final BGPRibRoutingPolicy routingPolicies = routeEntryDep.getRoutingPolicies();
204 final RIBSupport ribSupport = routeEntryDep.getRibSupport();
205 for (final Peer toPeer : this.peerTracker.getPeers()) {
206 if (!filterRoutes(fromPeerId, toPeer, localTK)) {
209 Optional<Attributes> effAttr = Optional.empty();
210 final Peer fromPeer = this.peerTracker.getPeer(fromPeerId);
211 if (fromPeer != null && attributes != null) {
212 final BGPRouteEntryExportParameters routeEntry
213 = new BGPRouteEntryExportParametersImpl(fromPeer, toPeer);
214 effAttr = routingPolicies.applyExportPolicies(routeEntry, attributes);
216 final InstanceIdentifier ribOutTarget
217 = ribSupport.createRouteIdentifier(toPeer.getRibOutIId(localTK), routeKey);
218 if (effAttr.isPresent() && route != null) {
219 LOG.debug("Write route {} to peer AdjRibsOut {}", route, toPeer.getPeerId());
220 tx.put(LogicalDatastoreType.OPERATIONAL, ribOutTarget, route);
221 tx.put(LogicalDatastoreType.OPERATIONAL, ribOutTarget.child(Attributes.class), effAttr.get());
223 LOG.trace("Removing {} from transaction for peer {}", ribOutTarget, toPeer.getPeerId());
224 tx.delete(LogicalDatastoreType.OPERATIONAL, ribOutTarget);