BUG-2383: wire up AdjRibInWriter 96/16096/12
authorRobert Varga <rovarga@cisco.com>
Thu, 12 Mar 2015 19:13:43 +0000 (20:13 +0100)
committerDana Kutenicsova <dkutenic@cisco.com>
Tue, 17 Mar 2015 20:58:19 +0000 (21:58 +0100)
Modify AdjRibInWriter lifecycle to fit with BGPPeer actions. Also make
sure we pick up the transaction chain from RIB.

Change-Id: Ide7b7bf3073d5a106608d555577535a079ed2b37
Signed-off-by: Robert Varga <rovarga@cisco.com>
Signed-off-by: Dana Kutenicsova <dkutenic@cisco.com>
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBActivator.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/RIB.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeerTest.java

index b630e7b05722c369551c56fca6bf9654378f9c43..01d0448f77ba7c8c06aea5475d62f77ca7b4ff9f 100644 (file)
@@ -15,15 +15,22 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import javax.annotation.Nonnull;
 import javax.annotation.concurrent.NotThreadSafe;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
+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.bgp.rib.rib.peer.AdjRibIn;
 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;
@@ -36,8 +43,10 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 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.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,36 +58,67 @@ import org.slf4j.LoggerFactory;
 final class AdjRibInWriter {
     private static final Logger LOG = LoggerFactory.getLogger(AdjRibInWriter.class);
 
-    // FIXME: is there a utility method to construct this?
-    private static final ContainerNode EMPTY_ADJRIBIN = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(AdjRibIn.QNAME)).addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build()).build();
     private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_FALSE = ImmutableNodes.leafNode(QName.create(Attributes.QNAME, "uptodate"), Boolean.FALSE);
     private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE = ImmutableNodes.leafNode(ATTRIBUTES_UPTODATE_FALSE.getNodeType(), Boolean.TRUE);
-    private static final QName AFI_QNAME = QName.create(Tables.QNAME, "afi");
-    private static final QName SAFI_QNAME = QName.create(Tables.QNAME, "safi");
+    private static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
+    private static final QName AFI_QNAME = QName.cachedReference(QName.create(Tables.QNAME, "afi"));
+    private static final QName SAFI_QNAME = QName.cachedReference(QName.create(Tables.QNAME, "safi"));
+    private static final QName PEER_ID_QNAME = QName.cachedReference(QName.create(Peer.QNAME, "peer-id"));
+    private static final QName PEER_ROLE_QNAME = QName.cachedReference(QName.create(Peer.QNAME, "peer-role"));
+    private static final NodeIdentifier ADJRIBIN = new NodeIdentifier(AdjRibIn.QNAME);
+    private static final NodeIdentifier PEER_ID = new NodeIdentifier(PEER_ID_QNAME);
+    private static final NodeIdentifier PEER_ROLE = new NodeIdentifier(PEER_ROLE_QNAME);
+    private static final NodeIdentifier TABLES = new NodeIdentifier(Tables.QNAME);
+
+    // FIXME: is there a utility method to construct this?
+    private static final ContainerNode EMPTY_ADJRIBIN = Builders.containerBuilder().withNodeIdentifier(ADJRIBIN).addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build()).build();
 
     private final Map<TablesKey, TableContext> tables;
-    private final YangInstanceIdentifier adjRibInRoot;
+    private final YangInstanceIdentifier tablesRoot;
+    private final YangInstanceIdentifier ribPath;
     private final DOMTransactionChain chain;
+    private final Ipv4Address peerId = null;
+    private final String role;
 
     /*
      * FIXME: transaction chain has to be instantiated in caller, so it can terminate us when it fails.
      */
-    private AdjRibInWriter(final DOMTransactionChain chain, final YangInstanceIdentifier adjRibInRoot, final Map<TablesKey, TableContext> tables) {
+    private AdjRibInWriter(final YangInstanceIdentifier ribPath, final DOMTransactionChain chain, final String role, final YangInstanceIdentifier tablesRoot, final Map<TablesKey, TableContext> tables) {
+        this.ribPath = Preconditions.checkNotNull(ribPath);
         this.chain = Preconditions.checkNotNull(chain);
-        this.adjRibInRoot = Preconditions.checkNotNull(adjRibInRoot);
         this.tables = Preconditions.checkNotNull(tables);
+        this.role = Preconditions.checkNotNull(role);
+        this.tablesRoot = tablesRoot;
     }
 
-    static AdjRibInWriter create(final DOMTransactionChain chain, final YangInstanceIdentifier peer) {
-        // Not used often, no need to optimize it via builder
-        final YangInstanceIdentifier adjRibInRoot = peer.node(EMPTY_ADJRIBIN.getIdentifier());
+    // We could use a codec, but this should be fine, too
+    private static String roleString(final PeerRole role) {
+        switch (role) {
+        case Ebgp:
+            return "ebgp";
+        case Ibgp:
+            return "ibgp";
+        case RrClient:
+            return "rr-client";
+        default:
+            throw new IllegalArgumentException("Unhandled role " + role);
+        }
+    }
 
-        // Create top-level AdjRibIn with an empty table list
-        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
-        tx.put(LogicalDatastoreType.OPERATIONAL, adjRibInRoot, EMPTY_ADJRIBIN);
-        tx.submit();
+    /**
+     * Create a new writer using a transaction chain.
+     *
+     * @param role peer's role
+     * @param chain transaction chain
+     * @return A fresh writer instance
+     */
+    static AdjRibInWriter create(@Nonnull final RibKey key, @Nonnull final PeerRole role, @Nonnull final DOMTransactionChain chain) {
+        final InstanceIdentifierBuilder b = YangInstanceIdentifier.builder();
+        b.node(BgpRib.QNAME);
+        b.node(Rib.QNAME);
+        b.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, key.getId().getValue());
 
-        return new AdjRibInWriter(chain, adjRibInRoot, Collections.<TablesKey, TableContext>emptyMap());
+        return new AdjRibInWriter(b.build(), chain, roleString(role), null, Collections.<TablesKey, TableContext>emptyMap());
     }
 
     /**
@@ -86,23 +126,46 @@ final class AdjRibInWriter {
      * Empty tables are created for new entries and old tables are deleted. Once this
      * method returns, the old instance must not be reasonably used.
      *
+     * @param newPeerId new peer BGP identifier
+     * @param registry RIB extension registry
      * @param tableTypes New tables, must not be null
      * @return New writer
      */
-    AdjRibInWriter changeTableTypes(final RIBExtensionConsumerContext registry, final Set<TablesKey> tableTypes) {
-        if (tableTypes.equals(tables.keySet())) {
-            return this;
-        }
-
+    AdjRibInWriter transform(final Ipv4Address newPeerId, final RIBExtensionConsumerContext registry, final Set<TablesKey> tableTypes) {
         final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
 
-        // Wipe tables which are not present in the new types
-        for (Entry<TablesKey, TableContext> e : tables.entrySet()) {
-            if (!tableTypes.contains(e.getKey())) {
-                e.getValue().removeTable(tx);
+        final YangInstanceIdentifier newTablesRoot;
+        if (!newPeerId.equals(this.peerId)) {
+            if (peerId != null) {
+                // Wipe old peer data completely
+                tx.delete(LogicalDatastoreType.OPERATIONAL, ribPath.node(Peer.QNAME).node(new NodeIdentifierWithPredicates(Peer.QNAME, PEER_ID_QNAME, peerId.getValue())));
+            }
+
+            // Install new empty peer structure
+            final NodeIdentifierWithPredicates peerKey = new NodeIdentifierWithPredicates(Peer.QNAME, PEER_ID_QNAME, newPeerId.getValue());
+            final YangInstanceIdentifier newPeerPath = ribPath.node(Peer.QNAME).node(peerKey);
+
+            final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> pb = Builders.mapEntryBuilder();
+            pb.withNodeIdentifier(peerKey);
+            pb.withChild(ImmutableNodes.leafNode(PEER_ID, newPeerId.getValue()));
+            pb.withChild(ImmutableNodes.leafNode(PEER_ROLE, role));
+            pb.withChild(EMPTY_ADJRIBIN);
+
+            tx.put(LogicalDatastoreType.OPERATIONAL, newPeerPath, pb.build());
+
+            newTablesRoot = newPeerPath.node(EMPTY_ADJRIBIN.getIdentifier()).node(TABLES);
+        } else {
+            newTablesRoot = tablesRoot;
+
+            // Wipe tables which are not present in the new types
+            for (Entry<TablesKey, TableContext> e : tables.entrySet()) {
+                if (!tableTypes.contains(e.getKey())) {
+                    e.getValue().removeTable(tx);
+                }
             }
         }
 
+        // Now create new table instances, potentially creating their empty entries
         final Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
         for (TablesKey k : tableTypes) {
             TableContext ctx = tables.get(k);
@@ -114,7 +177,7 @@ final class AdjRibInWriter {
                 }
 
                 // We will use table keys very often, make sure they are optimized
-                final InstanceIdentifierBuilder idb = YangInstanceIdentifier.builder(adjRibInRoot);
+                final InstanceIdentifierBuilder idb = YangInstanceIdentifier.builder(newTablesRoot);
 
                 // FIXME: use codec to translate the key
                 final Map<QName, Object> keyValues = ImmutableMap.<QName, Object>of(AFI_QNAME, BindingReflections.getQName(k.getAfi()), SAFI_QNAME, BindingReflections.getQName(k.getSafi()));
@@ -132,7 +195,7 @@ final class AdjRibInWriter {
 
         tx.submit();
 
-        return new AdjRibInWriter(chain, adjRibInRoot, tb.build());
+        return new AdjRibInWriter(ribPath, chain, role, newTablesRoot, tb.build());
     }
 
     /**
index ccca5e700fe26a40dafe229fdd495d05795c07a7..4405d21ff4d00928a19abaab60cf62c38943e2ac 100644 (file)
@@ -24,6 +24,11 @@ import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeRegist
 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpPeerState;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpSessionState;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.RouteTable;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.protocol.bgp.rib.RibReference;
 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionStatistics;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
@@ -33,6 +38,7 @@ import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
 import org.opendaylight.protocol.bgp.rib.spi.Peer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
+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.rib.TablesKey;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.slf4j.Logger;
@@ -43,7 +49,7 @@ import org.slf4j.LoggerFactory;
  * Class representing a peer. We have a single instance for each peer, which provides translation from BGP events into
  * RIB actions.
  */
-public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRuntimeMXBean {
+public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRuntimeMXBean, TransactionChainListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class);
 
@@ -63,9 +69,18 @@ public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRun
     private BGPPeerRuntimeRegistration runtimeReg;
     private long sessionEstablishedCounter = 0L;
 
+    @GuardedBy("this")
+    private AdjRibInWriter ribWriter;
+
     public BGPPeer(final String name, final RIB rib) {
         this.rib = Preconditions.checkNotNull(rib);
         this.name = name;
+
+        final DOMTransactionChain chain = rib.createPeerChain(this);
+        // FIXME: make this configurable
+        final PeerRole role = PeerRole.Ibgp;
+
+        ribWriter = AdjRibInWriter.create(((RibReference)rib).getInstanceIdentifier().getKey(), role, chain);
     }
 
     @Override
@@ -97,6 +112,8 @@ public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRun
             this.rib.initTable(this, key);
         }
 
+        this.ribWriter = ribWriter.transform(session.getBgpId(), rib.getRibExtensions(), tables);
+
         // Not particularly nice, but what can
         if (session instanceof BGPSessionImpl) {
             this.reg = this.rib.registerRIBsOut(this, new SessionRIBsOut((BGPSessionImpl) session));
@@ -109,6 +126,7 @@ public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRun
 
     private synchronized void cleanup() {
         // FIXME: BUG-196: support graceful restart
+        this.ribWriter.cleanTables(tables);
         for (final TablesKey key : this.tables) {
             this.rib.clearTable(this, key);
         }
@@ -219,4 +237,15 @@ public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRun
         peerState.setSessionEstablishedCount(this.sessionEstablishedCounter);
         return peerState;
     }
+
+    @Override
+    public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
+        // TODO Auto-generated method stub
+    }
 }
index 58741c29f56d75f2e7bc7493e3eebce9434f3f77..1ce965b71ccccef69db78cfaacfd915d148cc44f 100644 (file)
@@ -8,9 +8,7 @@
 package org.opendaylight.protocol.bgp.rib.impl;
 
 import com.google.common.collect.Lists;
-
 import java.util.List;
-
 import org.opendaylight.protocol.bgp.rib.spi.AbstractRIBExtensionProviderActivator;
 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsFactory;
 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
@@ -26,14 +24,14 @@ public final class RIBActivator extends AbstractRIBExtensionProviderActivator {
 
     @Override
     protected List<AutoCloseable> startRIBExtensionProviderImpl(final RIBExtensionProviderContext context) {
-        AdjRIBsFactory adj1 = new AdjRIBsFactory() {
+        final AdjRIBsFactory adj1 = new AdjRIBsFactory() {
             @Override
             public AdjRIBsIn<?, ?> createAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
                 return new Ipv4AdjRIBsIn(basePath);
             }
         };
 
-        AdjRIBsFactory adj2 = new AdjRIBsFactory() {
+        final AdjRIBsFactory adj2 = new AdjRIBsFactory() {
             @Override
             public AdjRIBsIn<?, ?> createAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
                 return new Ipv6AdjRIBsIn(basePath);
@@ -41,6 +39,8 @@ public final class RIBActivator extends AbstractRIBExtensionProviderActivator {
         };
         return Lists.newArrayList(
                 context.registerAdjRIBsInFactory(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class, adj1),
-                context.registerAdjRIBsInFactory(Ipv6AddressFamily.class, UnicastSubsequentAddressFamily.class, adj2));
+                context.registerAdjRIBsInFactory(Ipv6AddressFamily.class, UnicastSubsequentAddressFamily.class, adj2),
+                context.registerRIBSupport(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class, IPv4RIBSupport.getInstance()),
+                context.registerRIBSupport(Ipv6AddressFamily.class, UnicastSubsequentAddressFamily.class, IPv6RIBSupport.getInstance()));
     }
 }
index c2cf319b09248f8aea55bb5c64cf19dee8bdb680..1531935ebe86800cb356b47a220b90dcd4860e2b 100644 (file)
@@ -121,6 +121,7 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
     private final BlockingQueue<Peer> peers;
     private final DataBroker dataBroker;
     private final DOMDataBroker domDataBroker;
+    private final RIBExtensionConsumerContext extensions;
 
     private final Runnable scheduler = new Runnable() {
         @Override
@@ -168,6 +169,7 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
         this.peers = new LinkedBlockingQueue<>();
         this.dataBroker = dps;
         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
+        this.extensions = Preconditions.checkNotNull(extensions);
 
         LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
 
@@ -449,4 +451,9 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
         return domDataBroker.createTransactionChain(listener);
     }
+
+    @Override
+    public RIBExtensionConsumerContext getRibExtensions() {
+        return extensions;
+    }
 }
index 2993b9174022da694b56e5b1d54b137b5c974543..56469ba22f0a1e69dcb1cd3abe20fd81c0134997 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
+import java.util.Map.Entry;
 import java.util.Set;
 import javax.annotation.concurrent.NotThreadSafe;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -34,6 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Community;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ExtendedCommunity;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+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.schema.ChoiceNode;
@@ -85,19 +87,26 @@ final class TableContext {
         acb.addAll(tableSupport.cacheableAttributeObjects());
 
         // FIXME: new Codec.create(acb.build(), tableSupport.cacheableNlriObjects());
-        attributeCodec = null;
+        this.attributeCodec = null;
 
         // FIXME: new Codec.create(tableSupport.cacheableNlriObjects());
-        nlriCodec = null;
+        this.nlriCodec = null;
     }
 
     YangInstanceIdentifier getTableId() {
-        return tableId;
+        return this.tableId;
     }
 
     static void clearTable(final DOMDataWriteTransaction tx, final RIBSupport tableSupport, final YangInstanceIdentifier tableId) {
-        final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> tb =
-                ImmutableNodes.mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates)tableId.getLastPathArgument()).withChild(EMPTY_TABLE_ATTRIBUTES);
+        final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> tb = ImmutableNodes.mapEntryBuilder();
+        tb.withNodeIdentifier((NodeIdentifierWithPredicates)tableId.getLastPathArgument());
+        tb.withChild(EMPTY_TABLE_ATTRIBUTES);
+
+        // tableId is keyed, but that fact is not directly visible from YangInstanceIdentifier, see BUG-2796
+        final NodeIdentifierWithPredicates tableKey = (NodeIdentifierWithPredicates) tableId.getLastPathArgument();
+        for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
+            tb.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
+        }
 
         final ChoiceNode routes = tableSupport.emptyRoutes();
         Verify.verifyNotNull(routes, "Null empty routes in %s", tableSupport);
@@ -107,29 +116,29 @@ final class TableContext {
     }
 
     void clearTable(final DOMDataWriteTransaction tx) {
-        clearTable(tx, tableSupport, tableId);
+        clearTable(tx, this.tableSupport, this.tableId);
     }
 
     void removeTable(final DOMDataWriteTransaction tx) {
-        tx.delete(LogicalDatastoreType.OPERATIONAL, tableId);
+        tx.delete(LogicalDatastoreType.OPERATIONAL, this.tableId);
     }
 
     void writeRoutes(final Object codecFactory, final DOMDataWriteTransaction tx, final MpReachNlri nlri, final PathAttributes attributes) {
 
         // FIXME: run the decoder process
-        final ContainerNode domNlri = (ContainerNode) nlriCodec;
+        final ContainerNode domNlri = (ContainerNode) this.nlriCodec;
 
         // FIXME: run the decoder process
-        final ContainerNode domAttributes = (ContainerNode) attributeCodec;
+        final ContainerNode domAttributes = (ContainerNode) this.attributeCodec;
         final ContainerNode routeAttributes = Builders.containerBuilder(EMPTY_ROUTE_ATTRIBUTES).withValue(domAttributes.getValue()).build();
 
-        tableSupport.putRoutes(tx, tableId, domNlri, routeAttributes);
+        this.tableSupport.putRoutes(tx, this.tableId, domNlri, routeAttributes);
     }
 
     void removeRoutes(final Object object, final DOMDataWriteTransaction tx, final MpUnreachNlri nlri) {
         // FIXME: run the decoder process
-        final ContainerNode domNlri = (ContainerNode) nlriCodec;
+        final ContainerNode domNlri = (ContainerNode) this.nlriCodec;
 
-        tableSupport.deleteRoutes(tx, tableId, domNlri);
+        this.tableSupport.deleteRoutes(tx, this.tableId, domNlri);
     }
 }
index 4c09213ab9c049bbf9f9a99b825826722a7616a5..955eb1b8206ea3da41de1882727f3c7b310f05e7 100644 (file)
@@ -12,6 +12,7 @@ import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.protocol.bgp.rib.spi.Peer;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
@@ -58,4 +59,11 @@ public interface RIB {
      * @return A new transaction chain.
      */
     DOMTransactionChain createPeerChain(TransactionChainListener listener);
+
+    /**
+     * Return the RIB extensions available to the RIB instance.
+     *
+     * @return RIB extensions handle.
+     */
+    RIBExtensionConsumerContext getRibExtensions();
 }
index 3a6ea4fe6fe04d5dc0813164198d23d9acc95e0b..68166ffa05ea0c774c766ee0f341b076a135147e 100644 (file)
@@ -46,6 +46,8 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
@@ -112,6 +114,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 public class ApplicationPeerTest {
 
@@ -135,9 +139,15 @@ public class ApplicationPeerTest {
     @Mock
     WriteTransaction transWrite;
 
+    @Mock
+    DOMDataWriteTransaction domTransWrite;
+
     @Mock
     BindingTransactionChain chain;
 
+    @Mock
+    DOMTransactionChain domChain;
+
     @Mock
     ApplicationPeer peer;
 
@@ -185,8 +195,10 @@ public class ApplicationPeerTest {
         this.a2 = new org.opendaylight.protocol.bgp.linkstate.RIBActivator();
         this.a2.startRIBExtensionProvider(context);
         Mockito.doReturn(this.chain).when(this.dps).createTransactionChain(Mockito.any(RIBImpl.class));
+        Mockito.doReturn(this.domChain).when(this.dom).createTransactionChain(Mockito.any(BGPPeer.class));
         Mockito.doReturn(this.o).when(this.future).get();
         Mockito.doNothing().when(this.transWrite).put(Mockito.eq(LogicalDatastoreType.OPERATIONAL), Mockito.any(InstanceIdentifier.class), Mockito.any(Rib.class));
+        Mockito.doNothing().when(this.domTransWrite).put(Mockito.eq(LogicalDatastoreType.OPERATIONAL), Mockito.any(YangInstanceIdentifier.class), Mockito.any(NormalizedNode.class));
         Mockito.doAnswer(new Answer<Object>() {
 
             @Override
@@ -199,8 +211,10 @@ public class ApplicationPeerTest {
         Mockito.doNothing().when(this.transWrite).merge(Mockito.eq(LogicalDatastoreType.OPERATIONAL), Mockito.any(InstanceIdentifier.class), Mockito.any(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes.class));
         Mockito.doReturn(false).when(this.o).isPresent();
         Mockito.doReturn(this.future).when(this.transWrite).submit();
+        Mockito.doReturn(this.future).when(this.domTransWrite).submit();
         Mockito.doNothing().when(this.future).addListener(Mockito.any(Runnable.class), Mockito.any(Executor.class));
         Mockito.doReturn(this.transWrite).when(this.chain).newWriteOnlyTransaction();
+        Mockito.doReturn(this.domTransWrite).when(this.domChain).newWriteOnlyTransaction();
         Mockito.doReturn(this.eventLoop).when(this.channel).eventLoop();
         Mockito.doReturn("channel").when(this.channel).toString();
         Mockito.doAnswer(new Answer<Object>() {