From ff99057f43c60f74a922c4064b4527ac492708bf Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 12 Mar 2015 20:13:43 +0100 Subject: [PATCH] BUG-2383: wire up AdjRibInWriter 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 Signed-off-by: Dana Kutenicsova --- .../protocol/bgp/rib/impl/AdjRibInWriter.java | 115 ++++++++++++++---- .../protocol/bgp/rib/impl/BGPPeer.java | 31 ++++- .../protocol/bgp/rib/impl/RIBActivator.java | 10 +- .../protocol/bgp/rib/impl/RIBImpl.java | 7 ++ .../protocol/bgp/rib/impl/TableContext.java | 33 +++-- .../protocol/bgp/rib/impl/spi/RIB.java | 8 ++ .../bgp/rib/impl/ApplicationPeerTest.java | 14 +++ 7 files changed, 174 insertions(+), 44 deletions(-) diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java index b630e7b057..01d0448f77 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java @@ -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 ATTRIBUTES_UPTODATE_FALSE = ImmutableNodes.leafNode(QName.create(Attributes.QNAME, "uptodate"), Boolean.FALSE); private static final LeafNode 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 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 tables) { + private AdjRibInWriter(final YangInstanceIdentifier ribPath, final DOMTransactionChain chain, final String role, final YangInstanceIdentifier tablesRoot, final Map 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.emptyMap()); + return new AdjRibInWriter(b.build(), chain, roleString(role), null, Collections.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 tableTypes) { - if (tableTypes.equals(tables.keySet())) { - return this; - } - + AdjRibInWriter transform(final Ipv4Address newPeerId, final RIBExtensionConsumerContext registry, final Set tableTypes) { final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction(); - // Wipe tables which are not present in the new types - for (Entry 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 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 e : tables.entrySet()) { + if (!tableTypes.contains(e.getKey())) { + e.getValue().removeTable(tx); + } } } + // Now create new table instances, potentially creating their empty entries final Builder 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 keyValues = ImmutableMap.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()); } /** diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java index ccca5e700f..4405d21ff4 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java @@ -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 + } } diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBActivator.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBActivator.java index 58741c29f5..1ce965b71c 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBActivator.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBActivator.java @@ -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 startRIBExtensionProviderImpl(final RIBExtensionProviderContext context) { - AdjRIBsFactory adj1 = new AdjRIBsFactory() { + final AdjRIBsFactory adj1 = new AdjRIBsFactory() { @Override public AdjRIBsIn createAdjRIBs(final KeyedInstanceIdentifier basePath) { return new Ipv4AdjRIBsIn(basePath); } }; - AdjRIBsFactory adj2 = new AdjRIBsFactory() { + final AdjRIBsFactory adj2 = new AdjRIBsFactory() { @Override public AdjRIBsIn createAdjRIBs(final KeyedInstanceIdentifier 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())); } } diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java index c2cf319b09..1531935ebe 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java @@ -121,6 +121,7 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable, private final BlockingQueue 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; + } } diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java index 2993b91740..56469ba22f 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java @@ -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 tb = - ImmutableNodes.mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates)tableId.getLastPathArgument()).withChild(EMPTY_TABLE_ATTRIBUTES); + final DataContainerNodeBuilder 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 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); } } diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/RIB.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/RIB.java index 4c09213ab9..955eb1b820 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/RIB.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/RIB.java @@ -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(); } diff --git a/bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeerTest.java b/bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeerTest.java index 3a6ea4fe6f..68166ffa05 100644 --- a/bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeerTest.java +++ b/bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeerTest.java @@ -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() { @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() { -- 2.36.6