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 javax.annotation.concurrent.NotThreadSafe;
13 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
14 import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry;
15 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
16 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
17 import org.opendaylight.protocol.bgp.rib.spi.Peer;
18 import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup;
19 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
20 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryDependenciesContainer;
21 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryInfo;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerRole;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.TablesKey;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
28 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 abstract class BaseAbstractRouteEntry extends AbstractRouteEntry<BaseBestPath> {
37 private static final Logger LOG = LoggerFactory.getLogger(BaseAbstractRouteEntry.class);
38 private static final ContainerNode[] EMPTY_ATTRIBUTES = new ContainerNode[0];
39 private OffsetMap offsets = OffsetMap.EMPTY;
40 private ContainerNode[] values = EMPTY_ATTRIBUTES;
41 private BaseBestPath bestPath;
42 private BaseBestPath removedBestPath;
44 BaseAbstractRouteEntry(final BGPPeerTracker peerTracker) {
51 * @param routerId router ID in unsigned integer
52 * @param offset of removed route
53 * @return true if its the last route
55 protected final boolean removeRoute(final UnsignedInteger routerId, final int offset) {
56 this.values = this.offsets.removeValue(this.values, offset);
57 this.offsets = this.offsets.without(routerId);
58 return this.offsets.isEmpty();
62 public final boolean selectBest(final long localAs) {
64 * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
66 final BasePathSelector selector = new BasePathSelector(localAs);
68 // Select the best route.
69 for (int i = 0; i < this.offsets.size(); ++i) {
70 final UnsignedInteger routerId = this.offsets.getRouterKey(i);
71 final ContainerNode attributes = this.offsets.getValue(this.values, i);
72 LOG.trace("Processing router id {} attributes {}", routerId, attributes);
73 selector.processPath(routerId, attributes);
76 // Get the newly-selected best path.
77 final BaseBestPath newBestPath = selector.result();
78 final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
80 if (this.offsets.isEmpty()) {
81 this.removedBestPath = this.bestPath;
83 LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
84 this.bestPath = newBestPath;
90 public int addRoute(final UnsignedInteger routerId, final Long remotePathId,
91 final NodeIdentifier attributesIdentifier, final NormalizedNode<?, ?> data) {
92 LOG.trace("Find {} in {}", attributesIdentifier, data);
93 final ContainerNode advertisedAttrs
94 = (ContainerNode) NormalizedNodes
95 .findNode(data, attributesIdentifier).orElse(null);
96 int offset = this.offsets.offsetOf(routerId);
98 final OffsetMap newOffsets = this.offsets.with(routerId);
99 offset = newOffsets.offsetOf(routerId);
101 this.values = newOffsets.expand(this.offsets, this.values, offset);
102 this.offsets = newOffsets;
105 this.offsets.setValue(this.values, offset, advertisedAttrs);
106 LOG.trace("Added route from {} attributes {}", routerId, advertisedAttrs);
111 public void updateBestPaths(final RouteEntryDependenciesContainer entryDependencies,
112 final NodeIdentifierWithPredicates routeIdPA,
113 final DOMDataWriteTransaction tx) {
114 if (this.removedBestPath != null) {
115 removePathFromDataStore(entryDependencies, routeIdPA, tx);
116 this.removedBestPath = null;
118 if (this.bestPath != null) {
119 addPathToDataStore(entryDependencies, routeIdPA, tx);
124 public void initializeBestPaths(final RouteEntryDependenciesContainer entryDep,
125 final RouteEntryInfo entryInfo, final PeerExportGroup peerGroup, final DOMDataWriteTransaction tx) {
126 if (this.bestPath != null) {
127 final TablesKey localTK = entryDep.getLocalTablesKey();
128 final BaseBestPath path = this.bestPath;
129 final PeerId toPeerId = entryInfo.getToPeerId();
130 if (filterRoutes(path.getPeerId(), toPeerId, localTK)) {
131 final NodeIdentifierWithPredicates routeId = entryInfo.getRouteId();
132 final RIBSupport ribSupport = entryDep.getRibSupport();
133 NodeIdentifierWithPredicates routeIdDest = ribSupport.getRouteIdAddPath(path.getPathId(), routeId);
134 if (routeIdDest == null) {
135 routeIdDest = routeId;
137 final Peer fromPeer = this.peerTracker.getPeer(path.getPeerId());
138 final ContainerNode effAttrib = peerGroup.effectiveAttributes(
139 fromPeer.getRole(), path.getAttributes());
140 final YangInstanceIdentifier rootPath = entryInfo.getRootPath();
141 writeRoute(toPeerId, getAdjRibOutYII(ribSupport, rootPath, routeIdDest, localTK), effAttrib,
142 createValue(routeIdDest, path), ribSupport, tx);
147 private void removePathFromDataStore(final RouteEntryDependenciesContainer entryDep,
148 final NodeIdentifierWithPredicates routeIdPA, final DOMDataWriteTransaction tx) {
149 LOG.trace("Best Path removed {}", this.removedBestPath);
150 final YangInstanceIdentifier locRibTarget = entryDep.getLocRibTableTarget();
151 final RIBSupport ribSup = entryDep.getRibSupport();
152 NodeIdentifierWithPredicates routeIdTarget
153 = ribSup.getRouteIdAddPath(this.removedBestPath.getPathId(), routeIdPA);
154 if (routeIdTarget == null) {
155 routeIdTarget = routeIdPA;
157 fillLocRib(ribSup.routePath(locRibTarget.node(ROUTES_IDENTIFIER), routeIdTarget), null, tx);
158 fillAdjRibsOut(null, null, routeIdTarget, this.removedBestPath.getPeerId(), entryDep, tx);
161 private void addPathToDataStore(final RouteEntryDependenciesContainer entryDep,
162 final NodeIdentifierWithPredicates routeIdPA, final DOMDataWriteTransaction tx) {
163 final RIBSupport ribSup = entryDep.getRibSupport();
164 final YangInstanceIdentifier locRibTarget = entryDep.getLocRibTableTarget();
165 NodeIdentifierWithPredicates routeIdDest = ribSup.getRouteIdAddPath(this.bestPath.getPathId(), routeIdPA);
166 if (routeIdDest == null) {
167 routeIdDest = routeIdPA;
170 final MapEntryNode value = createValue(routeIdDest, this.bestPath);
171 LOG.trace("Selected best value {}", value);
173 final YangInstanceIdentifier pathAddPathTarget
174 = ribSup.routePath(locRibTarget.node(ROUTES_IDENTIFIER), routeIdDest);
175 fillLocRib(pathAddPathTarget, value, tx);
176 fillAdjRibsOut(this.bestPath.getAttributes(), value, routeIdDest, this.bestPath.getPeerId(), entryDep, tx);
179 final OffsetMap getOffsets() {
184 private void fillAdjRibsOut(final ContainerNode attributes, final MapEntryNode value,
185 final NodeIdentifierWithPredicates routeIdPA, final PeerId fromPeerId,
186 final RouteEntryDependenciesContainer routeEntryDep,
187 final DOMDataWriteTransaction tx) {
189 * We need to keep track of routers and populate adj-ribs-out, too. If we do not, we need to
190 * expose from which client a particular route was learned from in the local RIB, and have
191 * the listener perform filtering.
193 * We walk the policy set in order to minimize the amount of work we do for multiple peers:
194 * if we have two eBGP peers, for example, there is no reason why we should perform the translation
197 final RIBSupport ribSup = routeEntryDep.getRibSupport();
198 final ExportPolicyPeerTracker peerPT = routeEntryDep.getExportPolicyPeerTracker();
199 final TablesKey localTK = routeEntryDep.getLocalTablesKey();
200 for (final PeerRole role : PeerRole.values()) {
201 final PeerExportGroup peerGroup = peerPT.getPeerGroup(role);
202 if (peerGroup != null) {
203 final Peer fromPeer = this.peerTracker.getPeer(fromPeerId);
204 final ContainerNode effAttrib = peerGroup.effectiveAttributes(fromPeer.getRole(), attributes);
205 peerGroup.forEach((destPeer, rootPath) -> {
206 if (!filterRoutes(fromPeerId, destPeer, localTK)) {
209 update(destPeer, getAdjRibOutYII(ribSup, rootPath, routeIdPA, localTK), effAttrib, value, ribSup,