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.api.BestPath;
15 import org.opendaylight.protocol.bgp.mode.spi.AbstractRouteEntry;
16 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
17 import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup;
18 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerRole;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.TablesKey;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
25 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
33 abstract class BaseAbstractRouteEntry extends AbstractRouteEntry {
34 private static final Logger LOG = LoggerFactory.getLogger(BaseAbstractRouteEntry.class);
35 private static final ContainerNode[] EMPTY_ATTRIBUTES = new ContainerNode[0];
36 private OffsetMap offsets = OffsetMap.EMPTY;
37 private ContainerNode[] values = EMPTY_ATTRIBUTES;
38 private BaseBestPath bestPath;
39 private BaseBestPath removedBestPath;
44 * @param routerId router ID in unsigned integer
45 * @param offset of removed route
46 * @return true if its the last route
48 protected final boolean removeRoute(final UnsignedInteger routerId, final int offset) {
49 this.values = this.offsets.removeValue(this.values, offset);
50 this.offsets = this.offsets.without(routerId);
51 return this.offsets.isEmpty();
55 public final boolean selectBest(final long localAs) {
57 * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
59 final BasePathSelector selector = new BasePathSelector(localAs);
61 // Select the best route.
62 for (int i = 0; i < this.offsets.size(); ++i) {
63 final UnsignedInteger routerId = this.offsets.getRouterKey(i);
64 final ContainerNode attributes = this.offsets.getValue(this.values, i);
65 LOG.trace("Processing router id {} attributes {}", routerId, attributes);
66 selector.processPath(routerId, attributes);
69 // Get the newly-selected best path.
70 final BaseBestPath newBestPath = selector.result();
71 final boolean modified = newBestPath == null || !newBestPath.equals(this.bestPath);
73 if (this.offsets.isEmpty()) {
74 this.removedBestPath = this.bestPath;
76 LOG.trace("Previous best {}, current best {}", this.bestPath, newBestPath);
77 this.bestPath = newBestPath;
83 public int addRoute(final UnsignedInteger routerId, final Long remotePathId,
84 final NodeIdentifier attributesIdentifier, final NormalizedNode<?, ?> data) {
85 LOG.trace("Find {} in {}", attributesIdentifier, data);
86 final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes
87 .findNode(data, attributesIdentifier).orElse(null);
88 int offset = this.offsets.offsetOf(routerId);
90 final OffsetMap newOffsets = this.offsets.with(routerId);
91 offset = newOffsets.offsetOf(routerId);
93 this.values = newOffsets.expand(this.offsets, this.values, offset);
94 this.offsets = newOffsets;
97 this.offsets.setValue(this.values, offset, advertisedAttrs);
98 LOG.trace("Added route from {} attributes {}", routerId, advertisedAttrs);
103 public void updateRoute(final TablesKey localTK, final ExportPolicyPeerTracker peerPT,
104 final YangInstanceIdentifier locRibTarget, final RIBSupport ribSup,
105 final DOMDataWriteTransaction tx, final PathArgument routeIdPA) {
106 if (this.removedBestPath != null) {
107 removePathFromDataStore(this.removedBestPath, routeIdPA, locRibTarget, peerPT, localTK, ribSup, tx);
108 this.removedBestPath = null;
110 if (this.bestPath != null) {
111 addPathToDataStore(this.bestPath, routeIdPA, locRibTarget, ribSup, peerPT, localTK, tx);
116 public void writeRoute(final PeerId destPeer, final PathArgument routeId, final YangInstanceIdentifier rootPath,
117 final PeerExportGroup peerGroup, final TablesKey localTK, final ExportPolicyPeerTracker peerPT,
118 final RIBSupport ribSupport, final DOMDataWriteTransaction tx) {
119 if (this.bestPath != null) {
120 final BaseBestPath path = this.bestPath;
121 final PeerRole destPeerRole = getRoutePeerIdRole(peerPT, destPeer);
122 if (filterRoutes(path.getPeerId(), destPeer, peerPT, localTK, destPeerRole)) {
123 PathArgument routeIdDest = ribSupport.getRouteIdAddPath(path.getPathId(), routeId);
124 if (routeIdDest == null) {
125 routeIdDest = routeId;
127 final ContainerNode effAttrib = peerGroup.effectiveAttributes(
128 getRoutePeerIdRole(peerPT, path.getPeerId()), path.getAttributes());
129 writeRoute(destPeer, getAdjRibOutYII(ribSupport, rootPath, routeIdDest, localTK), effAttrib,
130 createValue(routeIdDest, path), ribSupport, tx);
135 private void removePathFromDataStore(final BestPath path, final PathArgument routeIdPA,
136 final YangInstanceIdentifier locRibTarget, final ExportPolicyPeerTracker peerPT,
137 final TablesKey localTK, final RIBSupport ribSup, final DOMDataWriteTransaction tx) {
138 LOG.trace("Best Path removed {}", path);
139 PathArgument routeIdTarget = ribSup.getRouteIdAddPath(path.getPathId(), routeIdPA);
140 if (routeIdTarget == null) {
141 routeIdTarget = routeIdPA;
143 fillLocRib(ribSup.routePath(locRibTarget.node(ROUTES_IDENTIFIER), routeIdTarget), null, tx);
144 fillAdjRibsOut(null, null, routeIdTarget, path.getPeerId(), peerPT, localTK, ribSup, tx);
147 private void addPathToDataStore(final BestPath path, final PathArgument routeIdPA,
148 final YangInstanceIdentifier locRibTarget, final RIBSupport ribSup, final ExportPolicyPeerTracker peerPT,
149 final TablesKey localTK, final DOMDataWriteTransaction tx) {
150 PathArgument routeIdDest = ribSup.getRouteIdAddPath(path.getPathId(), routeIdPA);
151 if (routeIdDest == null) {
152 routeIdDest = routeIdPA;
155 final MapEntryNode value = createValue(routeIdDest, path);
156 LOG.trace("Selected best value {}", value);
158 final YangInstanceIdentifier pathAddPathTarget
159 = ribSup.routePath(locRibTarget.node(ROUTES_IDENTIFIER), routeIdDest);
160 fillLocRib(pathAddPathTarget, value, tx);
161 fillAdjRibsOut(path.getAttributes(), value, routeIdDest, path.getPeerId(), peerPT, localTK, ribSup, tx);
164 final OffsetMap getOffsets() {
169 private void fillAdjRibsOut(final ContainerNode attributes, final MapEntryNode value,
170 final PathArgument routeId, final PeerId routePeerId, final ExportPolicyPeerTracker peerPT,
171 final TablesKey localTK, final RIBSupport ribSup, final DOMDataWriteTransaction tx) {
173 * We need to keep track of routers and populate adj-ribs-out, too. If we do not, we need to
174 * expose from which client a particular route was learned from in the local RIB, and have
175 * the listener perform filtering.
177 * We walk the policy set in order to minimize the amount of work we do for multiple peers:
178 * if we have two eBGP peers, for example, there is no reason why we should perform the translation
181 for (final PeerRole role : PeerRole.values()) {
182 final PeerExportGroup peerGroup = peerPT.getPeerGroup(role);
183 if (peerGroup != null) {
184 final ContainerNode effAttrib = peerGroup.effectiveAttributes(getRoutePeerIdRole(peerPT, routePeerId),
186 peerGroup.forEach((destPeer, rootPath) -> {
187 if (!filterRoutes(routePeerId, destPeer, peerPT, localTK, getRoutePeerIdRole(peerPT, destPeer))) {
190 update(destPeer, getAdjRibOutYII(ribSup, rootPath, routeId, localTK), effAttrib, value, ribSup, tx);