*/
package org.opendaylight.protocol.bgp.rib.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import java.util.Collection;
-import java.util.HashSet;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.LongAdder;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
-import org.opendaylight.protocol.bgp.rib.impl.spi.AbstractImportPolicy;
-import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
-import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
+import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
-import org.opendaylight.protocol.bgp.rib.impl.stats.peer.route.PerTableTypeRouteCounter;
-import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils;
+import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesInstalledCounters;
+import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesReceivedCounters;
import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.AdjRibIn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.EffectiveRibIn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
+import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
+import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.PeerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.AdjRibIn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.EffectiveRibIn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of the BGP import policy. Listens on peer's Adj-RIB-In, inspects all inbound
* routes in the context of the advertising peer's role and applies the inbound policy.
- *
+ * <p>
* Inbound policy is applied as follows:
- *
+ * <p>
* 1) if the peer is an eBGP peer, perform attribute replacement and filtering
* 2) check if a route is admissible based on attributes attached to it, as well as the
- * advertising peer's role
+ * advertising peer's role
* 3) output admitting routes with edited attributes into /bgp-rib/rib/peer/effective-rib-in/tables/routes
- *
*/
@NotThreadSafe
-final class EffectiveRibInWriter implements AutoCloseable {
+final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesInstalledCounters, AutoCloseable {
+ static final NodeIdentifier TABLE_ROUTES = new NodeIdentifier(Routes.QNAME);
private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
- protected static final NodeIdentifier TABLE_ROUTES = new NodeIdentifier(Routes.QNAME);
-
- private final class AdjInTracker implements AutoCloseable, ClusteredDOMDataTreeChangeListener {
- private final RIBSupportContextRegistry registry;
- private final YangInstanceIdentifier peerIId;
- private final YangInstanceIdentifier effRibTables;
- private final ListenerRegistration<?> reg;
- private final DOMTransactionChain chain;
- private final PerTableTypeRouteCounter effectiveRibInRouteCounters;
- private final PerTableTypeRouteCounter adjRibInRouteCounters;
- private final Map<TablesKey, Set<YangInstanceIdentifier>> effectiveRibInRouteMap = new ConcurrentHashMap<>();
- private final Map<TablesKey, Set<YangInstanceIdentifier>> adjRibInRouteMap = new ConcurrentHashMap<>();
+ private final AdjInTracker adjInTracker;
- AdjInTracker(final DOMDataTreeChangeService service, final RIBSupportContextRegistry registry, final DOMTransactionChain chain, final YangInstanceIdentifier peerIId,
- @Nonnull final PerTableTypeRouteCounter effectiveRibInRouteCounters, @Nonnull final PerTableTypeRouteCounter adjRibInRouteCounters) {
- this.registry = Preconditions.checkNotNull(registry);
- this.chain = Preconditions.checkNotNull(chain);
- this.peerIId = Preconditions.checkNotNull(peerIId);
- this.effRibTables = this.peerIId.node(EffectiveRibIn.QNAME).node(Tables.QNAME);
- this.effectiveRibInRouteCounters = Preconditions.checkNotNull(effectiveRibInRouteCounters);
- this.adjRibInRouteCounters = Preconditions.checkNotNull(adjRibInRouteCounters);
+ private EffectiveRibInWriter(final BGPRouteEntryImportParameters peer, final RIB rib,
+ final BindingTransactionChain chain,
+ final KeyedInstanceIdentifier<Peer, PeerKey> peerIId, final Set<TablesKey> tables) {
+ this.adjInTracker = new AdjInTracker(peer, rib, chain, peerIId, tables);
+ }
- final DOMDataTreeIdentifier treeId = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, this.peerIId.node(AdjRibIn.QNAME).node(Tables.QNAME));
- LOG.debug("Registered Effective RIB on {}", this.peerIId);
- this.reg = service.registerDataTreeChangeListener(treeId, this);
- }
+ static EffectiveRibInWriter create(final BGPRouteEntryImportParameters peer, @Nonnull final RIB rib,
+ @Nonnull final BindingTransactionChain chain,
+ @Nonnull final KeyedInstanceIdentifier<Peer, PeerKey> peerIId,
+ @Nonnull final Set<TablesKey> tables) {
+ return new EffectiveRibInWriter(peer, rib, chain, peerIId, tables);
+ }
- /**
- * @deprecated Should always pass in route counter
- * @param service
- * @param registry
- * @param chain
- * @param peerIId
- */
- @Deprecated
- AdjInTracker(final DOMDataTreeChangeService service, final RIBSupportContextRegistry registry, final DOMTransactionChain chain, final YangInstanceIdentifier peerIId) {
- this(service, registry, chain, peerIId, new PerTableTypeRouteCounter("effective-rib-in"), new PerTableTypeRouteCounter("adj-rib-in"));
- }
+ @Override
+ public synchronized void close() {
+ this.adjInTracker.close();
+ }
- private void updateRoute(@Nonnull final PerTableTypeRouteCounter counter, @Nonnull final Map<TablesKey, Set<YangInstanceIdentifier>> routeMap,
- @Nonnull final TablesKey tablesKey, @Nonnull final YangInstanceIdentifier routeId) {
- routeMap.putIfAbsent(tablesKey, new HashSet<>());
- routeMap.get(tablesKey).add(routeId);
+ @Override
+ public long getPrefixedReceivedCount(final TablesKey tablesKey) {
+ return this.adjInTracker.getPrefixedReceivedCount(tablesKey);
+ }
- updateRouteCounter(counter, routeMap,tablesKey);
- }
+ @Override
+ public Set<TablesKey> getTableKeys() {
+ return this.adjInTracker.getTableKeys();
+ }
- private void deleteRoute(@Nonnull final PerTableTypeRouteCounter counter, @Nonnull final Map<TablesKey, Set<YangInstanceIdentifier>> routeMap,
- @Nonnull final TablesKey tablesKey, @Nonnull final YangInstanceIdentifier routeId) {
- if (routeMap.containsKey(tablesKey)) {
- routeMap.get(tablesKey).remove(routeId);
- }
+ @Override
+ public boolean isSupported(final TablesKey tablesKey) {
+ return this.adjInTracker.isSupported(tablesKey);
+ }
- updateRouteCounter(counter, routeMap,tablesKey);
- }
+ @Override
+ public long getPrefixedInstalledCount(@Nonnull final TablesKey tablesKey) {
+ return this.adjInTracker.getPrefixedInstalledCount(tablesKey);
+ }
- private void deleteRoute(@Nonnull final PerTableTypeRouteCounter counter, @Nonnull final Map<TablesKey, Set<YangInstanceIdentifier>> routeMap,
- @Nonnull final TablesKey tablesKey) {
- routeMap.remove(tablesKey);
+ @Override
+ public long getTotalPrefixesInstalled() {
+ return this.adjInTracker.getTotalPrefixesInstalled();
+ }
- updateRouteCounter(counter, routeMap,tablesKey);
+ private static final class AdjInTracker implements PrefixesReceivedCounters, PrefixesInstalledCounters,
+ AutoCloseable, ClusteredDataTreeChangeListener<Tables> {
+ private final RIBSupportContextRegistry registry;
+ private final KeyedInstanceIdentifier<Peer, PeerKey> peerIId;
+ private final InstanceIdentifier<EffectiveRibIn> effRibTables;
+ private final ListenerRegistration<?> reg;
+ private final BindingTransactionChain chain;
+ private final Map<TablesKey, LongAdder> prefixesReceived;
+ private final Map<TablesKey, LongAdder> prefixesInstalled;
+ private final BGPRibRoutingPolicy ribPolicies;
+ private final BGPRouteEntryImportParameters peerImportParameters;
+
+ @SuppressWarnings("unchecked")
+ AdjInTracker(final BGPRouteEntryImportParameters peer, final RIB rib,
+ final BindingTransactionChain chain,
+ final KeyedInstanceIdentifier<Peer, PeerKey> peerIId,
+ @Nonnull final Set<TablesKey> tables) {
+ this.registry = requireNonNull(rib.getRibSupportContext());
+ this.chain = requireNonNull(chain);
+ this.peerIId = requireNonNull(peerIId);
+ this.effRibTables = this.peerIId.child(EffectiveRibIn.class);
+ this.prefixesInstalled = buildPrefixesTables(tables);
+ this.prefixesReceived = buildPrefixesTables(tables);
+ this.ribPolicies = requireNonNull(rib.getRibPolicies());
+ this.peerImportParameters = peer;
+ final DataTreeIdentifier treeId = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
+ this.peerIId.child(AdjRibIn.class).child(Tables.class));
+ LOG.debug("Registered Effective RIB on {}", this.peerIId);
+ this.reg = requireNonNull(rib.getDataBroker()).registerDataTreeChangeListener(treeId, this);
}
- private void updateRouteCounter(@Nonnull final PerTableTypeRouteCounter counter, @Nonnull final Map<TablesKey, Set<YangInstanceIdentifier>> routeMap,
- @Nonnull final TablesKey tablesKey) {
- counter.getCounterOrSetDefault(tablesKey)
- .setCount(routeMap.getOrDefault(tablesKey, new HashSet<>()).size());
+ private Map<TablesKey, LongAdder> buildPrefixesTables(final Set<TablesKey> tables) {
+ final ImmutableMap.Builder<TablesKey, LongAdder> b = ImmutableMap.builder();
+ tables.forEach(table -> b.put(table, new LongAdder()));
+ return b.build();
}
- private void processRoute(final DOMDataWriteTransaction tx, final RIBSupport ribSupport, final AbstractImportPolicy policy, final YangInstanceIdentifier routesPath, final DataTreeCandidateNode route) {
- LOG.debug("Process route {}", route.getIdentifier());
- final YangInstanceIdentifier routeId = ribSupport.routePath(routesPath, route.getIdentifier());
- final TablesKey tablesKey = new TablesKey(ribSupport.getAfi(), ribSupport.getSafi());
- switch (route.getModificationType()) {
- case DELETE:
- case DISAPPEARED:
- tx.delete(LogicalDatastoreType.OPERATIONAL, routeId);
- LOG.debug("Route deleted. routeId={}", routeId);
-
- deleteRoute(this.adjRibInRouteCounters, this.adjRibInRouteMap, tablesKey, routeId);
- deleteRoute(this.effectiveRibInRouteCounters, this.effectiveRibInRouteMap, tablesKey, routeId);
- break;
- case UNMODIFIED:
- // No-op
- break;
- case APPEARED:
- case SUBTREE_MODIFIED:
- case WRITE:
- tx.put(LogicalDatastoreType.OPERATIONAL, routeId, route.getDataAfter().get());
- // count adj-rib-in route first
- updateRoute(this.adjRibInRouteCounters, this.adjRibInRouteMap, tablesKey, routeId);
- updateRoute(this.effectiveRibInRouteCounters, this.effectiveRibInRouteMap, tablesKey, routeId);
- // Lookup per-table attributes from RIBSupport
- final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(route.getDataAfter(), ribSupport.routeAttributesIdentifier()).orNull();
- final ContainerNode effectiveAttrs;
-
- if (advertisedAttrs != null) {
- effectiveAttrs = policy.effectiveAttributes(advertisedAttrs);
- } else {
- effectiveAttrs = null;
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Tables>> changes) {
+ LOG.trace("Data changed called to effective RIB. Change : {}", changes);
+ WriteTransaction tx = null;
+ for (final DataTreeModification<Tables> tc : changes) {
+ final DataObjectModification<Tables> table = tc.getRootNode();
+ if (tx == null) {
+ tx = this.chain.newWriteOnlyTransaction();
}
-
- LOG.debug("Route {} effective attributes {} towards {}", route.getIdentifier(), effectiveAttrs, routeId);
-
- if (effectiveAttrs != null) {
- tx.put(LogicalDatastoreType.OPERATIONAL, routeId.node(ribSupport.routeAttributesIdentifier()), effectiveAttrs);
-
- updateRoute(this.effectiveRibInRouteCounters, this.effectiveRibInRouteMap, tablesKey, routeId);
- } else {
- LOG.warn("Route {} advertised empty attributes", routeId);
- tx.delete(LogicalDatastoreType.OPERATIONAL, routeId);
-
- deleteRoute(this.effectiveRibInRouteCounters, this.effectiveRibInRouteMap, tablesKey, routeId);
+ final DataObjectModification.ModificationType modificationType = table.getModificationType();
+ switch (modificationType) {
+ case DELETE:
+ final Tables removeTable = table.getDataBefore();
+ final TablesKey tableKey = removeTable.getKey();
+ final KeyedInstanceIdentifier<Tables, TablesKey> effectiveTablePath
+ = this.effRibTables.child(Tables.class, tableKey);
+ LOG.debug("Delete Effective Table {} modification type {}, "
+ , effectiveTablePath, modificationType);
+ tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath);
+ CountersUtil.decrement(this.prefixesInstalled.get(tableKey), tableKey);
+ break;
+ case SUBTREE_MODIFIED:
+ final Tables before = table.getDataBefore();
+ final Tables after = table.getDataAfter();
+ final TablesKey tk = after.getKey();
+ LOG.debug("Process table {} type {}, dataAfter {}, dataBefore {}",
+ tk, modificationType, after, before);
+
+ final KeyedInstanceIdentifier<Tables, TablesKey> tablePath
+ = this.effRibTables.child(Tables.class, tk);
+ final RIBSupport ribSupport = this.registry.getRIBSupport(tk);
+ if (ribSupport == null) {
+ break;
+ }
+ tx.put(LogicalDatastoreType.OPERATIONAL,
+ tablePath.child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp
+ .rib.rev180329.rib.tables.Attributes.class), after.getAttributes());
+
+ final DataObjectModification routesChangesContainer =
+ table.getModifiedChildContainer(ribSupport.routesContainerClass());
+
+ if (routesChangesContainer == null) {
+ break;
+ }
+ updateRoutes(tx, tk, ribSupport, tablePath, routesChangesContainer.getModifiedChildren());
+ break;
+ case WRITE:
+ writeTable(tx, table);
+ break;
+ default:
+ LOG.warn("Ignoring unhandled root {}", table);
+ break;
}
- break;
- default:
- LOG.warn("Ignoring unhandled route {}", route);
- break;
+ }
+ if (tx != null) {
+ tx.submit();
}
}
- private void processTableChildren(final DOMDataWriteTransaction tx, final RIBSupport ribSupport, final YangInstanceIdentifier tablePath, final Collection<DataTreeCandidateNode> children) {
- for (final DataTreeCandidateNode child : children) {
- final PathArgument childIdentifier = child.getIdentifier();
- final Optional<NormalizedNode<?, ?>> childDataAfter = child.getDataAfter();
- final TablesKey tablesKey = new TablesKey(ribSupport.getAfi(), ribSupport.getSafi());
- LOG.debug("Process table {} type {}, dataAfter {}, dataBefore {}", childIdentifier, child
- .getModificationType(), childDataAfter, child.getDataBefore());
- final YangInstanceIdentifier childPath = tablePath.node(childIdentifier);
- switch (child.getModificationType()) {
- case DELETE:
- case DISAPPEARED:
- tx.delete(LogicalDatastoreType.OPERATIONAL, childPath);
- LOG.debug("Route deleted. routeId={}", childPath);
-
- deleteRoute(this.adjRibInRouteCounters, this.adjRibInRouteMap, tablesKey, childPath);
- deleteRoute(this.effectiveRibInRouteCounters, this.effectiveRibInRouteMap, tablesKey, childPath);
- break;
- case UNMODIFIED:
- // No-op
- break;
- case SUBTREE_MODIFIED:
- processModifiedRouteTables(child, childIdentifier,tx, ribSupport, EffectiveRibInWriter.this.importPolicy, childPath, childDataAfter);
- break;
- case APPEARED:
- case WRITE:
- writeRouteTables(child, childIdentifier,tx, ribSupport, EffectiveRibInWriter.this.importPolicy, childPath, childDataAfter);
-
- break;
- default:
- LOG.warn("Ignoring unhandled child {}", child);
- break;
+ @SuppressWarnings("unchecked")
+ private void updateRoutes(
+ final WriteTransaction tx,
+ final TablesKey tableKey, final RIBSupport ribSupport,
+ final KeyedInstanceIdentifier<Tables, TablesKey> tablePath,
+ final Collection<DataObjectModification<? extends DataObject>> routeChanges) {
+ for (final DataObjectModification<? extends DataObject> routeChanged : routeChanges) {
+ final Identifier routeKey
+ = ((InstanceIdentifier.IdentifiableItem) routeChanged.getIdentifier()).getKey();
+ switch (routeChanged.getModificationType()) {
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ writeRoutes(tx, tableKey, ribSupport, tablePath, routeKey, (Route) routeChanged.getDataAfter());
+ break;
+ case DELETE:
+ final InstanceIdentifier routeIID = ribSupport.createRouteIdentifier(tablePath, routeKey);
+ tx.delete(LogicalDatastoreType.OPERATIONAL, routeIID);
+ break;
}
}
}
- private void processModifiedRouteTables(final DataTreeCandidateNode child, final PathArgument childIdentifier, final DOMDataWriteTransaction tx,
- final RIBSupport ribSupport, final AbstractImportPolicy policy, final YangInstanceIdentifier childPath, final Optional<NormalizedNode<?, ?>> childDataAfter) {
- if (TABLE_ROUTES.equals(childIdentifier)) {
- for (final DataTreeCandidateNode route : ribSupport.changedRoutes(child)) {
- processRoute(tx, ribSupport, policy, childPath, route);
- }
+ @SuppressWarnings("unchecked")
+ private void writeRoutes(final WriteTransaction tx, final TablesKey tk, final RIBSupport ribSupport,
+ final KeyedInstanceIdentifier<Tables, TablesKey> tablePath, final Identifier routeKey,
+ final Route route) {
+ final InstanceIdentifier routeIID = ribSupport.createRouteIdentifier(tablePath, routeKey);
+ CountersUtil.increment(this.prefixesReceived.get(tk), tk);
+ final Optional<Attributes> effAtt = this.ribPolicies
+ .applyImportPolicies(this.peerImportParameters, route.getAttributes());
+ if (effAtt.isPresent()) {
+ CountersUtil.increment(this.prefixesInstalled.get(tk), tk);
+ tx.put(LogicalDatastoreType.OPERATIONAL, routeIID, route);
+ tx.put(LogicalDatastoreType.OPERATIONAL, routeIID.child(Attributes.class), effAtt.get());
} else {
- tx.put(LogicalDatastoreType.OPERATIONAL, childPath, childDataAfter.get());
+ tx.delete(LogicalDatastoreType.OPERATIONAL, routeIID);
}
}
- private void writeRouteTables(final DataTreeCandidateNode child, final PathArgument childIdentifier, final DOMDataWriteTransaction tx, final RIBSupport ribSupport, final AbstractImportPolicy policy, final YangInstanceIdentifier childPath, final Optional<NormalizedNode<?, ?>> childDataAfter) {
- if (TABLE_ROUTES.equals(childIdentifier)) {
- final Collection<DataTreeCandidateNode> changedRoutes = ribSupport.changedRoutes(child);
- if (!changedRoutes.isEmpty()) {
- tx.put(LogicalDatastoreType.OPERATIONAL, childPath, childDataAfter.get());
- // Routes are special, as they may end up being filtered. The previous put conveniently
- // ensured that we have them in at target, so a subsequent delete will not fail :)
- for (final DataTreeCandidateNode route : changedRoutes) {
- processRoute(tx, ribSupport, policy, childPath, route);
- }
- }
+ @SuppressWarnings("unchecked")
+ private void writeTable(final WriteTransaction tx, final DataObjectModification<Tables> table) {
+ final Tables newTable = table.getDataAfter();
+ if (newTable == null) {
+ return;
}
- }
+ final TablesKey tableKey = newTable.getKey();
+ final KeyedInstanceIdentifier<Tables, TablesKey> tablePath
+ = this.effRibTables.child(Tables.class, tableKey);
- private RIBSupportContext getRibSupport(final NodeIdentifierWithPredicates tableKey) {
- return this.registry.getRIBSupportContext(tableKey);
- }
+ // Create an empty table
+ LOG.trace("Create Empty table", tablePath);
+ if (table.getDataBefore() == null) {
+ tx.put(LogicalDatastoreType.OPERATIONAL, tablePath, new TablesBuilder()
+ .setAfi(tableKey.getAfi()).setSafi(tableKey.getSafi())
+ .setRoutes(this.registry.getRIBSupport(tableKey).emptyRoutesContainer())
+ .setAttributes(newTable.getAttributes()).build());
+ }
- private YangInstanceIdentifier effectiveTablePath(final NodeIdentifierWithPredicates tableKey) {
- return this.effRibTables.node(tableKey);
- }
+ final RIBSupport ribSupport = this.registry.getRIBSupport(tableKey);
+ final Routes routes = newTable.getRoutes();
+ if (ribSupport == null || routes == null) {
+ return;
+ }
- private void modifyTable(final DOMDataWriteTransaction tx, final NodeIdentifierWithPredicates tableKey, final DataTreeCandidateNode table) {
- final RIBSupportContext ribSupport = getRibSupport(tableKey);
- final YangInstanceIdentifier tablePath = effectiveTablePath(tableKey);
+ final DataObjectModification routesChangesContainer =
+ table.getModifiedChildContainer(ribSupport.routesContainerClass());
- processTableChildren(tx, ribSupport.getRibSupport(), tablePath, table.getChildNodes());
+ if (routesChangesContainer == null) {
+ return;
+ }
+ updateRoutes(tx, tableKey, ribSupport, tablePath, routesChangesContainer.getModifiedChildren());
}
- private void writeTable(final DOMDataWriteTransaction tx, final NodeIdentifierWithPredicates tableKey, final DataTreeCandidateNode table) {
- final RIBSupportContext ribSupport = getRibSupport(tableKey);
- final YangInstanceIdentifier tablePath = effectiveTablePath(tableKey);
-
- // Create an empty table
- LOG.trace("Create Empty table", tablePath);
- ribSupport.createEmptyTableStructure(tx, tablePath);
-
- processTableChildren(tx, ribSupport.getRibSupport(), tablePath, table.getChildNodes());
+ @Override
+ public synchronized void close() {
+ this.reg.close();
+ this.prefixesReceived.values().forEach(LongAdder::reset);
+ this.prefixesInstalled.values().forEach(LongAdder::reset);
}
@Override
- public void onDataTreeChanged(@Nonnull final Collection<DataTreeCandidate> changes) {
- LOG.trace("Data changed called to effective RIB. Change : {}", changes);
-
- // we have a lot of transactions created for 'nothing' because a lot of changes
- // are skipped, so ensure we only create one transaction when we really need it
- DOMDataWriteTransaction tx = null;
- for (final DataTreeCandidate tc : changes) {
- final YangInstanceIdentifier rootPath = tc.getRootPath();
-
- final DataTreeCandidateNode root = tc.getRootNode();
- for (final DataTreeCandidateNode table : root.getChildNodes()) {
- if (tx == null) {
- tx = this.chain.newWriteOnlyTransaction();
- }
- changeDataTree(tx, rootPath, root, table);
- }
- }
- if (tx != null) {
- tx.submit();
+ public long getPrefixedReceivedCount(final TablesKey tablesKey) {
+ final LongAdder counter = this.prefixesReceived.get(tablesKey);
+ if (counter == null) {
+ return 0;
}
+ return counter.longValue();
}
- private void changeDataTree(final DOMDataWriteTransaction tx, final YangInstanceIdentifier rootPath,
- final DataTreeCandidateNode root, final DataTreeCandidateNode table) {
- final PathArgument lastArg = table.getIdentifier();
- Verify.verify(lastArg instanceof NodeIdentifierWithPredicates, "Unexpected type %s in path %s", lastArg.getClass(), rootPath);
- final NodeIdentifierWithPredicates tableKey = (NodeIdentifierWithPredicates) lastArg;
- final RIBSupport ribSupport = getRibSupport(tableKey).getRibSupport();
- final ModificationType modificationType = root.getModificationType();
- switch (modificationType) {
- case DELETE:
- case DISAPPEARED:
- final YangInstanceIdentifier effectiveTablePath = effectiveTablePath(tableKey);
- LOG.debug("Delete Effective Table {} modification type {}, ", effectiveTablePath, modificationType);
+ @Override
+ public Set<TablesKey> getTableKeys() {
+ return ImmutableSet.copyOf(this.prefixesReceived.keySet());
+ }
- // delete the corresponding effective table
- tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath);
+ @Override
+ public boolean isSupported(final TablesKey tablesKey) {
+ return this.prefixesReceived.containsKey(tablesKey);
+ }
- deleteRoute(this.adjRibInRouteCounters, this.adjRibInRouteMap, new TablesKey(ribSupport.getAfi(), ribSupport.getSafi()));
- deleteRoute(this.effectiveRibInRouteCounters, this.effectiveRibInRouteMap, new TablesKey(ribSupport.getAfi(), ribSupport.getSafi()));
- break;
- case SUBTREE_MODIFIED:
- modifyTable(tx, tableKey, table);
- break;
- case UNMODIFIED:
- LOG.info("Ignoring spurious notification on {} data {}", rootPath, table);
- break;
- case APPEARED:
- case WRITE:
- writeTable(tx, tableKey, table);
- break;
- default:
- LOG.warn("Ignoring unhandled root {}", root);
- break;
+ @Override
+ public long getPrefixedInstalledCount(final TablesKey tablesKey) {
+ final LongAdder counter = this.prefixesInstalled.get(tablesKey);
+ if (counter == null) {
+ return 0;
}
+ return counter.longValue();
}
@Override
- public void close() {
- this.reg.close();
+ public long getTotalPrefixesInstalled() {
+ return this.prefixesInstalled.values().stream().mapToLong(LongAdder::longValue).sum();
}
}
-
- private final AdjInTracker adjInTracker;
- private final AbstractImportPolicy importPolicy;
-
- @Deprecated
- static EffectiveRibInWriter create(@Nonnull final DOMDataTreeChangeService service, @Nonnull final DOMTransactionChain chain,
- @Nonnull final YangInstanceIdentifier peerIId, @Nonnull final ImportPolicyPeerTracker importPolicyPeerTracker, @Nonnull final RIBSupportContextRegistry registry, final PeerRole peerRole) {
- return new EffectiveRibInWriter(service, chain, peerIId, importPolicyPeerTracker, registry, peerRole);
- }
-
- static EffectiveRibInWriter create(@Nonnull final DOMDataTreeChangeService service, @Nonnull final DOMTransactionChain chain,
- @Nonnull final YangInstanceIdentifier peerIId, @Nonnull final ImportPolicyPeerTracker importPolicyPeerTracker, @Nonnull final RIBSupportContextRegistry registry, final PeerRole peerRole,
- @Nonnull final PerTableTypeRouteCounter effectiveRouteCounters, @Nonnull final PerTableTypeRouteCounter adjRibInRouteCounters) {
- return new EffectiveRibInWriter(service, chain, peerIId, importPolicyPeerTracker, registry, peerRole, effectiveRouteCounters, adjRibInRouteCounters);
- }
-
- @Deprecated
- private EffectiveRibInWriter(final DOMDataTreeChangeService service, final DOMTransactionChain chain, final YangInstanceIdentifier peerIId,
- final ImportPolicyPeerTracker importPolicyPeerTracker, final RIBSupportContextRegistry registry, final PeerRole peerRole) {
- importPolicyPeerTracker.peerRoleChanged(peerIId, peerRole);
- this.importPolicy = importPolicyPeerTracker.policyFor(IdentifierUtils.peerId((NodeIdentifierWithPredicates) peerIId.getLastPathArgument()));
- this.adjInTracker = new AdjInTracker(service, registry, chain, peerIId);
- }
-
- private EffectiveRibInWriter(final DOMDataTreeChangeService service, final DOMTransactionChain chain, final YangInstanceIdentifier peerIId,
- final ImportPolicyPeerTracker importPolicyPeerTracker, final RIBSupportContextRegistry registry, final PeerRole peerRole,
- @Nonnull final PerTableTypeRouteCounter effectiveRouteCounters, @Nonnull final PerTableTypeRouteCounter adjRibInRouteCounters) {
- importPolicyPeerTracker.peerRoleChanged(peerIId, peerRole);
- this.importPolicy = importPolicyPeerTracker.policyFor(IdentifierUtils.peerId((NodeIdentifierWithPredicates) peerIId.getLastPathArgument()));
- this.adjInTracker = new AdjInTracker(service, registry, chain, peerIId, effectiveRouteCounters, adjRibInRouteCounters);
- }
-
- @Override
- public void close() {
- this.adjInTracker.close();
- }
}