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 java.util.Objects.requireNonNull;
12 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBIN;
13 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ATTRIBUTES;
14 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.EFFRIBIN;
15 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ROUTES;
16 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES;
18 import com.google.common.collect.ImmutableList;
19 import com.google.common.collect.ImmutableMap;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.common.util.concurrent.FluentFuture;
22 import com.google.common.util.concurrent.FutureCallback;
23 import com.google.common.util.concurrent.MoreExecutors;
24 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
25 import java.util.Collection;
26 import java.util.List;
28 import java.util.Optional;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.atomic.LongAdder;
32 import javax.annotation.Nonnull;
33 import javax.annotation.concurrent.GuardedBy;
34 import javax.annotation.concurrent.NotThreadSafe;
35 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
36 import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
39 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
40 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
41 import org.opendaylight.mdsal.common.api.CommitInfo;
42 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
43 import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
48 import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesInstalledCounters;
49 import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesReceivedCounters;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
51 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
52 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
53 import org.opendaylight.protocol.bgp.route.targetcontrain.spi.ClientRouteTargetContrainCache;
54 import org.opendaylight.protocol.bgp.route.targetcontrain.spi.RouteTargetMembeshipUtil;
55 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.AfiSafiType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.Communities;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.route.target.constrain.rev180618.RouteTargetConstrainSubsequentAddressFamily;
61 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;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv4AddressFamily;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv6AddressFamily;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.MplsLabeledVpnSubsequentAddressFamily;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.RouteTarget;
66 import org.opendaylight.yangtools.concepts.ListenerRegistration;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
70 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
73 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
77 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
78 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
80 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
85 * Implementation of the BGP import policy. Listens on peer's Adj-RIB-In, inspects all inbound
86 * routes in the context of the advertising peer's role and applies the inbound policy.
89 * Inbound policy is applied as follows:
92 * 1) if the peer is an eBGP peer, perform attribute replacement and filtering
93 * 2) check if a route is admissible based on attributes attached to it, as well as the
94 * advertising peer's role
95 * 3) output admitting routes with edited attributes into /bgp-rib/rib/peer/effective-rib-in/tables/routes
98 final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesInstalledCounters,
99 AutoCloseable, ClusteredDOMDataTreeChangeListener {
101 private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
102 private static final TablesKey IVP4_VPN_TABLE_KEY = new TablesKey(Ipv4AddressFamily.class,
103 MplsLabeledVpnSubsequentAddressFamily.class);
104 private static final TablesKey IVP6_VPN_TABLE_KEY = new TablesKey(Ipv6AddressFamily.class,
105 MplsLabeledVpnSubsequentAddressFamily.class);
106 private static final ImmutableList<Communities> STALE_LLGR_COMMUNUTIES = ImmutableList.of(
107 StaleCommunities.STALE_LLGR);
108 private static final Attributes STALE_LLGR_ATTRIBUTES = new org.opendaylight.yang.gen.v1.urn.opendaylight.params
109 .xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder()
110 .setCommunities(STALE_LLGR_COMMUNUTIES)
112 private static final ChoiceNode EMPTY_ROUTES = Builders.choiceBuilder().withNodeIdentifier(ROUTES).build();
114 private final RIBSupportContextRegistry registry;
115 private final YangInstanceIdentifier peerIId;
116 private final YangInstanceIdentifier effRibTables;
117 private final DOMDataTreeChangeService service;
118 private final List<RouteTarget> rtMemberships;
119 private final RibOutRefresh vpnTableRefresher;
120 private final ClientRouteTargetContrainCache rtCache;
121 private ListenerRegistration<?> reg;
122 private DOMTransactionChain chain;
123 private final Map<TablesKey, LongAdder> prefixesReceived;
124 private final Map<TablesKey, LongAdder> prefixesInstalled;
125 private final BGPRibRoutingPolicy ribPolicies;
126 private final BGPRouteEntryImportParameters peerImportParameters;
127 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
129 private FluentFuture<? extends CommitInfo> submitted;
130 private boolean rtMembershipsUpdated;
132 EffectiveRibInWriter(
133 final BGPRouteEntryImportParameters peer,
135 final DOMTransactionChain chain,
136 final YangInstanceIdentifier peerIId,
137 final Set<TablesKey> tables,
138 final BGPTableTypeRegistryConsumer tableTypeRegistry,
139 final List<RouteTarget> rtMemberships,
140 final ClientRouteTargetContrainCache rtCache) {
141 this.registry = requireNonNull(rib.getRibSupportContext());
142 this.chain = requireNonNull(chain);
143 this.peerIId = requireNonNull(peerIId);
144 this.effRibTables = this.peerIId.node(EFFRIBIN);
145 this.prefixesInstalled = buildPrefixesTables(tables);
146 this.prefixesReceived = buildPrefixesTables(tables);
147 this.ribPolicies = requireNonNull(rib.getRibPolicies());
148 this.service = requireNonNull(rib.getService());
149 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
150 this.peerImportParameters = peer;
151 this.rtMemberships = rtMemberships;
152 this.rtCache = rtCache;
153 this.vpnTableRefresher = rib;
157 final DOMDataTreeIdentifier treeId = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
158 this.peerIId.node(ADJRIBIN).node(TABLES));
159 LOG.debug("Registered Effective RIB on {}", this.peerIId);
160 this.reg = requireNonNull(this.service).registerDataTreeChangeListener(treeId, this);
163 private static Map<TablesKey, LongAdder> buildPrefixesTables(final Set<TablesKey> tables) {
164 final ImmutableMap.Builder<TablesKey, LongAdder> b = ImmutableMap.builder();
165 tables.forEach(table -> b.put(table, new LongAdder()));
170 public synchronized void onDataTreeChanged(@Nonnull final Collection<DataTreeCandidate> changes) {
171 if (this.chain == null) {
172 LOG.trace("Chain closed. Ignoring Changes : {}", changes);
176 LOG.trace("Data changed called to effective RIB. Change : {}", changes);
177 DOMDataWriteTransaction tx = null;
178 for (final DataTreeCandidate tc : changes) {
179 final YangInstanceIdentifier rootPath = tc.getRootPath();
180 final DataTreeCandidateNode root = tc.getRootNode();
181 for (final DataTreeCandidateNode table : root.getChildNodes()) {
183 tx = this.chain.newWriteOnlyTransaction();
185 changeDataTree(tx, rootPath, root, table);
190 final FluentFuture<? extends CommitInfo> future = tx.commit();
191 this.submitted = future;
192 future.addCallback(new FutureCallback<CommitInfo>() {
194 public void onSuccess(final CommitInfo result) {
195 LOG.trace("Successful commit");
199 public void onFailure(final Throwable trw) {
200 LOG.error("Failed commit", trw);
202 }, MoreExecutors.directExecutor());
205 //Refresh VPN Table if RT Memberships were updated
206 if (this.rtMembershipsUpdated) {
207 this.vpnTableRefresher.refreshTable(IVP4_VPN_TABLE_KEY, this.peerImportParameters.getFromPeerId());
208 this.vpnTableRefresher.refreshTable(IVP6_VPN_TABLE_KEY, this.peerImportParameters.getFromPeerId());
209 this.rtMembershipsUpdated = false;
214 public synchronized void close() {
215 if (this.reg != null) {
219 if (this.submitted != null) {
221 this.submitted.get();
222 } catch (final InterruptedException | ExecutionException throwable) {
223 LOG.error("Write routes failed", throwable);
226 if (this.chain != null) {
230 this.prefixesReceived.values().forEach(LongAdder::reset);
231 this.prefixesInstalled.values().forEach(LongAdder::reset);
235 public long getPrefixedReceivedCount(final TablesKey tablesKey) {
236 final LongAdder counter = this.prefixesReceived.get(tablesKey);
237 if (counter == null) {
240 return counter.longValue();
244 public Set<TablesKey> getTableKeys() {
245 return ImmutableSet.copyOf(this.prefixesReceived.keySet());
249 public boolean isSupported(final TablesKey tablesKey) {
250 return this.prefixesReceived.containsKey(tablesKey);
254 public long getPrefixedInstalledCount(final TablesKey tablesKey) {
255 final LongAdder counter = this.prefixesInstalled.get(tablesKey);
256 if (counter == null) {
259 return counter.longValue();
263 public long getTotalPrefixesInstalled() {
264 return this.prefixesInstalled.values().stream().mapToLong(LongAdder::longValue).sum();
268 private void changeDataTree(final DOMDataWriteTransaction tx, final YangInstanceIdentifier rootPath,
269 final DataTreeCandidateNode root, final DataTreeCandidateNode table) {
270 final PathArgument lastArg = table.getIdentifier();
271 verify(lastArg instanceof NodeIdentifierWithPredicates, "Unexpected type %s in path %s", lastArg.getClass(),
273 final NodeIdentifierWithPredicates tableKey = (NodeIdentifierWithPredicates) lastArg;
274 final RIBSupportContext ribContext = this.registry.getRIBSupportContext(tableKey);
275 if (ribContext == null) {
276 LOG.warn("Table {} is not supported, ignoring event", tableKey);
280 final YangInstanceIdentifier effectiveTablePath = effectiveTablePath(tableKey);
281 final ModificationType modificationType = root.getModificationType();
282 LOG.debug("Effective table {} modification type {}", effectiveTablePath, modificationType);
283 switch (modificationType) {
286 deleteTable(tx, ribContext, effectiveTablePath, table);
290 writeTable(tx, ribContext, effectiveTablePath, table);
292 case SUBTREE_MODIFIED:
293 modifyTable(tx, ribContext, effectiveTablePath, table);
296 LOG.info("Ignoring spurious notification on {} data {}", rootPath, table);
299 LOG.warn("Ignoring unhandled root {}", table);
304 private void deleteTable(final DOMDataWriteTransaction tx, final RIBSupportContext ribContext,
305 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
306 LOG.debug("Delete Effective Table {}", effectiveTablePath);
307 onDeleteTable(ribContext.getRibSupport(), effectiveTablePath, table.getDataBefore());
308 tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath);
311 private void modifyTable(final DOMDataWriteTransaction tx, final RIBSupportContext ribContext,
312 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
313 LOG.debug("Modify Effective Table {}", effectiveTablePath);
315 final DataTreeCandidateNode modifiedAttrs = table.getModifiedChild(ATTRIBUTES);
316 if (modifiedAttrs != null) {
317 final Optional<NormalizedNode<?, ?>> attrsAfter = modifiedAttrs.getDataAfter();
318 final YangInstanceIdentifier effAttrsPath = effectiveTablePath.node(ATTRIBUTES);
319 if (attrsAfter.isPresent()) {
320 tx.put(LogicalDatastoreType.OPERATIONAL, effAttrsPath, attrsAfter.get());
322 tx.delete(LogicalDatastoreType.OPERATIONAL, effAttrsPath);
326 final DataTreeCandidateNode modifiedRoutes = table.getModifiedChild(ROUTES);
327 if (modifiedRoutes != null) {
328 final RIBSupport<?, ?, ?, ?> ribSupport = ribContext.getRibSupport();
329 switch (modifiedRoutes.getModificationType()) {
332 deleteRoutesBefore(tx, ribSupport, effectiveTablePath, modifiedRoutes);
333 // XXX: YANG Tools seems to have an issue stacking DELETE with child WRITE
334 tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ROUTES), EMPTY_ROUTES);
335 writeRoutesAfter(tx, ribSupport, effectiveTablePath, modifiedRoutes.getDataAfter());
339 deleteRoutesBefore(tx, ribSupport, effectiveTablePath, modifiedRoutes);
340 tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ROUTES));
342 case SUBTREE_MODIFIED:
343 for (DataTreeCandidateNode modifiedRoute : ribSupport.changedRoutes(modifiedRoutes)) {
344 processRoute(tx, ribSupport, effectiveTablePath, modifiedRoute);
351 LOG.warn("Ignoring modified routes {}", modifiedRoutes);
357 private void writeTable(final DOMDataWriteTransaction tx, final RIBSupportContext ribContext,
358 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
359 LOG.debug("Write Effective Table {}", effectiveTablePath);
360 onDeleteTable(ribContext.getRibSupport(), effectiveTablePath, table.getDataBefore());
362 final Optional<NormalizedNode<?, ?>> maybeTableAfter = table.getDataAfter();
363 if (maybeTableAfter.isPresent()) {
364 final MapEntryNode tableAfter = extractMapEntry(maybeTableAfter);
365 ribContext.createEmptyTableStructure(tx, effectiveTablePath);
367 final Optional<DataContainerChild<?, ?>> maybeAttrsAfter = tableAfter.getChild(ATTRIBUTES);
368 if (maybeAttrsAfter.isPresent()) {
369 final ContainerNode attrsAfter = extractContainer(maybeAttrsAfter);
370 tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ATTRIBUTES), attrsAfter);
373 writeRoutesAfter(tx, ribContext.getRibSupport(), effectiveTablePath,
374 NormalizedNodes.findNode(tableAfter, ROUTES));
378 // Performs house-keeping when the contents of a table is deleted
379 private void onDeleteTable(final RIBSupport<?, ?, ?, ?> ribSupport, final YangInstanceIdentifier effectiveTablePath,
380 final Optional<NormalizedNode<?, ?>> tableBefore) {
381 // Routes are special in that we need to process the to keep our counters accurate
382 final Optional<NormalizedNode<?, ?>> maybeRoutesBefore = findRoutesMap(ribSupport,
383 NormalizedNodes.findNode(tableBefore, ROUTES));
384 if (maybeRoutesBefore.isPresent()) {
385 onRoutesDeleted(ribSupport, effectiveTablePath, extractMap(maybeRoutesBefore).getValue());
389 private void deleteRoutesBefore(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
390 final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode modifiedRoutes) {
391 final Optional<NormalizedNode<?, ?>> maybeRoutesBefore = NormalizedNodes.findNode(
392 modifiedRoutes.getDataBefore(), ribSupport.relativeRoutesPath());
393 if (maybeRoutesBefore.isPresent()) {
394 onRoutesDeleted(ribSupport, effectiveTablePath, extractMap(maybeRoutesBefore).getValue());
398 private void writeRoutesAfter(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
399 final YangInstanceIdentifier effectiveTablePath, final Optional<NormalizedNode<?, ?>> routesAfter) {
400 final Optional<NormalizedNode<?, ?>> maybeRoutesAfter = NormalizedNodes.findNode(routesAfter,
401 ribSupport.relativeRoutesPath());
402 if (maybeRoutesAfter.isPresent()) {
403 final YangInstanceIdentifier routesPath = routeMapPath(ribSupport, effectiveTablePath);
404 for (MapEntryNode routeAfter : extractMap(maybeRoutesAfter).getValue()) {
405 writeRoute(tx, ribSupport, routesPath.node(routeAfter.getIdentifier()), Optional.empty(), routeAfter);
410 private void onRoutesDeleted(final RIBSupport<?, ?, ?, ?> ribSupport,
411 final YangInstanceIdentifier effectiveTablePath, final Collection<MapEntryNode> deletedRoutes) {
412 if (ribSupport.getSafi() == RouteTargetConstrainSubsequentAddressFamily.class) {
413 final YangInstanceIdentifier routesPath = routeMapPath(ribSupport, effectiveTablePath);
414 for (final MapEntryNode routeBefore : deletedRoutes) {
415 deleteRouteTarget(ribSupport, routesPath.node(routeBefore.getIdentifier()), routeBefore);
417 this.rtMembershipsUpdated = true;
420 final TablesKey tablesKey = ribSupport.getTablesKey();
421 CountersUtil.add(prefixesInstalled.get(tablesKey), tablesKey, -deletedRoutes.size());
424 private void processRoute(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
425 final YangInstanceIdentifier routesPath, final DataTreeCandidateNode route) {
426 LOG.debug("Process route {}", route.getIdentifier());
427 final YangInstanceIdentifier routePath = ribSupport.routePath(routesPath, route.getIdentifier());
428 switch (route.getModificationType()) {
431 deleteRoute(tx, ribSupport, routePath, route.getDataBefore().orElse(null));
437 case SUBTREE_MODIFIED:
439 writeRoute(tx, ribSupport, routePath, route.getDataBefore(), route.getDataAfter().get());
441 LOG.warn("Ignoring unhandled route {}", route);
446 private void deleteRoute(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
447 final YangInstanceIdentifier routeIdPath, final NormalizedNode<?, ?> route) {
448 handleRouteTarget(ModificationType.DELETE, ribSupport, routeIdPath, route);
449 tx.delete(LogicalDatastoreType.OPERATIONAL, routeIdPath);
450 LOG.debug("Route deleted. routeId={}", routeIdPath);
451 final TablesKey tablesKey = ribSupport.getTablesKey();
452 CountersUtil.decrement(this.prefixesInstalled.get(tablesKey), tablesKey);
455 private void writeRoute(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
456 final YangInstanceIdentifier routePath, final Optional<NormalizedNode<?, ?>> routeBefore,
457 final NormalizedNode<?, ?> routeAfter) {
458 final TablesKey tablesKey = ribSupport.getTablesKey();
459 CountersUtil.increment(this.prefixesReceived.get(tablesKey), tablesKey);
460 // Lookup per-table attributes from RIBSupport
461 final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(routeAfter,
462 ribSupport.routeAttributesIdentifier()).orElse(null);
463 final Attributes routeAttrs = ribSupport.attributeFromContainerNode(advertisedAttrs);
464 final Optional<Attributes> optEffAtt;
465 // In case we want to add LLGR_STALE we do not process route through policies since it may be
466 // considered as received with LLGR_STALE from peer which is not true.
467 final boolean longLivedStale = false;
468 if (longLivedStale) {
469 // LLGR procedures are in effect. If the route is tagged with NO_LLGR, it needs to be removed.
470 final List<Communities> effCommunities = routeAttrs.getCommunities();
471 if (effCommunities != null && effCommunities.contains(CommunityUtil.NO_LLGR)) {
472 deleteRoute(tx, ribSupport, routePath, routeBefore.orElse(null));
475 optEffAtt = Optional.of(wrapLongLivedStale(routeAttrs));
477 final Class<? extends AfiSafiType> afiSafiType
478 = tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey()).get();
479 optEffAtt = this.ribPolicies
480 .applyImportPolicies(this.peerImportParameters, routeAttrs, afiSafiType);
482 if (!optEffAtt.isPresent()) {
483 deleteRoute(tx, ribSupport, routePath, routeBefore.orElse(null));
486 handleRouteTarget(ModificationType.WRITE, ribSupport, routePath, routeAfter);
487 tx.put(LogicalDatastoreType.OPERATIONAL, routePath, routeAfter);
488 CountersUtil.increment(this.prefixesInstalled.get(tablesKey), tablesKey);
490 final YangInstanceIdentifier attPath = routePath.node(ribSupport.routeAttributesIdentifier());
491 final Attributes attToStore = optEffAtt.get();
492 if (!attToStore.equals(routeAttrs)) {
493 final ContainerNode finalAttribute = ribSupport.attributeToContainerNode(attPath, attToStore);
494 tx.put(LogicalDatastoreType.OPERATIONAL, attPath, finalAttribute);
498 private void addRouteTarget(final RouteTargetConstrainRoute rtc) {
499 final RouteTarget rtMembership = RouteTargetMembeshipUtil.getRT(rtc);
500 if (PeerRole.Ebgp != this.peerImportParameters.getFromPeerRole()) {
501 this.rtCache.cacheRoute(rtc);
503 this.rtMemberships.add(rtMembership);
506 private void deleteRouteTarget(final RIBSupport<?, ?, ?, ?> ribSupport, final YangInstanceIdentifier routeIdPath,
507 final NormalizedNode<?, ?> route) {
508 deleteRouteTarget((RouteTargetConstrainRoute) ribSupport.fromNormalizedNode(routeIdPath, route));
511 private void deleteRouteTarget(final RouteTargetConstrainRoute rtc) {
512 final RouteTarget rtMembership = RouteTargetMembeshipUtil.getRT(rtc);
513 if (PeerRole.Ebgp != this.peerImportParameters.getFromPeerRole()) {
514 this.rtCache.uncacheRoute(rtc);
516 this.rtMemberships.remove(rtMembership);
519 private void handleRouteTarget(final ModificationType modificationType, final RIBSupport<?, ?, ?, ?> ribSupport,
520 final YangInstanceIdentifier routeIdPath, final NormalizedNode<?, ?> route) {
521 if (ribSupport.getSafi() == RouteTargetConstrainSubsequentAddressFamily.class) {
522 final RouteTargetConstrainRoute rtc =
523 (RouteTargetConstrainRoute) ribSupport.fromNormalizedNode(routeIdPath, route);
524 if (ModificationType.DELETE == modificationType) {
525 deleteRouteTarget(rtc);
529 this.rtMembershipsUpdated = true;
533 @SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD")
534 private static Attributes wrapLongLivedStale(final Attributes attrs) {
536 return STALE_LLGR_ATTRIBUTES;
539 final List<Communities> oldCommunities = attrs.getCommunities();
540 final List<Communities> newCommunities;
541 if (oldCommunities != null) {
542 if (oldCommunities.contains(StaleCommunities.STALE_LLGR)) {
545 newCommunities = StaleCommunities.create(oldCommunities);
547 newCommunities = STALE_LLGR_COMMUNUTIES;
550 return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329
551 .path.attributes.AttributesBuilder(attrs).setCommunities(newCommunities).build();
554 // XXX: this should be moved to YangInstanceIdentifier at some point
555 private static YangInstanceIdentifier concat(final YangInstanceIdentifier parent, final List<PathArgument> args) {
556 YangInstanceIdentifier ret = parent;
557 for (PathArgument arg : args) {
563 private YangInstanceIdentifier effectiveTablePath(final NodeIdentifierWithPredicates tableKey) {
564 return this.effRibTables.node(TABLES).node(tableKey);
567 private static YangInstanceIdentifier routeMapPath(final RIBSupport<?, ?, ?, ?> ribSupport,
568 final YangInstanceIdentifier tablePath) {
569 return concat(tablePath.node(ROUTES), ribSupport.relativeRoutesPath());
572 private static Optional<NormalizedNode<?, ?>> findRoutesMap(final RIBSupport<?, ?, ?, ?> ribSupport,
573 final Optional<NormalizedNode<?, ?>> optRoutes) {
574 return NormalizedNodes.findNode(optRoutes, ribSupport.relativeRoutesPath());
577 private static ContainerNode extractContainer(final Optional<? extends NormalizedNode<?, ?>> optNode) {
578 final NormalizedNode<?, ?> node = optNode.get();
579 verify(node instanceof ContainerNode, "Expected ContainerNode, got %s", node);
580 return (ContainerNode) node;
583 private static MapNode extractMap(final Optional<? extends NormalizedNode<?, ?>> optNode) {
584 final NormalizedNode<?, ?> node = optNode.get();
585 verify(node instanceof MapNode, "Expected MapNode, got %s", node);
586 return (MapNode) node;
589 private static MapEntryNode extractMapEntry(final Optional<? extends NormalizedNode<?, ?>> optNode) {
590 final NormalizedNode<?, ?> node = optNode.get();
591 verify(node instanceof MapEntryNode, "Expected MapEntryNode, got %s", node);
592 return (MapEntryNode) node;