--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+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.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+
+/**
+ * Maintains the mapping of PeerId -> Role. Subclasses get notified of changes and can do their
+ * own thing.
+ */
+abstract class AbstractPeerRoleTracker implements AutoCloseable {
+ /**
+ * 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) {
+ for (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);
+ }
+ }
+ }
+
+ private static final QName PEER_ROLE = QName.cachedReference(QName.create(Peer.QNAME, "peer-role"));
+ private final ListenerRegistration<?> registration;
+
+ protected AbstractPeerRoleTracker(final @Nonnull DOMDataTreeChangeService service, @Nonnull final YangInstanceIdentifier ribId) {
+ // Slightly evil, but our users should be fine with this
+ registration = service.registerDataTreeChangeListener(
+ new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, ribId.node(Peer.QNAME).node(PEER_ROLE)),
+ new PeerRoleListener());
+ }
+
+ @Override
+ public void close() {
+ registration.close();
+ }
+
+ /**
+ * Invoked whenever a peer role changes.
+ *
+ * @param peerPath Peer's path
+ * @param role Peer's new role, null indicates the peer has disappeared.
+ */
+ protected abstract void peerRoleChanged(@Nonnull YangInstanceIdentifier peerPath, @Nullable PeerRole role);
+}
*/
package org.opendaylight.protocol.bgp.rib.impl;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
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.LeafNode;
-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;
* structures. This is done so we maintain causality and loose coupling.
*/
@NotThreadSafe
-final class EffectiveRibInWriter {
- private static final Predicate<PathArgument> IS_PEER = new Predicate<PathArgument>() {
- @Override
- public boolean apply(final PathArgument input) {
- return input.getNodeType().equals(Peer.QNAME);
- }
- };
- private static final Predicate<PathArgument> IS_TABLES = new Predicate<PathArgument>() {
- @Override
- public boolean apply(final PathArgument input) {
- return input.getNodeType().equals(Tables.QNAME);
- }
- };
- private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
- private static final QName PEER_ID = QName.create(Peer.QNAME, "peer-id");
-
- // FIXME: implement as id.firstIdentifierOf(IS_PEER), null indicating not found
- private static final NodeIdentifierWithPredicates firstKeyOf(final YangInstanceIdentifier id, final Predicate<PathArgument> match) {
- final PathArgument ret = Iterables.find(id.getPathArguments(), IS_PEER);
- Preconditions.checkArgument(ret instanceof NodeIdentifierWithPredicates, "Non-key peer identifier %s", ret);
- return (NodeIdentifierWithPredicates) ret;
- }
+final class EffectiveRibInWriter implements AutoCloseable {
- static final NodeIdentifierWithPredicates peerKey(final YangInstanceIdentifier id) {
- return firstKeyOf(id, IS_PEER);
- }
-
- static final PeerId peerId(final NodeIdentifierWithPredicates peerKey) {
- return (PeerId) peerKey.getKeyValues().get(PEER_ID);
- }
-
- private static final NodeIdentifierWithPredicates tableKey(final YangInstanceIdentifier id) {
- return firstKeyOf(id, IS_TABLES);
- }
-
- /**
- * Maintains the mapping of PeerId -> Role inside. 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) {
- synchronized (policies) {
- for (DataTreeCandidate tc : changes) {
- // Obtain the peer's key
- final NodeIdentifierWithPredicates peerKey = peerKey(tc.getRootPath());
-
- // Check for removal
- final Optional<NormalizedNode<?, ?>> maybePeerRole = tc.getRootNode().getDataAfter();
- if (maybePeerRole.isPresent()) {
- final LeafNode<?> peerRoleLeaf = (LeafNode<?>) maybePeerRole.get();
- // FIXME: need codec here
- final PeerRole peerRole = (PeerRole) peerRoleLeaf.getValue();
-
- // Lookup policy based on role
- final AbstractImportPolicy policy = AbstractImportPolicy.forRole(peerRole);
-
- // Update lookup map
- policies.put(peerId(peerKey), policy);
- } else {
- policies.remove(peerId(peerKey));
- }
- }
- }
- }
- }
+ private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
/**
* Maintains the individual routes for a particular table's routes under:
this.tableKey = Preconditions.checkNotNull(tableKey);
// Lookup peer ID
- this.peerId = (PeerId) Preconditions.checkNotNull(peerKey.getKeyValues().get(PEER_ID));
+ this.peerId = IdentifierUtils.peerId(peerKey);
// FIXME: need target table ID
target = null;
final ContainerNode effectiveAttrs;
if (adverisedAttrs != null && tc.getRootNode().getDataAfter().isPresent()) {
- synchronized (policies) {
- final AbstractImportPolicy policy = policies.get(peerId);
- effectiveAttrs = policy.effectiveAttributes(adverisedAttrs);
- }
+ final AbstractImportPolicy policy = peerPolicyTracker.policyFor(peerId);
+ effectiveAttrs = policy.effectiveAttributes(adverisedAttrs);
} else {
effectiveAttrs = null;
}
for (DataTreeCandidate tc : changes) {
// Obtain the peer's key
- final NodeIdentifierWithPredicates peerKey = peerKey(tc.getRootPath());
+ final NodeIdentifierWithPredicates peerKey = IdentifierUtils.peerKey(tc.getRootPath());
// Lookup
- final NodeIdentifierWithPredicates tableKey = tableKey(tc.getRootPath());
+ final NodeIdentifierWithPredicates tableKey = IdentifierUtils.tableKey(tc.getRootPath());
switch (tc.getRootNode().getModificationType()) {
case DELETE:
}
}
- private final Map<PeerId, AbstractImportPolicy> policies = new HashMap<>();
+ private final ImportPolicyPeerTracker peerPolicyTracker;
private final DOMTransactionChain chain;
- private EffectiveRibInWriter(final DOMTransactionChain chain) {
+ private EffectiveRibInWriter(final DOMDataTreeChangeService service, final DOMTransactionChain chain, final YangInstanceIdentifier ribId) {
this.chain = Preconditions.checkNotNull(chain);
- // FIXME: subscribe peerRoleListener, tableListener
+ this.peerPolicyTracker = new ImportPolicyPeerTracker(service, ribId);
+
+ // FIXME: subscribe tableListener
+ }
+
+ @Override
+ public void close() {
+ peerPolicyTracker.close();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+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.bgp.rib.rib.Peer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+final class IdentifierUtils {
+ private static final Predicate<PathArgument> IS_PEER = new Predicate<PathArgument>() {
+ @Override
+ public boolean apply(final PathArgument input) {
+ return input.getNodeType().equals(Peer.QNAME);
+ }
+ };
+ private static final Predicate<PathArgument> IS_TABLES = new Predicate<PathArgument>() {
+ @Override
+ public boolean apply(final PathArgument input) {
+ return input.getNodeType().equals(Tables.QNAME);
+ }
+ };
+ private static final QName PEER_ID = QName.cachedReference(QName.create(Peer.QNAME, "peer-id"));
+
+ private IdentifierUtils() {
+ throw new UnsupportedOperationException();
+ }
+
+ // FIXME: implement as id.firstIdentifierOf(IS_PEER), null indicating not found
+ private static NodeIdentifierWithPredicates firstKeyOf(final YangInstanceIdentifier id, final Predicate<PathArgument> match) {
+ final PathArgument ret = Iterables.find(id.getPathArguments(), match);
+ Preconditions.checkArgument(ret instanceof NodeIdentifierWithPredicates, "Non-key peer identifier %s", ret);
+ return (NodeIdentifierWithPredicates) ret;
+ }
+
+ private static YangInstanceIdentifier firstIdentifierOf(final YangInstanceIdentifier id, final Predicate<PathArgument> match) {
+ final int idx = Iterables.indexOf(id.getPathArguments(), match);
+ Preconditions.checkArgument(idx != -1, "Failed to find %s in %s", match, id);
+ return YangInstanceIdentifier.create(Iterables.limit(id.getPathArguments(), idx));
+ }
+
+ static YangInstanceIdentifier peerPath(final YangInstanceIdentifier id) {
+ return firstIdentifierOf(id, IS_PEER);
+ }
+
+ static NodeIdentifierWithPredicates peerKey(final YangInstanceIdentifier id) {
+ return firstKeyOf(id, IS_PEER);
+ }
+
+ static PeerId peerId(final NodeIdentifierWithPredicates peerKey) {
+ // We could use a codec, but this is simple enough
+ return new PeerId((String) peerKey.getKeyValues().get(PEER_ID));
+ }
+
+ static NodeIdentifierWithPredicates tableKey(final YangInstanceIdentifier id) {
+ return firstKeyOf(id, IS_TABLES);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.rib.impl;
+
+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;
+
+/**
+ * Tracks import policy corresponding to a particular peer.
+ */
+final class ImportPolicyPeerTracker extends AbstractPeerRoleTracker {
+ private final Map<PeerId, AbstractImportPolicy> policies = new ConcurrentHashMap<>();
+
+ protected ImportPolicyPeerTracker(final DOMDataTreeChangeService service, final YangInstanceIdentifier ribId) {
+ super(service, ribId);
+ }
+
+ @Override
+ protected void peerRoleChanged(final YangInstanceIdentifier peerPath, final PeerRole role) {
+ final PeerId peer = IdentifierUtils.peerId((NodeIdentifierWithPredicates) peerPath.getLastPathArgument());
+
+ if (role != null) {
+ // Lookup policy based on role
+ final AbstractImportPolicy policy = AbstractImportPolicy.forRole(role);
+
+ // Update lookup map
+ policies.put(peer, policy);
+ } else {
+ policies.remove(peer);
+ }
+ }
+
+ AbstractImportPolicy policyFor(final PeerId peerId) {
+ return policies.get(peerId);
+ }
+}
\ No newline at end of file
for (DataTreeCandidate tc : changes) {
final YangInstanceIdentifier path = tc.getRootPath();
final PathArgument routeId = path.getLastPathArgument();
- final NodeIdentifierWithPredicates peerKey = EffectiveRibInWriter.peerKey(path);
- final PeerId peerId = EffectiveRibInWriter.peerId(peerKey);
+ final NodeIdentifierWithPredicates peerKey = IdentifierUtils.peerKey(path);
+ final PeerId peerId = IdentifierUtils.peerId(peerKey);
final UnsignedInteger routerId = RouterIds.routerIdForPeerId(peerId);
RouteEntry entry = routeEntries.get(routeId);