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.rib.impl;
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
13 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBIN_NID;
14 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ATTRIBUTES_NID;
15 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.EFFRIBIN_NID;
16 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.LLGR_STALE_NID;
17 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ROUTES_NID;
18 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID;
19 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.UPTODATE_NID;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.util.concurrent.FluentFuture;
25 import com.google.common.util.concurrent.FutureCallback;
26 import com.google.common.util.concurrent.MoreExecutors;
27 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
28 import java.util.Collection;
29 import java.util.List;
31 import java.util.Optional;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.atomic.LongAdder;
35 import org.checkerframework.checker.lock.qual.GuardedBy;
36 import org.checkerframework.checker.lock.qual.Holding;
37 import org.eclipse.jdt.annotation.NonNull;
38 import org.eclipse.jdt.annotation.Nullable;
39 import org.opendaylight.mdsal.common.api.CommitInfo;
40 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
41 import org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener;
42 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
43 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
44 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
45 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
46 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
47 import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
52 import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesInstalledCounters;
53 import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesReceivedCounters;
54 import org.opendaylight.protocol.bgp.rib.spi.RIBNormalizedNodes;
55 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
56 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
57 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
58 import org.opendaylight.protocol.bgp.route.targetcontrain.spi.ClientRouteTargetContrainCache;
59 import org.opendaylight.protocol.bgp.route.targetcontrain.spi.RouteTargetMembeshipUtil;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.Communities;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.RouteTargetConstrainSubsequentAddressFamily;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.route.target.constrain.routes.route.target.constrain.routes.RouteTargetConstrainRoute;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.Ipv4AddressFamily;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.Ipv6AddressFamily;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.MplsLabeledVpnSubsequentAddressFamily;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteTarget;
70 import org.opendaylight.yangtools.concepts.ListenerRegistration;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
74 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
77 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
80 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
81 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
82 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
83 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
84 import org.opendaylight.yangtools.yang.data.tree.api.ModificationType;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
89 * Implementation of the BGP import policy. Listens on peer's Adj-RIB-In, inspects all inbound
90 * routes in the context of the advertising peer's role and applies the inbound policy.
93 * Inbound policy is applied as follows:
96 * 1) if the peer is an eBGP peer, perform attribute replacement and filtering
97 * 2) check if a route is admissible based on attributes attached to it, as well as the
98 * advertising peer's role
99 * 3) output admitting routes with edited attributes into /bgp-rib/rib/peer/effective-rib-in/tables/routes
102 * This class is NOT thread-safe.
104 final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesInstalledCounters,
105 AutoCloseable, ClusteredDOMDataTreeChangeListener {
107 private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
108 private static final TablesKey IVP4_VPN_TABLE_KEY =
109 new TablesKey(Ipv4AddressFamily.VALUE, MplsLabeledVpnSubsequentAddressFamily.VALUE);
110 private static final TablesKey IVP6_VPN_TABLE_KEY =
111 new TablesKey(Ipv6AddressFamily.VALUE, MplsLabeledVpnSubsequentAddressFamily.VALUE);
112 private static final ImmutableList<Communities> STALE_LLGR_COMMUNUTIES =
113 ImmutableList.of(StaleCommunities.STALE_LLGR);
114 private static final Attributes STALE_LLGR_ATTRIBUTES = new org.opendaylight.yang.gen.v1.urn.opendaylight.params
115 .xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder()
116 .setCommunities(STALE_LLGR_COMMUNUTIES)
118 private static final ChoiceNode EMPTY_ROUTES = Builders.choiceBuilder().withNodeIdentifier(ROUTES_NID).build();
120 private final RIBSupportContextRegistry registry;
121 private final YangInstanceIdentifier peerIId;
122 private final YangInstanceIdentifier effRibTables;
123 private final DOMDataTreeChangeService service;
124 private final List<RouteTarget> rtMemberships;
125 private final RibOutRefresh vpnTableRefresher;
126 private final ClientRouteTargetContrainCache rtCache;
127 private ListenerRegistration<?> reg;
128 private DOMTransactionChain chain;
129 private final Map<TablesKey, LongAdder> prefixesReceived;
130 private final Map<TablesKey, LongAdder> prefixesInstalled;
131 private final BGPRibRoutingPolicy ribPolicies;
132 private final BGPRouteEntryImportParameters peerImportParameters;
133 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
135 private FluentFuture<? extends CommitInfo> submitted;
136 private boolean rtMembershipsUpdated;
138 EffectiveRibInWriter(
139 final BGPRouteEntryImportParameters peer,
141 final DOMTransactionChain chain,
142 final YangInstanceIdentifier peerIId,
143 final Set<TablesKey> tables,
144 final BGPTableTypeRegistryConsumer tableTypeRegistry,
145 final List<RouteTarget> rtMemberships,
146 final ClientRouteTargetContrainCache rtCache) {
147 registry = requireNonNull(rib.getRibSupportContext());
148 this.chain = requireNonNull(chain);
149 this.peerIId = requireNonNull(peerIId);
150 effRibTables = this.peerIId.node(EFFRIBIN_NID);
151 prefixesInstalled = buildPrefixesTables(tables);
152 prefixesReceived = buildPrefixesTables(tables);
153 ribPolicies = requireNonNull(rib.getRibPolicies());
154 service = requireNonNull(rib.getService());
155 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
156 peerImportParameters = peer;
157 this.rtMemberships = rtMemberships;
158 this.rtCache = rtCache;
159 vpnTableRefresher = rib;
163 final DOMDataTreeIdentifier treeId = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
164 peerIId.node(ADJRIBIN_NID).node(TABLES_NID));
165 LOG.debug("Registered Effective RIB on {}", peerIId);
166 reg = requireNonNull(service).registerDataTreeChangeListener(treeId, this);
169 private static Map<TablesKey, LongAdder> buildPrefixesTables(final Set<TablesKey> tables) {
170 final ImmutableMap.Builder<TablesKey, LongAdder> b = ImmutableMap.builder();
171 tables.forEach(table -> b.put(table, new LongAdder()));
176 public synchronized void onInitialData() {
177 // FIXME: update as if root was deleted
181 public synchronized void onDataTreeChanged(final List<DataTreeCandidate> changes) {
183 LOG.trace("Chain closed. Ignoring Changes : {}", changes);
187 LOG.trace("Data changed called to effective RIB. Change : {}", changes);
188 DOMDataTreeWriteTransaction tx = null;
189 for (final DataTreeCandidate tc : changes) {
190 final YangInstanceIdentifier rootPath = tc.getRootPath();
191 final DataTreeCandidateNode root = tc.getRootNode();
192 for (final DataTreeCandidateNode table : root.childNodes()) {
194 tx = chain.newWriteOnlyTransaction();
196 changeDataTree(tx, rootPath, root, table);
201 final FluentFuture<? extends CommitInfo> future = tx.commit();
203 future.addCallback(new FutureCallback<CommitInfo>() {
205 public void onSuccess(final CommitInfo result) {
206 LOG.trace("Successful commit");
210 public void onFailure(final Throwable trw) {
211 LOG.error("Failed commit", trw);
213 }, MoreExecutors.directExecutor());
216 //Refresh VPN Table if RT Memberships were updated
217 if (rtMembershipsUpdated) {
218 vpnTableRefresher.refreshTable(IVP4_VPN_TABLE_KEY, peerImportParameters.getFromPeerId());
219 vpnTableRefresher.refreshTable(IVP6_VPN_TABLE_KEY, peerImportParameters.getFromPeerId());
220 rtMembershipsUpdated = false;
225 public synchronized void close() {
230 if (submitted != null) {
233 } catch (final InterruptedException | ExecutionException throwable) {
234 LOG.error("Write routes failed", throwable);
241 prefixesReceived.values().forEach(LongAdder::reset);
242 prefixesInstalled.values().forEach(LongAdder::reset);
246 public long getPrefixedReceivedCount(final TablesKey tablesKey) {
247 final LongAdder counter = prefixesReceived.get(tablesKey);
248 if (counter == null) {
251 return counter.longValue();
255 public Set<TablesKey> getTableKeys() {
256 return ImmutableSet.copyOf(prefixesReceived.keySet());
260 public boolean isSupported(final TablesKey tablesKey) {
261 return prefixesReceived.containsKey(tablesKey);
265 public long getPrefixedInstalledCount(final TablesKey tablesKey) {
266 final LongAdder counter = prefixesInstalled.get(tablesKey);
267 if (counter == null) {
270 return counter.longValue();
274 public long getTotalPrefixesInstalled() {
275 return prefixesInstalled.values().stream().mapToLong(LongAdder::longValue).sum();
279 private void changeDataTree(final DOMDataTreeWriteTransaction tx, final YangInstanceIdentifier rootPath,
280 final DataTreeCandidateNode root, final DataTreeCandidateNode table) {
281 final PathArgument lastArg = table.name();
282 verify(lastArg instanceof NodeIdentifierWithPredicates, "Unexpected type %s in path %s", lastArg.getClass(),
284 final NodeIdentifierWithPredicates tableKey = (NodeIdentifierWithPredicates) lastArg;
285 final RIBSupportContext ribContext = registry.getRIBSupportContext(tableKey);
286 if (ribContext == null) {
287 LOG.warn("Table {} is not supported, ignoring event", tableKey);
291 final YangInstanceIdentifier effectiveTablePath = effectiveTablePath(tableKey);
292 final ModificationType modificationType = root.modificationType();
293 LOG.debug("Effective table {} modification type {}", effectiveTablePath, modificationType);
294 switch (modificationType) {
297 deleteTable(tx, ribContext, effectiveTablePath, table);
301 writeTable(tx, ribContext, effectiveTablePath, table);
303 case SUBTREE_MODIFIED:
304 modifyTable(tx, ribContext, effectiveTablePath, table);
307 LOG.info("Ignoring spurious notification on {} data {}", rootPath, table);
310 LOG.warn("Ignoring unhandled root {}", table);
315 private void deleteTable(final DOMDataTreeWriteTransaction tx, final RIBSupportContext ribContext,
316 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
317 LOG.debug("Delete Effective Table {}", effectiveTablePath);
318 onDeleteTable(ribContext.getRibSupport(), effectiveTablePath, table.dataBefore());
319 tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath);
322 private void modifyTable(final DOMDataTreeWriteTransaction tx, final RIBSupportContext ribContext,
323 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
324 LOG.debug("Modify Effective Table {}", effectiveTablePath);
326 final boolean wasLongLivedStale = isLongLivedStaleTable(table.findDataBefore());
327 final boolean longLivedStale = isLongLivedStaleTable(table.findDataAfter());
328 if (wasLongLivedStale != longLivedStale) {
329 LOG.debug("LLGR_STALE flag flipped {}, overwriting table {}", longLivedStale ? "ON" : "OFF",
331 writeTable(tx, ribContext, effectiveTablePath, table);
335 final var modifiedAttrs = table.modifiedChild(ATTRIBUTES_NID);
336 if (modifiedAttrs != null) {
337 final YangInstanceIdentifier effAttrsPath = effectiveTablePath.node(ATTRIBUTES_NID);
338 final var attrsAfter = modifiedAttrs.dataAfter();
339 if (attrsAfter != null) {
340 tx.put(LogicalDatastoreType.OPERATIONAL, effAttrsPath,
341 effectiveAttributes(extractContainer(attrsAfter)));
343 tx.delete(LogicalDatastoreType.OPERATIONAL, effAttrsPath);
347 final var modifiedRoutes = table.modifiedChild(ROUTES_NID);
348 if (modifiedRoutes != null) {
349 final RIBSupport<?, ?> ribSupport = ribContext.getRibSupport();
350 switch (modifiedRoutes.modificationType()) {
353 deleteRoutesBefore(tx, ribSupport, effectiveTablePath, modifiedRoutes);
354 // XXX: YANG Tools seems to have an issue stacking DELETE with child WRITE
355 tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ROUTES_NID), EMPTY_ROUTES);
356 writeRoutesAfter(tx, ribSupport, effectiveTablePath, modifiedRoutes.findDataAfter(),
361 deleteRoutesBefore(tx, ribSupport, effectiveTablePath, modifiedRoutes);
362 tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ROUTES_NID));
364 case SUBTREE_MODIFIED:
365 for (DataTreeCandidateNode modifiedRoute : ribSupport.changedRoutes(modifiedRoutes)) {
366 processRoute(tx, ribSupport, effectiveTablePath, modifiedRoute, longLivedStale);
373 LOG.warn("Ignoring modified routes {}", modifiedRoutes);
379 private void writeTable(final DOMDataTreeWriteTransaction tx, final RIBSupportContext ribContext,
380 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
381 LOG.debug("Write Effective Table {}", effectiveTablePath);
382 onDeleteTable(ribContext.getRibSupport(), effectiveTablePath, table.dataBefore());
384 final var node = table.dataAfter();
386 verify(node instanceof MapEntryNode, "Expected MapEntryNode, got %s", node);
387 final MapEntryNode tableAfter = (MapEntryNode) node;
388 ribContext.createEmptyTableStructure(tx, effectiveTablePath);
390 final DataContainerChild maybeAttrsAfter = tableAfter.childByArg(ATTRIBUTES_NID);
391 final boolean longLivedStale;
392 if (maybeAttrsAfter != null) {
393 final ContainerNode attrsAfter = extractContainer(maybeAttrsAfter);
394 longLivedStale = isLongLivedStale(attrsAfter);
395 tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ATTRIBUTES_NID),
396 effectiveAttributes(attrsAfter));
398 longLivedStale = false;
401 writeRoutesAfter(tx, ribContext.getRibSupport(), effectiveTablePath,
402 NormalizedNodes.findNode(tableAfter, ROUTES_NID), longLivedStale);
406 // Performs house-keeping when the contents of a table is deleted
407 private void onDeleteTable(final RIBSupport<?, ?> ribSupport, final YangInstanceIdentifier effectiveTablePath,
408 final @Nullable NormalizedNode tableBefore) {
409 // Routes are special in that we need to process the to keep our counters accurate
410 final var maybeRoutesBefore = findRoutesMap(ribSupport, NormalizedNodes.findNode(tableBefore, ROUTES_NID));
411 if (maybeRoutesBefore.isPresent()) {
412 onRoutesDeleted(ribSupport, effectiveTablePath, extractMap(maybeRoutesBefore).body());
416 private void deleteRoutesBefore(final DOMDataTreeWriteTransaction tx, final RIBSupport<?, ?> ribSupport,
417 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode modifiedRoutes) {
418 final Optional<NormalizedNode> maybeRoutesBefore =
419 NormalizedNodes.findNode(modifiedRoutes.dataBefore(), ribSupport.relativeRoutesPath());
420 if (maybeRoutesBefore.isPresent()) {
421 onRoutesDeleted(ribSupport, effectiveTablePath, extractMap(maybeRoutesBefore).body());
425 private void writeRoutesAfter(final DOMDataTreeWriteTransaction tx, final RIBSupport<?, ?> ribSupport,
426 final YangInstanceIdentifier effectiveTablePath, final Optional<NormalizedNode> routesAfter,
427 final boolean longLivedStale) {
428 final Optional<NormalizedNode> maybeRoutesAfter = NormalizedNodes.findNode(routesAfter,
429 ribSupport.relativeRoutesPath());
430 if (maybeRoutesAfter.isPresent()) {
431 final YangInstanceIdentifier routesPath = routeMapPath(ribSupport, effectiveTablePath);
432 for (MapEntryNode routeAfter : extractMap(maybeRoutesAfter).body()) {
433 writeRoute(tx, ribSupport, routesPath.node(routeAfter.name()), null, routeAfter, longLivedStale);
438 private void onRoutesDeleted(final RIBSupport<?, ?> ribSupport, final YangInstanceIdentifier effectiveTablePath,
439 final Collection<MapEntryNode> deletedRoutes) {
440 if (RouteTargetConstrainSubsequentAddressFamily.VALUE.equals(ribSupport.getTablesKey().getSafi())) {
441 final YangInstanceIdentifier routesPath = routeMapPath(ribSupport, effectiveTablePath);
442 for (final MapEntryNode routeBefore : deletedRoutes) {
443 deleteRouteTarget(ribSupport, routesPath.node(routeBefore.name()), routeBefore);
445 rtMembershipsUpdated = true;
448 final TablesKey tablesKey = ribSupport.getTablesKey();
449 CountersUtil.add(prefixesInstalled.get(tablesKey), tablesKey, -deletedRoutes.size());
452 private void processRoute(final DOMDataTreeWriteTransaction tx, final RIBSupport<?, ?> ribSupport,
453 final YangInstanceIdentifier routesPath, final DataTreeCandidateNode route, final boolean longLivedStale) {
454 LOG.debug("Process route {}", route.name());
455 final YangInstanceIdentifier routePath = ribSupport.routePath(routesPath, route.name());
456 switch (route.modificationType()) {
459 deleteRoute(tx, ribSupport, routePath, route.dataBefore());
465 case SUBTREE_MODIFIED:
467 writeRoute(tx, ribSupport, routePath, route.dataBefore(), route.getDataAfter(), longLivedStale);
470 LOG.warn("Ignoring unhandled route {}", route);
475 private void deleteRoute(final DOMDataTreeWriteTransaction tx, final RIBSupport<?, ?> ribSupport,
476 final YangInstanceIdentifier routeIdPath, final NormalizedNode route) {
477 handleRouteTarget(ModificationType.DELETE, ribSupport, routeIdPath, route);
478 tx.delete(LogicalDatastoreType.OPERATIONAL, routeIdPath);
479 LOG.debug("Route deleted. routeId={}", routeIdPath);
480 final TablesKey tablesKey = ribSupport.getTablesKey();
481 CountersUtil.decrement(prefixesInstalled.get(tablesKey), tablesKey);
484 private void writeRoute(final DOMDataTreeWriteTransaction tx, final RIBSupport<?, ?> ribSupport,
485 final YangInstanceIdentifier routePath, final @Nullable NormalizedNode routeBefore,
486 final @NonNull NormalizedNode routeAfter, final boolean longLivedStale) {
487 final TablesKey tablesKey = ribSupport.getTablesKey();
488 CountersUtil.increment(prefixesReceived.get(tablesKey), tablesKey);
489 // Lookup per-table attributes from RIBSupport
490 final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(routeAfter,
491 ribSupport.routeAttributesIdentifier()).orElse(null);
492 final Attributes routeAttrs = ribSupport.attributeFromContainerNode(advertisedAttrs);
493 final Optional<Attributes> optEffAtt;
494 // In case we want to add LLGR_STALE we do not process route through policies since it may be
495 // considered as received with LLGR_STALE from peer which is not true.
496 if (longLivedStale) {
497 // LLGR procedures are in effect. If the route is tagged with NO_LLGR, it needs to be removed.
498 final List<Communities> effCommunities = routeAttrs.getCommunities();
499 if (effCommunities != null && effCommunities.contains(CommunityUtil.NO_LLGR)) {
500 deleteRoute(tx, ribSupport, routePath, routeBefore);
503 optEffAtt = Optional.of(wrapLongLivedStale(routeAttrs));
505 optEffAtt = ribPolicies.applyImportPolicies(peerImportParameters, routeAttrs,
506 verifyNotNull(tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey())));
508 if (optEffAtt.isEmpty()) {
509 deleteRoute(tx, ribSupport, routePath, routeBefore);
512 handleRouteTarget(ModificationType.WRITE, ribSupport, routePath, routeAfter);
513 tx.put(LogicalDatastoreType.OPERATIONAL, routePath, routeAfter);
514 CountersUtil.increment(prefixesInstalled.get(tablesKey), tablesKey);
516 final Attributes attToStore = optEffAtt.orElseThrow();
517 if (!attToStore.equals(routeAttrs)) {
518 final YangInstanceIdentifier attPath = routePath.node(ribSupport.routeAttributesIdentifier());
519 final ContainerNode finalAttribute = ribSupport.attributeToContainerNode(attPath, attToStore);
520 tx.put(LogicalDatastoreType.OPERATIONAL, attPath, finalAttribute);
524 private void addRouteTarget(final RouteTargetConstrainRoute rtc) {
525 final RouteTarget rtMembership = RouteTargetMembeshipUtil.getRT(rtc);
526 if (PeerRole.Ebgp != peerImportParameters.getFromPeerRole()) {
527 rtCache.cacheRoute(rtc);
529 rtMemberships.add(rtMembership);
532 private void deleteRouteTarget(final RIBSupport<?, ?> ribSupport, final YangInstanceIdentifier routeIdPath,
533 final NormalizedNode route) {
534 deleteRouteTarget((RouteTargetConstrainRoute) ribSupport.fromNormalizedNode(routeIdPath, route));
537 private void deleteRouteTarget(final RouteTargetConstrainRoute rtc) {
538 final RouteTarget rtMembership = RouteTargetMembeshipUtil.getRT(rtc);
539 if (PeerRole.Ebgp != peerImportParameters.getFromPeerRole()) {
540 rtCache.uncacheRoute(rtc);
542 rtMemberships.remove(rtMembership);
545 private void handleRouteTarget(final ModificationType modificationType, final RIBSupport<?, ?> ribSupport,
546 final YangInstanceIdentifier routeIdPath, final NormalizedNode route) {
547 if (RouteTargetConstrainSubsequentAddressFamily.VALUE.equals(ribSupport.getTablesKey().getSafi())) {
548 final var rtc = (RouteTargetConstrainRoute) ribSupport.fromNormalizedNode(routeIdPath, route);
549 if (ModificationType.DELETE == modificationType) {
550 deleteRouteTarget(rtc);
554 rtMembershipsUpdated = true;
558 @SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD")
559 private static Attributes wrapLongLivedStale(final Attributes attrs) {
561 return STALE_LLGR_ATTRIBUTES;
564 final List<Communities> oldCommunities = attrs.getCommunities();
565 final List<Communities> newCommunities;
566 if (oldCommunities != null) {
567 if (oldCommunities.contains(StaleCommunities.STALE_LLGR)) {
570 newCommunities = StaleCommunities.create(oldCommunities);
572 newCommunities = STALE_LLGR_COMMUNUTIES;
575 return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120
576 .path.attributes.AttributesBuilder(attrs).setCommunities(newCommunities).build();
579 // XXX: this should be moved to YangInstanceIdentifier at some point
580 private static YangInstanceIdentifier concat(final YangInstanceIdentifier parent, final List<PathArgument> args) {
581 YangInstanceIdentifier ret = parent;
582 for (PathArgument arg : args) {
588 private YangInstanceIdentifier effectiveTablePath(final NodeIdentifierWithPredicates tableKey) {
589 return effRibTables.node(TABLES_NID).node(tableKey);
592 private static YangInstanceIdentifier routeMapPath(final RIBSupport<?, ?> ribSupport,
593 final YangInstanceIdentifier tablePath) {
594 return concat(tablePath.node(ROUTES_NID), ribSupport.relativeRoutesPath());
597 private static Optional<NormalizedNode> findRoutesMap(final RIBSupport<?, ?> ribSupport,
598 final Optional<NormalizedNode> optRoutes) {
599 return NormalizedNodes.findNode(optRoutes, ribSupport.relativeRoutesPath());
602 private static ContainerNode extractContainer(final NormalizedNode node) {
603 verify(node instanceof ContainerNode, "Expected ContainerNode, got %s", node);
604 return (ContainerNode) node;
607 private static MapNode extractMap(final Optional<? extends NormalizedNode> optNode) {
608 final NormalizedNode node = optNode.orElseThrow();
609 verify(node instanceof MapNode, "Expected MapNode, got %s", node);
610 return (MapNode) node;
613 private static boolean isLongLivedStale(final ContainerNode attributes) {
614 return NormalizedNodes.findNode(attributes, LLGR_STALE_NID).isPresent();
617 private static boolean isLongLivedStaleTable(final Optional<NormalizedNode> optTable) {
618 final Optional<NormalizedNode> optAttributes = NormalizedNodes.findNode(optTable, ATTRIBUTES_NID);
619 return optAttributes.isPresent() && isLongLivedStale(extractContainer(optAttributes.orElseThrow()));
622 private static ContainerNode effectiveAttributes(final ContainerNode attrs) {
623 final var upToDate = attrs.childByArg(UPTODATE_NID);
624 if (upToDate != null) {
625 final Object value = upToDate.body();
626 verify(value instanceof Boolean, "Expected boolean uptodate, got %s", value);
627 if ((Boolean) value) {
628 return RIBNormalizedNodes.UPTODATE_ATTRIBUTES;
631 return RIBNormalizedNodes.NOT_UPTODATE_ATTRIBUTES;