package org.opendaylight.protocol.bgp.rib.impl;
import com.google.common.base.Optional;
-import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
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;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* Maintains the mapping of PeerId -> Role. Subclasses get notified of changes and can do their
* own thing.
*/
-abstract class AbstractPeerRoleTracker implements AutoCloseable {
+abstract class AbstractPeerRoleTracker {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPeerRoleTracker.class);
- /**
- * We are subscribed to our target leaf, but that is a wildcard:
- * /bgp-rib/rib/peer/peer-role
- *
- * MD-SAL assumption: we are getting one {@link DataTreeCandidate} for each expanded
- * wildcard path, so are searching for a particular key.
- */
- private final class PeerRoleListener implements DOMDataTreeChangeListener {
-
- @Override
- public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
- LOG.debug("Data Changed for Peer role {}", changes);
- for (final DataTreeCandidate tc : changes) {
- // Obtain the peer's path
- final YangInstanceIdentifier peerPath = IdentifierUtils.peerPath(tc.getRootPath());
-
- // Check for removal
- final Optional<NormalizedNode<?, ?>> maybePeerRole = tc.getRootNode().getDataAfter();
- final PeerRole role;
- if (maybePeerRole.isPresent()) {
- final LeafNode<?> peerRoleLeaf = (LeafNode<?>) maybePeerRole.get();
- // We could go for a coded, but his is simpler and faster
- role = PeerRole.valueOf(BindingMapping.getClassName((String) peerRoleLeaf.getValue()));
- } else {
- role = null;
- }
-
- peerRoleChanged(peerPath, role);
- }
+ public void onDataTreeChanged(final DataTreeCandidateNode change, final YangInstanceIdentifier peerPath) {
+ LOG.debug("Data Changed for Peer role {} path {}", change, peerPath);
+
+ // Check for removal
+ final Optional<NormalizedNode<?, ?>> maybePeerRole = change.getDataAfter();
+ final PeerRole role;
+ if (maybePeerRole.isPresent()) {
+ final LeafNode<?> peerRoleLeaf = (LeafNode<?>) maybePeerRole.get();
+ // We could go for a codec, but this is simpler and faster
+ role = PeerRole.valueOf(BindingMapping.getClassName((String) peerRoleLeaf.getValue()));
+ } else {
+ role = null;
}
+ peerRoleChanged(peerPath, role);
}
- private static final QName PEER_ROLE = QName.cachedReference(QName.create(Peer.QNAME, "peer-role"));
- private final ListenerRegistration<?> registration;
-
- protected AbstractPeerRoleTracker(@Nonnull final DOMDataTreeChangeService service, @Nonnull final YangInstanceIdentifier ribId) {
- // Slightly evil, but our users should be fine with this
- final YangInstanceIdentifier roleId = ribId.node(Peer.QNAME).node(Peer.QNAME).node(PEER_ROLE);
- this.registration = service.registerDataTreeChangeListener(new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, roleId), new PeerRoleListener());
- }
+ static final NodeIdentifier PEER_ROLE_NID = new NodeIdentifier(QName.cachedReference(QName.create(Peer.QNAME, "peer-role")));
- @Override
- public void close() {
- this.registration.close();
+ protected AbstractPeerRoleTracker() {
}
/**
final class EffectiveRibInWriter implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
private static final NodeIdentifier TABLE_ROUTES = new NodeIdentifier(Routes.QNAME);
+ private static final NodeIdentifier ADJRIBIN_NID = new NodeIdentifier(AdjRibIn.QNAME);
+ private static final NodeIdentifier TABLES_NID = new NodeIdentifier(Tables.QNAME);
/**
* Maintains {@link TableRouteListener} instances.
this.chain = Preconditions.checkNotNull(chain);
this.ribId = Preconditions.checkNotNull(ribId);
- final YangInstanceIdentifier tableId = ribId.node(Peer.QNAME).node(Peer.QNAME).node(AdjRibIn.QNAME).node(Tables.QNAME).node(Tables.QNAME);
+ final YangInstanceIdentifier tableId = ribId.node(Peer.QNAME).node(Peer.QNAME);
final DOMDataTreeIdentifier treeId = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, tableId);
LOG.debug("Registered Effective RIB on {}", tableId);
this.reg = service.registerDataTreeChangeListener(treeId, this);
// Obtain the peer's key
final NodeIdentifierWithPredicates peerKey = IdentifierUtils.peerKey(rootPath);
+ final DataTreeCandidateNode root = tc.getRootNode();
- // Extract the table key, this should be safe based on the path where we subscribed,
- // but let's verify explicitly.
- final PathArgument lastArg = rootPath.getLastPathArgument();
- Verify.verify(lastArg instanceof NodeIdentifierWithPredicates, "Unexpected type %s in path %s", lastArg.getClass(), rootPath);
- final NodeIdentifierWithPredicates tableKey = (NodeIdentifierWithPredicates) lastArg;
+ // call out peer-role has changed
+ final DataTreeCandidateNode roleChange = root.getModifiedChild(AbstractPeerRoleTracker.PEER_ROLE_NID);
+ if (roleChange != null) {
+ EffectiveRibInWriter.this.peerPolicyTracker.onDataTreeChanged(roleChange, IdentifierUtils.peerPath(rootPath));
+ }
- final DataTreeCandidateNode root = tc.getRootNode();
- switch (root.getModificationType()) {
- case DELETE:
- // delete the corresponding effective table
- tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath(peerKey, tableKey));
- break;
- case SUBTREE_MODIFIED:
- modifyTable(tx, peerKey, tableKey, root);
- break;
- case UNMODIFIED:
- LOG.info("Ignoring spurious notification on {} data {}", rootPath, root);
- break;
- case WRITE:
- writeTable(tx, peerKey, tableKey, root);
- break;
- default:
- LOG.warn("Ignoring unhandled root {}", root);
- break;
+ // filter out any change outside AdjRibsIn
+ final DataTreeCandidateNode ribIn = root.getModifiedChild(ADJRIBIN_NID);
+ if (ribIn == null) {
+ LOG.debug("Skipping change {}", tc.getRootNode());
+ continue;
}
- }
+ final DataTreeCandidateNode tables = ribIn.getModifiedChild(TABLES_NID);
+ if (tables == null) {
+ LOG.debug("Skipping change {}", tc.getRootNode());
+ continue;
+ }
+ for (final DataTreeCandidateNode table : tables.getChildNodes()) {
+ final PathArgument lastArg = table.getIdentifier();
+ Verify.verify(lastArg instanceof NodeIdentifierWithPredicates, "Unexpected type %s in path %s", lastArg.getClass(), rootPath);
+ final NodeIdentifierWithPredicates tableKey = (NodeIdentifierWithPredicates) lastArg;
+ switch (root.getModificationType()) {
+ case DELETE:
+ // delete the corresponding effective table
+ tx.delete(LogicalDatastoreType.OPERATIONAL, effectiveTablePath(peerKey, tableKey));
+ break;
+ case MERGE:
+ // TODO: upstream API should never give us this, as it leaks how the delta was created.
+ LOG.info("Merge on {} reported, this should never have happened, but attempting to cope", rootPath);
+ modifyTable(tx, peerKey, tableKey, table);
+ break;
+ case SUBTREE_MODIFIED:
+ modifyTable(tx, peerKey, tableKey, table);
+ break;
+ case UNMODIFIED:
+ LOG.info("Ignoring spurious notification on {} data {}", rootPath, table);
+ break;
+ case WRITE:
+ writeTable(tx, peerKey, tableKey, table);
+ break;
+ default:
+ LOG.warn("Ignoring unhandled root {}", root);
+ break;
+ }
+ }
+ }
tx.submit();
}
private EffectiveRibInWriter(final DOMDataTreeChangeService service, final DOMTransactionChain chain, final YangInstanceIdentifier ribId,
final PolicyDatabase pd, final RIBSupportContextRegistry registry) {
- this.peerPolicyTracker = new ImportPolicyPeerTracker(service, ribId, pd);
+ this.peerPolicyTracker = new ImportPolicyPeerTracker(pd);
this.adjInTracker = new AdjInTracker(service, registry, chain, ribId);
}
@Override
public void close() {
this.adjInTracker.close();
- this.peerPolicyTracker.close();
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
private volatile Map<PeerRole, PeerExportGroup> groups = Collections.emptyMap();
private final PolicyDatabase policyDatabase;
- ExportPolicyPeerTracker(final DOMDataTreeChangeService service, final YangInstanceIdentifier ribId, final PolicyDatabase policyDatabase) {
- super(service, ribId);
+ ExportPolicyPeerTracker(final PolicyDatabase policyDatabase) {
this.policyDatabase = Preconditions.checkNotNull(policyDatabase);
}
// Index things nicely for easy access
final Multimap<PeerRole, YangInstanceIdentifier> roleToIds = ArrayListMultimap.create(PeerRole.values().length, 2);
final Map<PeerId, PeerRole> idToRole = new HashMap<>();
- for (Entry<YangInstanceIdentifier, PeerRole> e : peerPathRoles.entrySet()) {
+ for (final Entry<YangInstanceIdentifier, PeerRole> e : peerPathRoles.entrySet()) {
roleToIds.put(e.getValue(), e.getKey());
idToRole.put(IdentifierUtils.peerId((NodeIdentifierWithPredicates) e.getKey().getLastPathArgument()), e.getValue());
}
final Map<PeerId, PeerRole> allPeerRoles = ImmutableMap.copyOf(idToRole);
final Map<PeerRole, PeerExportGroup> ret = new EnumMap<>(PeerRole.class);
- for (Entry<PeerRole, Collection<YangInstanceIdentifier>> e : roleToIds.asMap().entrySet()) {
- final AbstractExportPolicy policy = policyDatabase.exportPolicyForRole(e.getKey());
+ for (final Entry<PeerRole, Collection<YangInstanceIdentifier>> e : roleToIds.asMap().entrySet()) {
+ final AbstractExportPolicy policy = this.policyDatabase.exportPolicyForRole(e.getKey());
final Collection<Entry<PeerId, YangInstanceIdentifier>> peers = ImmutableList.copyOf(Collections2.transform(e.getValue(), GENERATE_PEERID));
ret.put(e.getKey(), new PeerExportGroup(peers, allPeerRoles, policy));
*/
final PeerRole oldRole;
if (role != null) {
- oldRole = peerRoles.put(peerPath, role);
+ oldRole = this.peerRoles.put(peerPath, role);
} else {
- oldRole = peerRoles.remove(peerPath);
+ oldRole = this.peerRoles.remove(peerPath);
}
if (role != oldRole) {
LOG.debug("Peer {} changed role from {} to {}", peerPath, oldRole, role);
- groups = createGroups(peerRoles);
+ this.groups = createGroups(this.peerRoles);
}
}
PeerExportGroup getPeerGroup(final PeerRole role) {
- return groups.get(Preconditions.checkNotNull(role));
+ return this.groups.get(Preconditions.checkNotNull(role));
}
}
\ No newline at end of file
import com.google.common.base.Preconditions;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Tracks import policy corresponding to a particular peer.
*/
final class ImportPolicyPeerTracker extends AbstractPeerRoleTracker {
+ private static final Logger LOG = LoggerFactory.getLogger(ImportPolicyPeerTracker.class);
+
private final Map<PeerId, AbstractImportPolicy> policies = new ConcurrentHashMap<>();
private final PolicyDatabase policyDatabase;
- protected ImportPolicyPeerTracker(final DOMDataTreeChangeService service, final YangInstanceIdentifier ribId, final PolicyDatabase policyDatabase) {
- super(service, ribId);
+ protected ImportPolicyPeerTracker(final PolicyDatabase policyDatabase) {
+ super();
this.policyDatabase = Preconditions.checkNotNull(policyDatabase);
}
if (role != null) {
// Lookup policy based on role
- final AbstractImportPolicy policy = policyDatabase.importPolicyForRole(role);
+ final AbstractImportPolicy policy = this.policyDatabase.importPolicyForRole(role);
// Update lookup map
- policies.put(peer, policy);
+ this.policies.put(peer, policy);
+ LOG.debug("Updating policy {} for peer {}", policy, peer);
} else {
- policies.remove(peer);
+ this.policies.remove(peer);
}
}
AbstractImportPolicy policyFor(final PeerId peerId) {
- return new CachingImportPolicy(policies.get(peerId));
+ LOG.trace("Peer ID : {}", peerId);
+ return new CachingImportPolicy(this.policies.get(peerId));
}
}
\ No newline at end of file
this.registry = registry;
this.ribSupport = this.registry.getRIBSupportContext(tablesKey).getRibSupport();
this.attributesIdentifier = this.ribSupport.routeAttributesIdentifier();
- this.peerPolicyTracker = new ExportPolicyPeerTracker(service, target, pd);
+ this.peerPolicyTracker = new ExportPolicyPeerTracker(pd);
final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
tx.merge(LogicalDatastoreType.OPERATIONAL, this.locRibTarget.node(Routes.QNAME), this.ribSupport.emptyRoutes());
@Override
public void close() {
- this.peerPolicyTracker.close();
+ this.chain.close();
}
@Nonnull private AbstractRouteEntry createEntry(final PathArgument routeId) {