BUG-5685: Register BGP Rib to Cluster Singleton Service Provider 04/42904/7
authorClaudio D. Gasparini <cgaspari@cisco.com>
Wed, 10 Aug 2016 12:48:32 +0000 (14:48 +0200)
committerClaudio D. Gasparini <cgaspari@cisco.com>
Sat, 13 Aug 2016 10:06:03 +0000 (10:06 +0000)
Register BGP Rib to Cluster Singleton Service Provider
When running on clustering, it was need it to have different
configuration per instance to avoid conflicts.
Now all instance can have same configuration, since cluster
service provider take cares of make active the one
is running on Leader Cluster. If Leader goes down,
 the instance from the new Leader will become active.

Change-Id: Id93897fd8b5460dc6d445bd7fa1c5faa8729a8b5
Signed-off-by: Claudio D. Gasparini <cgaspari@cisco.com>
bgp/rib-impl/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/impl/RIBImplModule.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/config/BgpDeployerImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/RibImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/BgpDeployer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/spi/RIB.java
bgp/rib-impl/src/main/resources/org/opendaylight/blueprint/bgp-rib.xml
bgp/rib-impl/src/test/java/org/opendaylight/controller/config/yang/bgp/rib/impl/AbstractRIBImplModuleTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/AbstractRIBTestSetup.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ParserToSalTest.java

index 9a9497704be18451be0f464339de25fbf39c712f..d6f6cfa8b64db45564b2525b7bd19bb003fd185a 100755 (executable)
@@ -25,16 +25,21 @@ import java.util.Map;
 import java.util.stream.Collectors;
 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.controller.config.api.osgi.WaitingServiceTracker;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPBestPathSelection;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
 import org.opendaylight.protocol.bgp.rib.impl.spi.InstanceType;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.ProtocolKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.osgi.framework.BundleContext;
 
@@ -73,21 +78,26 @@ public final class RIBImplModule extends org.opendaylight.controller.config.yang
                 WaitingServiceTracker.create(BgpDeployer.class, this.bundleContext);
         final BgpDeployer bgpDeployer = bgpDeployerTracker.waitForService(WaitingServiceTracker.FIVE_MINUTES);
         //map configuration to OpenConfig BGP
-        final Protocol protocol = bgpDeployer.getMappingService().fromRib(getBgpRibId(), getClusterId(), getRibId(), new AsNumber(getLocalAs()), getLocalTableDependency(),
+        final Protocol protocol = bgpDeployer.getMappingService().fromRib(getBgpRibId(), getClusterId(), getRibId(),
+            new AsNumber(getLocalAs()), getLocalTableDependency(),
                 mapBestPathSelectionStrategyByFamily(getRibPathSelectionModeDependency()));
-        //write to configuration DS
-        final KeyedInstanceIdentifier<Protocol, ProtocolKey> protocolIId = bgpDeployer.getInstanceIdentifier().child(Protocols.class).child(Protocol.class,
-                protocol.getKey());
-        bgpDeployer.writeConfiguration(protocol, protocolIId);
+        final Global global = protocol.getAugmentation(Protocol1.class).getBgp().getGlobal();
+        final KeyedInstanceIdentifier<Protocol, ProtocolKey> protocolIId = bgpDeployer.getInstanceIdentifier().child(Protocols.class)
+            .child(Protocol.class, protocol.getKey());
+        final InstanceIdentifier<Bgp> bgpIID = protocolIId.augmentation(Protocol1.class).child(Bgp.class);
+        bgpDeployer.onGlobalCreated(bgpIID, global, () -> bgpDeployer.writeConfiguration(protocol, protocolIId));
+
         //get rib instance service, use filter
         final WaitingServiceTracker<RIB> ribTracker = WaitingServiceTracker.create(RIB.class,
-                this.bundleContext, "(" + InstanceType.RIB.getBeanName() + "=" + getRibId().getValue() + ")");
+            this.bundleContext, "(" + InstanceType.RIB.getBeanName() + "=" + getRibId().getValue() + ")");
         final RIB rib = ribTracker.waitForService(WaitingServiceTracker.FIVE_MINUTES);
         final RIBImplRuntimeRegistration register = getRootRuntimeBeanRegistratorWrapper().register(rib.getRenderStats());
+
         return Reflection.newProxy(AutoCloseableRIB.class, new AbstractInvocationHandler() {
             @Override
             protected Object handleInvocation(final Object proxy, final Method method, final Object[] args) throws Throwable {
                 if (method.getName().equals("close")) {
+                    bgpDeployer.onGlobalRemoved(bgpIID);
                     register.close();
                     bgpDeployerTracker.close();
                     ribTracker.close();
@@ -105,7 +115,7 @@ public final class RIBImplModule extends org.opendaylight.controller.config.yang
 
     private Map<TablesKey, PathSelectionMode> mapBestPathSelectionStrategyByFamily(final List<BGPBestPathSelection> bestPathSelectionDependency) {
         return Collections.unmodifiableMap(bestPathSelectionDependency.stream().collect(
-                Collectors.<BGPBestPathSelection, TablesKey, PathSelectionMode>toMap(st -> new TablesKey(st.getAfi(), st.getSafi()), st -> st.getStrategy())));
+                Collectors.toMap(st -> new TablesKey(st.getAfi(), st.getSafi()), st -> st.getStrategy())));
     }
 
     private static interface AutoCloseableRIB extends RIB, AutoCloseable {
index d4e31e56244d062ae33fe13811b3f95e8754054c..9d708d0ec732c2e7ae175bf0141be7873e9e4850 100755 (executable)
@@ -7,12 +7,13 @@
  */
 package org.opendaylight.protocol.bgp.rib.impl;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -35,12 +36,17 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
@@ -81,12 +87,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @ThreadSafe
-public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
+public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
-    @VisibleForTesting
-    public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
-    @VisibleForTesting
-    public static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes.QNAME);
+    private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
+    private static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes.QNAME);
 
     private final BGPDispatcher dispatcher;
     private final DOMTransactionChain domChain;
@@ -99,6 +103,11 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
     private final YangInstanceIdentifier yangRibId;
     private final RIBSupportContextRegistryImpl ribContextRegistry;
     private final CodecsRegistryImpl codecsRegistry;
+    private final ServiceGroupIdentifier serviceGroupIdentifier;
+    private final ClusterSingletonServiceProvider provider;
+    private final PolicyDatabase policyDatabase;
+    private final BgpDeployer.WriteConfiguration configurationWriter;
+    private ClusterSingletonServiceRegistration registration;
     private final DOMDataBrokerExtension service;
     private final List<LocRibWriter> locRibs = new ArrayList<>();
     private final BGPConfigModuleTracker configModuleTracker;
@@ -107,14 +116,14 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
     private final ImportPolicyPeerTracker importPolicyPeerTracker;
     private final RIBImplRuntimeMXBeanImpl renderStats;
-    private RIBImplRuntimeRegistrator registrator = null;
-    private RIBImplRuntimeRegistration runtimeReg = null;
-
-    public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
-            final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
-            final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
-            @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
-            final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
+    private final RibId ribId;
+
+    public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
+        final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
+        final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
+        @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
+        final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider, final BgpDeployer.WriteConfiguration configurationWriter) {
+
         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
         this.domChain = domDataBroker.createTransactionChain(this);
         this.localAs = Preconditions.checkNotNull(localAs);
@@ -123,6 +132,7 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
         this.localTables = ImmutableSet.copyOf(localTables);
         this.localTablesKeys = new HashSet<>();
         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
+        this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
         this.extensions = Preconditions.checkNotNull(extensions);
         this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
@@ -134,83 +144,23 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
         this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
         final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
         this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
-
-        LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
-
-        final ContainerNode bgpRib = Builders.containerBuilder()
-                .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
-                .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
-
-        final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
-                new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
-                .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
-                .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
-                .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
-                        .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
-                        .build()).build();
-
-
-        final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
-
-        // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
-        trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
-        trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
-
-        try {
-            trans.submit().checkedGet();
-        } catch (final TransactionCommitFailedException e) {
-            LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
-        }
-        final PolicyDatabase policyDatabase  = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
-        this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
-
-        final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
-        this.service = domDatatreeChangeService;
-        LOG.debug("Effective RIB created.");
-
-        for (final BgpTableType t : this.localTables) {
-            final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
-            this.localTablesKeys.add(key);
-            startLocRib(key, policyDatabase);
-        }
-
-        if (this.configModuleTracker != null) {
-            this.configModuleTracker.onInstanceCreate();
-        }
-    }
-
-    public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
-            final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
-            final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
-            final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies, final GeneratedClassLoadingStrategy classStrategy) {
-        this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
-                domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null);
-    }
-
-    public synchronized void registerRootRuntimeBean(final RIBImplRuntimeRegistrator registrator) {
-        this.registrator = registrator;
-
-        initStatsRuntimeBean();
+        this.ribId = ribId;
+        this.policyDatabase  = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
+        this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl( this.policyDatabase);
+        this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId + "-service-group");
+        Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
+        this.provider = provider;
+        LOG.info("RIB Singleton Service {} registered", this.getIdentifier());
+        this.registration = registerClusterSingletonService(this);
+        this.configurationWriter = configurationWriter;
     }
 
-    /**
-     * Register the statistic runtime bean
-     */
-    private void initStatsRuntimeBean() {
-        if (this.registrator != null) {
-            LOG.debug("Initializing Render Status runtime bean..");
-            this.runtimeReg = this.registrator.register(this.renderStats);
-        }
-    }
-
-    private void stopStatsRuntimeBean() {
-        if (this.runtimeReg != null) {
-            LOG.debug("Destroying Render Status runtime bean..");
-            this.runtimeReg.close();
-            this.runtimeReg = null;
-        }
-        // reset all the stats
-        this.renderStats.getLocRibRouteCounter().resetAll();
+    public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
+        final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
+        final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
+        final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
+        this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
+                domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
     }
 
     private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
@@ -258,27 +208,10 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
     }
 
     @Override
-    public synchronized void close() {
-        try {
-            final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
-            t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
-            t.submit().checkedGet();
-        } catch (final TransactionCommitFailedException e) {
-            LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
-        }
-        this.domChain.close();
-        for (final LocRibWriter locRib : this.locRibs) {
-            try {
-                locRib.close();
-            } catch (final Exception e) {
-                LOG.warn("Could not close LocalRib reference: {}", locRib, e);
-            }
-        }
-
-        stopStatsRuntimeBean();
-
-        if (this.configModuleTracker != null) {
-            this.configModuleTracker.onInstanceClose();
+    public synchronized void close() throws Exception {
+        if (registration != null) {
+            registration.close();
+            registration = null;
         }
     }
 
@@ -371,4 +304,90 @@ public final class RIBImpl extends DefaultRibReference implements AutoCloseable,
     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
         return this.importPolicyPeerTracker;
     }
+
+    @Override
+    public void instantiateServiceInstance() {
+        if(this.configurationWriter != null) {
+            this.configurationWriter.apply();
+        }
+        LOG.info("RIB Singleton Service {} instantiated", this.getIdentifier());
+        LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
+
+        final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
+            .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
+
+        final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
+            new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
+            .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
+            .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
+            .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
+                .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
+                .build()).build();
+
+
+        final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
+
+        // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
+        trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
+        trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
+
+        try {
+            trans.submit().checkedGet();
+        } catch (final TransactionCommitFailedException e) {
+            LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
+        }
+
+        LOG.debug("Effective RIB created.");
+
+        for (final BgpTableType t : this.localTables) {
+            final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
+            this.localTablesKeys.add(key);
+            startLocRib(key, policyDatabase);
+        }
+
+        if (this.configModuleTracker != null) {
+            this.configModuleTracker.onInstanceCreate();
+        }
+    }
+
+    @Override
+    public ListenableFuture<Void> closeServiceInstance() {
+        try {
+            final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
+            t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
+            t.submit().checkedGet();
+        } catch (final TransactionCommitFailedException e) {
+            LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
+        }
+        this.domChain.close();
+        for (final LocRibWriter locRib : this.locRibs) {
+            try {
+                locRib.close();
+            } catch (final Exception e) {
+                LOG.warn("Could not close LocalRib reference: {}", locRib, e);
+            }
+        }
+
+        this.renderStats.getLocRibRouteCounter().resetAll();
+
+        if (this.configModuleTracker != null) {
+            this.configModuleTracker.onInstanceClose();
+        }
+        return Futures.immediateFuture(null);
+    }
+
+    @Override
+    public ServiceGroupIdentifier getIdentifier() {
+        return this.serviceGroupIdentifier;
+    }
+
+    @Override
+    public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
+        return this.provider.registerClusterSingletonService(clusterSingletonService);
+    }
+
+    @Override
+    public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
+        return getIdentifier();
+    }
 }
index 1b572990a81056e0729c0fa27213540a4709e400..49e6bbea76474930f27bb871dfbaf9a5686c4c38 100644 (file)
@@ -12,7 +12,6 @@ import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUti
 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceName;
 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getRibInstanceName;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
@@ -24,15 +23,14 @@ import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
 import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
 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.ReadWriteTransaction;
 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.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
@@ -58,44 +56,43 @@ import org.osgi.service.blueprint.container.BlueprintContainer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListener<Bgp>, AutoCloseable {
-
+public final class BgpDeployerImpl implements BgpDeployer, ClusteredDataTreeChangeListener<Bgp>, AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
-
     private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
     private final BlueprintContainer container;
     private final BundleContext bundleContext;
     private final BGPOpenConfigMappingService mappingService;
-    private final ListenerRegistration<BgpDeployerImpl>  registration;
+    private final ListenerRegistration<BgpDeployerImpl> registration;
     @GuardedBy("this")
     private final Map<InstanceIdentifier<Bgp>, RibImpl> ribs = new HashMap<>();
     @GuardedBy("this")
     private final Map<InstanceIdentifier<Neighbor>, BgpPeer> peers = new HashMap<>();
+    private final DataBroker dataBroker;
     @GuardedBy("this")
     private boolean closed;
 
-    private final DataBroker dataBroker;
-
     public BgpDeployerImpl(final String networkInstanceName, final BlueprintContainer container, final BundleContext bundleContext, final DataBroker dataBroker,
-            final BGPOpenConfigMappingService mappingService) {
+        final BGPOpenConfigMappingService mappingService) {
         this.dataBroker = Preconditions.checkNotNull(dataBroker);
         this.container = Preconditions.checkNotNull(container);
         this.bundleContext = Preconditions.checkNotNull(bundleContext);
         this.mappingService = Preconditions.checkNotNull(mappingService);
         this.networkInstanceIId = InstanceIdentifier
-                .create(NetworkInstances.class)
-                .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
+            .create(NetworkInstances.class)
+            .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
         Futures.addCallback(initializeNetworkInstance(dataBroker, this.networkInstanceIId), new FutureCallback<Void>() {
             @Override
             public void onSuccess(final Void result) {
                 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
             }
+
             @Override
             public void onFailure(final Throwable t) {
                 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, t);
             }
         });
-        this.registration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, this.networkInstanceIId.child(Protocols.class)
+        this.registration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+            this.networkInstanceIId.child(Protocols.class)
                 .child(Protocol.class)
                 .augmentation(Protocol1.class)
                 .child(Bgp.class)), this);
@@ -130,23 +127,23 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
     @Override
     public synchronized void close() throws Exception {
         this.registration.close();
-        this.peers.values().forEach(bgpPeer -> bgpPeer.close());
+        this.peers.values().forEach(BgpPeer::close);
         this.peers.clear();
-        this.ribs.values().forEach(rib -> rib.close());
+        this.ribs.values().forEach(RibImpl::close);
         this.ribs.clear();
         this.closed = true;
     }
 
     private static CheckedFuture<Void, TransactionCommitFailedException> initializeNetworkInstance(final DataBroker dataBroker,
-            final InstanceIdentifier<NetworkInstance> networkInstance) {
+        final InstanceIdentifier<NetworkInstance> networkInstance) {
         final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
         wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
-                new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName()).setProtocols(new ProtocolsBuilder().build()).build());
+            new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName()).setProtocols(new ProtocolsBuilder().build()).build());
         return wTx.submit();
     }
 
     private void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
-            final InstanceIdentifier<Bgp> rootIdentifier) {
+        final InstanceIdentifier<Bgp> rootIdentifier) {
         switch (dataObjectModification.getModificationType()) {
         case DELETE:
             onGlobalRemoved(rootIdentifier);
@@ -164,27 +161,28 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
         LOG.debug("Modifing RIB instance with configuration: {}", global);
         //restart existing rib instance with a new configuration
         final RibImpl ribImpl = this.ribs.get(rootIdentifier);
-        if (ribImpl != null) {
-            ribImpl.close();
-            initiateRibInstance(rootIdentifier, global, ribImpl);
-        } else {
+        if(ribImpl == null ) {
             //if not exists, create a new instance
-            onGlobalCreated(rootIdentifier, global);
+            onGlobalCreated(rootIdentifier, global, null);
+        } else if (!ribImpl.isGlobalEqual(global)) {
+            ribImpl.close();
+            initiateRibInstance(rootIdentifier, global, ribImpl, null);
         }
         LOG.debug("RIB instance modified {}", ribImpl);
     }
 
-    private void onGlobalCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Global global) {
-        //create, start and register rib instance
+    @Override
+    public synchronized void onGlobalCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Global global, final WriteConfiguration
+        configurationWriter) {
         LOG.debug("Creating RIB instance with configuration: {}", global);
         final RibImpl ribImpl = (RibImpl) this.container.getComponentInstance(InstanceType.RIB.getBeanName());
-        initiateRibInstance(rootIdentifier, global, ribImpl);
+        initiateRibInstance(rootIdentifier, global, ribImpl, configurationWriter);
         this.ribs.put(rootIdentifier, ribImpl);
         LOG.debug("RIB instance created {}", ribImpl);
     }
 
-    private void onGlobalRemoved(final InstanceIdentifier<Bgp> rootIdentifier) {
-        //destroy rib instance
+    @Override
+    public synchronized void onGlobalRemoved(final InstanceIdentifier<Bgp> rootIdentifier) {
         LOG.debug("Removing RIB instance: {}", rootIdentifier);
         final RibImpl ribImpl = this.ribs.remove(rootIdentifier);
         if (ribImpl != null) {
@@ -201,14 +199,14 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
     }
 
     private void initiateRibInstance(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
-            final RibImpl ribImpl) {
+        final RibImpl ribImpl, final WriteConfiguration configurationWriter) {
         final String ribInstanceName = getRibInstanceName(rootIdentifier);
-        ribImpl.start(global, ribInstanceName, this.mappingService);
+        ribImpl.start(global, ribInstanceName, this.mappingService, configurationWriter);
         registerRibInstance(ribImpl, ribInstanceName);
     }
 
     private void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
-            final InstanceIdentifier<Bgp> rootIdentifier) {
+        final InstanceIdentifier<Bgp> rootIdentifier) {
         for (final DataObjectModification<? extends DataObject> neighborModification : dataObjectModification.getModifiedChildren()) {
             switch (neighborModification.getModificationType()) {
             case DELETE:
@@ -267,7 +265,7 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
     }
 
     private void initiatePeerInstance(final InstanceIdentifier<Bgp> rootIdentifier, final InstanceIdentifier<Neighbor> neighborIdentifier, final Neighbor neighbor,
-            final BgpPeer bgpPeer) {
+        final BgpPeer bgpPeer) {
         final String peerInstanceName = getNeighborInstanceName(neighborIdentifier);
         final RibImpl rib = this.ribs.get(rootIdentifier);
         if (rib != null) {
@@ -277,38 +275,22 @@ public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListene
     }
 
     @Override
-    public <T extends DataObject> ListenableFuture<Void> writeConfiguration(final T data,
-            final InstanceIdentifier<T> identifier) {
+    public BGPOpenConfigMappingService getMappingService() {
+        return this.mappingService;
+    }
+
+    @Override
+    public <T extends DataObject> ListenableFuture<Void> writeConfiguration(final T data, final InstanceIdentifier<T> identifier) {
         final ReadWriteTransaction wTx = this.dataBroker.newReadWriteTransaction();
-        final CheckedFuture<Optional<T>, ReadFailedException> readFuture = wTx.read(LogicalDatastoreType.CONFIGURATION, identifier);
-        Futures.addCallback(readFuture, new FutureCallback<Optional<T>>() {
-            @Override
-            public void onSuccess(final Optional<T> result) {
-                if (!result.isPresent()) {
-                    wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data);
-                }
-            }
-            @Override
-            public void onFailure(final Throwable t) {
-                LOG.debug("Failed to ensure presence of {}, try to write configuration.", identifier, t);
-                wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data);
-            }
-        });
+        wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data);
         return wTx.submit();
-
     }
 
     @Override
     public <T extends DataObject> ListenableFuture<Void> removeConfiguration(
-            final InstanceIdentifier<T> identifier) {
+        final InstanceIdentifier<T> identifier) {
         final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
         wTx.delete(LogicalDatastoreType.CONFIGURATION, identifier);
         return wTx.submit();
     }
-
-    @Override
-    public BGPOpenConfigMappingService getMappingService() {
-        return this.mappingService;
-    }
-
 }
index 2fa881b041a3387e1e19a7252210dda94bc72abc..44c35d333522c38f5691ed5bb4c47a794e341025 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.protocol.bgp.rib.impl.config;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -19,11 +20,16 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
 import org.opendaylight.protocol.bgp.rib.impl.RIBImpl;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
+import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
@@ -31,8 +37,10 @@ import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 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.RibId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
@@ -60,10 +68,15 @@ public final class RibImpl implements RIB, AutoCloseable {
     private RIBImpl ribImpl;
     private ServiceRegistration<?> serviceRegistration;
     private ListenerRegistration<SchemaContextListener> schemaContextRegistration;
+    private final ClusterSingletonServiceProvider provider;
+    private List<AfiSafi> afiSafi;
+    private AsNumber asNumber;
+    private Ipv4Address routerId;
 
     @SuppressWarnings("deprecation")
-    public RibImpl(final RIBExtensionConsumerContext contextProvider, final BGPDispatcher dispatcher,
+    public RibImpl(final ClusterSingletonServiceProvider provider, final RIBExtensionConsumerContext contextProvider, final BGPDispatcher dispatcher,
             final BindingCodecTreeFactory codecTreeFactory, final DOMDataBroker domBroker, final SchemaService schemaService) {
+        this.provider = Preconditions.checkNotNull(provider);
         this.extensions = contextProvider;
         this.dispatcher = dispatcher;
         this.codecTreeFactory = codecTreeFactory;
@@ -71,12 +84,21 @@ public final class RibImpl implements RIB, AutoCloseable {
         this.schemaService = schemaService;
     }
 
-    void start(final Global global, final String instanceName, final BGPOpenConfigMappingService mappingService) {
+    void start(final Global global, final String instanceName, final BGPOpenConfigMappingService mappingService,
+        final BgpDeployer.WriteConfiguration configurationWriter) {
         Preconditions.checkState(this.ribImpl == null, "Previous instance %s was not closed.", this);
-        this.ribImpl = createRib(global, instanceName, mappingService);
+        this.ribImpl = createRib(provider, global, instanceName, mappingService, configurationWriter);
         this.schemaContextRegistration = this.schemaService.registerSchemaContextListener(this.ribImpl);
     }
 
+    Boolean isGlobalEqual(final Global global) {
+        final List<AfiSafi> globalAfiSafi = global.getAfiSafis().getAfiSafi();
+        final AsNumber globalAs = global.getConfig().getAs();
+        final Ipv4Address globalRouterId = global.getConfig().getRouterId();
+        return this.afiSafi.containsAll(globalAfiSafi) && globalAfiSafi.containsAll(this.afiSafi)
+            && globalAs.equals(this.asNumber) && globalRouterId.equals(this.routerId);
+    }
+
     @Override
     public KeyedInstanceIdentifier<Rib, RibKey> getInstanceIdentifier() {
         return this.ribImpl.getInstanceIdentifier();
@@ -145,7 +167,11 @@ public final class RibImpl implements RIB, AutoCloseable {
     @Override
     public void close() {
         if (this.ribImpl != null) {
-            this.ribImpl.close();
+            try {
+                this.ribImpl.close();
+            } catch (Exception e) {
+                LOG.warn("Failed to close {} rib instance", this, e);
+            }
             this.ribImpl = null;
         }
         if (this.schemaContextRegistration != null) {
@@ -162,7 +188,7 @@ public final class RibImpl implements RIB, AutoCloseable {
         }
     }
 
-    public void setServiceRegistration(final ServiceRegistration<?> serviceRegistration) {
+    void setServiceRegistration(final ServiceRegistration<?> serviceRegistration) {
         this.serviceRegistration = serviceRegistration;
     }
 
@@ -181,19 +207,30 @@ public final class RibImpl implements RIB, AutoCloseable {
         return this.ribImpl.getLocalTablesKeys();
     }
 
+    @Override
+    public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
+        return this.ribImpl.getRibIServiceGroupIdentifier();
+    }
+
     @Override
     public String toString() {
         return this.ribImpl.toString();
     }
 
-    private RIBImpl createRib(final Global global, final String bgpInstanceName, final BGPOpenConfigMappingService mappingService) {
-        final Map<TablesKey, PathSelectionMode> pathSelectionModes = mappingService.toPathSelectionMode(global.getAfiSafis().getAfiSafi()).entrySet()
-                .stream().collect(Collectors.toMap(entry -> new TablesKey(entry.getKey().getAfi(), entry.getKey().getSafi()), entry -> entry.getValue()));
-        return new RIBImpl(new RibId(bgpInstanceName), new AsNumber(global.getConfig().getAs().getValue()),
-                new BgpId(global.getConfig().getRouterId().getValue()), new ClusterIdentifier(global.getConfig().getRouterId().getValue()),
-                this.extensions, this.dispatcher, this.codecTreeFactory, this.domBroker,
-                mappingService.toTableTypes(global.getAfiSafis().getAfiSafi()), pathSelectionModes,
-                this.extensions.getClassLoadingStrategy());
+    private RIBImpl createRib(final ClusterSingletonServiceProvider provider, final Global global, final String bgpInstanceName,
+        final BGPOpenConfigMappingService mappingService, final BgpDeployer.WriteConfiguration configurationWriter) {
+        this.afiSafi = global.getAfiSafis().getAfiSafi();
+        this.asNumber = global.getConfig().getAs();
+        this.routerId = global.getConfig().getRouterId();
+        final Map<TablesKey, PathSelectionMode> pathSelectionModes = mappingService.toPathSelectionMode(this.afiSafi).entrySet()
+                .stream().collect(Collectors.toMap(entry -> new TablesKey(entry.getKey().getAfi(), entry.getKey().getSafi()), Map.Entry::getValue));
+        return new RIBImpl(provider, new RibId(bgpInstanceName), this.asNumber, new BgpId(this.routerId), new ClusterIdentifier(this.routerId),
+                this.extensions, this.dispatcher, this.codecTreeFactory, this.domBroker, mappingService.toTableTypes(this.afiSafi), pathSelectionModes,
+                this.extensions.getClassLoadingStrategy(), configurationWriter);
     }
 
+    @Override
+    public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
+        return this.provider.registerClusterSingletonService(clusterSingletonService);
+    }
 }
index d5dc75f3eb2af1e8659bd0f0a860781388b47e77..b14615bda502da7eb9ff25437ff58bcb4cf7f297 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.protocol.bgp.rib.impl.spi;
 
 import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -18,12 +20,16 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * The BgpDeployer service is managing RIB, Peer, Application Peer instances based on the OpenConfig BGP
  * configuration status.
  * BGP configuration is held under the specific OpenConfig's NetworkInstance subtree.
- *
  */
 public interface BgpDeployer {
 
+    interface WriteConfiguration {
+        void apply();
+    }
+
     /**
      * Get pointer to NetworkInstance instance where this particular BGP deployer is binded.
+     *
      * @return InstanceIdentifier
      */
     InstanceIdentifier<NetworkInstance> getInstanceIdentifier();
@@ -33,4 +39,18 @@ public interface BgpDeployer {
     <T extends DataObject> ListenableFuture<Void> writeConfiguration(T data, InstanceIdentifier<T> identifier);
 
     <T extends DataObject> ListenableFuture<Void> removeConfiguration(InstanceIdentifier<T> identifier);
+
+    /**
+     * Create, start and register rib instance
+     * @param rootIdentifier
+     * @param global
+     * @param configurationWriter
+     */
+    void onGlobalCreated(InstanceIdentifier<Bgp> rootIdentifier, Global global, WriteConfiguration configurationWriter);
+
+    /**
+     * Destroy rib instance
+     * @param rootIdentifier
+     */
+    void onGlobalRemoved(InstanceIdentifier<Bgp> rootIdentifier);
 }
index 60c6c18b123f3924f3a9c1b9a05b57682d7ac122..92128f9e499e1756dde3d8eb3a78a055b4a0c433 100755 (executable)
@@ -13,6 +13,8 @@ import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
 import org.opendaylight.protocol.bgp.rib.RibReference;
 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
@@ -27,7 +29,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 /**
  * Internal reference to a RIB instance.
  */
-public interface RIB  extends RibReference {
+public interface RIB  extends RibReference, ClusterSingletonServiceProvider {
     AsNumber getLocalAs();
 
     BgpId getBgpIdentifier();
@@ -103,4 +105,10 @@ public interface RIB  extends RibReference {
     ImportPolicyPeerTracker getImportPolicyPeerTracker();
 
     Set<TablesKey> getLocalTablesKeys();
+
+    /**
+     * Return common ServiceGroupIdentifier to be used between same group cluster service
+     * @return ServiceGroupIdentifier
+     */
+    ServiceGroupIdentifier getRibIServiceGroupIdentifier();
 }
index ad6820fb62d144a581c04fa89347c99b9b9f4cec..d193a9819b0e17d428450dea5b7fd5ee9fdb16c6 100644 (file)
@@ -5,6 +5,7 @@
   <reference id="BGPExtensionContext" interface="org.opendaylight.protocol.bgp.parser.spi.BGPExtensionConsumerContext"/>
   <reference id="globalBossGroup" interface="io.netty.channel.EventLoopGroup" odl:type="global-boss-group"/>
   <reference id="globalWorkerGroup" interface="io.netty.channel.EventLoopGroup" odl:type="global-worker-group"/>
+  <reference id="clusterSingletonServiceProvider" interface="org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider"/>
 
   <bean id="BGPDispatcher" class="org.opendaylight.protocol.bgp.rib.impl.BGPDispatcherImpl">
     <argument>
@@ -59,6 +60,7 @@
   <service ref="bgpDeployer" interface="org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer"/>
 
   <bean id="ribImpl" class="org.opendaylight.protocol.bgp.rib.impl.config.RibImpl" scope="prototype">
+    <argument ref="clusterSingletonServiceProvider"/>
     <argument ref="globalBgpExtensions"/>
     <argument ref="BGPDispatcher"/>
     <argument ref="codecTreeFactory"/>
index 21c29eb3bf6f7bee6c2083429a2023a28b2b8f50..ed9aab31e60504ad1fd294c01aa50d808470dd69 100755 (executable)
@@ -101,6 +101,8 @@ import org.opendaylight.protocol.bgp.rib.spi.SimpleRIBExtensionProviderContext;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.NeighborBuilder;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.NeighborKey;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
@@ -109,6 +111,8 @@ import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.re
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.BGP;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1Builder;
 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.RibId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
@@ -274,7 +278,14 @@ public abstract class AbstractRIBImplModuleTest extends AbstractConfigTest {
                 any(InetSocketAddress.class), any(BGPPeerRegistry.class), anyInt(), any(Optional.class));
 
         setupMockService(BgpDeployer.class, this.bgpDeployer);
-        doReturn(new ProtocolBuilder().setKey(new ProtocolKey(BGP.class, "bgp")).build()).when(this.bgpMappingService).fromRib(any(), any(), any(), any(), any(), any());
+        final Global global = mock(Global.class);
+        final Bgp globalBgp = mock(Bgp.class);
+        doReturn(global).when(globalBgp).getGlobal();
+        doReturn("global").when(global).toString();
+        doReturn(new ProtocolBuilder().setKey(new ProtocolKey(BGP.class, "bgp"))
+            .addAugmentation(Protocol1.class, new Protocol1Builder().setBgp(globalBgp).build()).build())
+            .when(this.bgpMappingService).fromRib(any(), any(), any(), any(), any(), any());
+        doNothing().when(this.bgpDeployer).onGlobalCreated(any(),any(),any());
         doReturn(NEIGHBOR).when(this.bgpMappingService).fromBgpPeer(any(), any(),
                 any(), any(), any(), any(), any(), any(), any(), any(), any());
         doReturn(this.mockedFuture).when(this.bgpDeployer).writeConfiguration(any(), any());
@@ -327,6 +338,7 @@ public abstract class AbstractRIBImplModuleTest extends AbstractConfigTest {
         doReturn(new ServiceReference[]{mockServiceRef}).when(this.mockedContext).
         getServiceReferences(serviceInterface.getName(), null);
         doReturn(instance).when(this.mockedContext).getService(mockServiceRef);
+        doReturn("test").when(mockServiceRef).toString();
     }
 
     private static SchemaContext parseYangStreams(final Collection<ByteSource> streams) {
index c361768bd95b38af6fa2f485adb21e7aa14d3b92..c11e21dcd83a4cc1d3133312aed5a5ea6714ba75 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.protocol.bgp.rib.impl;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Throwables;
 import com.google.common.util.concurrent.CheckedFuture;
@@ -37,6 +40,9 @@ 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.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.protocol.bgp.inet.RIBActivator;
 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
@@ -97,7 +103,7 @@ public class AbstractRIBTestSetup {
     protected static final TablesKey KEY = new TablesKey(AFI, SAFI);
     private BindingCodecTreeFactory codecFactory;
     private RIBActivator a1;
-    RIBSupport ribSupport;
+    private RIBSupport ribSupport;
     protected static final QName PREFIX_QNAME = QName.create(Ipv4Route.QNAME, "prefix").intern();
 
     @Mock
@@ -127,6 +133,9 @@ public class AbstractRIBTestSetup {
     @Mock
     private DOMDataTreeChangeService service;
 
+    @Mock
+    private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+
     @Before
     public void setUp() throws Exception {
         mockRib();
@@ -143,10 +152,11 @@ public class AbstractRIBTestSetup {
         this.a1 = new RIBActivator();
         this.a1.startRIBExtensionProvider(context);
         mockedMethods();
-        this.rib = new RIBImpl(new RibId("test"), new AsNumber(5L), this.RIB_ID,
-            this.CLUSTER_ID, context, this.dispatcher, this.codecFactory, this.dom,
-                localTables, Collections.singletonMap(new TablesKey(AFI, SAFI), BasePathSelectionModeFactory.createBestPathSelectionStrategy()),
-                GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy());
+        doReturn(Mockito.mock(ClusterSingletonServiceRegistration.class)).when(this.clusterSingletonServiceProvider)
+            .registerClusterSingletonService(any(ClusterSingletonService.class));
+        this.rib = new RIBImpl(this.clusterSingletonServiceProvider, new RibId("test"), new AsNumber(5L), RIB_ID, CLUSTER_ID, context,
+            this.dispatcher, this.codecFactory, this.dom, localTables, Collections.singletonMap(new TablesKey(AFI, SAFI),
+            BasePathSelectionModeFactory.createBestPathSelectionStrategy()), GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), null);
         this.rib.onGlobalContextUpdated(schemaContext);
         this.ribSupport = getRib().getRibSupportContext().getRIBSupportContext(KEY).getRibSupport();
     }
index 7e31705c5fcfaa8702aee1b5cab3230fbe38632c..1fa62a242fc664ce7c298ac7143b4c6108e6b1a2 100755 (executable)
@@ -9,6 +9,8 @@ package org.opendaylight.protocol.bgp.rib.impl;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Throwables;
@@ -24,6 +26,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -33,6 +36,9 @@ import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
 import org.opendaylight.controller.md.sal.binding.test.DataBrokerTestCustomizer;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
 import org.opendaylight.protocol.bgp.inet.RIBActivator;
 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
@@ -71,20 +77,25 @@ import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 public class ParserToSalTest extends AbstractDataBrokerTest {
 
     private static final String TEST_RIB_ID = "testRib";
-
-    private final String hex_messages = "/bgp_hex.txt";
-
     private BGPMock mock;
     private AbstractRIBExtensionProviderActivator baseact, lsact;
     private RIBExtensionProviderContext ext1, ext2;
-
+    private static final TablesKey TABLE_KEY = new TablesKey(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class);
     @Mock
     BGPDispatcher dispatcher;
-
-    BindingCodecTreeFactory codecFactory;
+    @Mock
+    private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+    private BindingCodecTreeFactory codecFactory;
 
     private SchemaService schemaService;
 
+    @Before
+    public void setUp() throws Exception {
+        super.setup();
+        doReturn(Mockito.mock(ClusterSingletonServiceRegistration.class)).when(this.clusterSingletonServiceProvider).
+            registerClusterSingletonService(any(ClusterSingletonService.class));
+    }
+
     @Override
     protected java.lang.Iterable<org.opendaylight.yangtools.yang.binding.YangModuleInfo> getModuleInfos() throws Exception {
         return ImmutableList.of(BindingReflections.getModuleInfo(Ipv4Route.class), BindingReflections.getModuleInfo(Ipv6Route.class), BindingReflections.getModuleInfo(LinkstateRoute.class));
@@ -103,7 +114,8 @@ public class ParserToSalTest extends AbstractDataBrokerTest {
         MockitoAnnotations.initMocks(this);
         final List<byte[]> bgpMessages;
         try {
-            bgpMessages = HexDumpBGPFileParser.parseMessages(ParserToSalTest.class.getResourceAsStream(this.hex_messages));
+            final String hexMessages = "/bgp_hex.txt";
+            bgpMessages = HexDumpBGPFileParser.parseMessages(ParserToSalTest.class.getResourceAsStream(hexMessages));
         } catch (final IOException e) {
             throw Throwables.propagate(e);
         }
@@ -130,11 +142,11 @@ public class ParserToSalTest extends AbstractDataBrokerTest {
     @Test
     public void testWithLinkstate() throws InterruptedException, ExecutionException {
         final List<BgpTableType> tables = ImmutableList.of(
-                (BgpTableType) new BgpTableTypeImpl(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class));
-        final RIBImpl rib = new RIBImpl(new RibId(TEST_RIB_ID), new AsNumber(72L), new BgpId("127.0.0.1"), null, this.ext2, this.dispatcher,
-                this.codecFactory, getDomBroker(), tables,
-                Collections.singletonMap(new TablesKey(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class),
-                        BasePathSelectionModeFactory.createBestPathSelectionStrategy()), GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy());
+                new BgpTableTypeImpl(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class));
+        final RIBImpl rib = new RIBImpl(this.clusterSingletonServiceProvider, new RibId(TEST_RIB_ID), new AsNumber(72L), new BgpId("127.0.0.1"),
+            null, this.ext2, this.dispatcher, this.codecFactory, getDomBroker(), tables, Collections.singletonMap(TABLE_KEY,
+            BasePathSelectionModeFactory.createBestPathSelectionStrategy()), GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), null);
+        rib.instantiateServiceInstance();
         assertTablesExists(tables, true);
         rib.onGlobalContextUpdated(this.schemaService.getGlobalContext());
         final BGPPeer peer = new BGPPeer("peer-" + this.mock.toString(), rib, PeerRole.Ibgp, null);
@@ -145,11 +157,11 @@ public class ParserToSalTest extends AbstractDataBrokerTest {
 
     @Test
     public void testWithoutLinkstate() throws InterruptedException, ExecutionException {
-        final List<BgpTableType> tables = ImmutableList.of((BgpTableType) new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class));
-        final RIBImpl rib = new RIBImpl(new RibId(TEST_RIB_ID), new AsNumber(72L), new BgpId("127.0.0.1"), null, this.ext1, this.dispatcher,
-                this.codecFactory, getDomBroker(), tables,
-                Collections.singletonMap(new TablesKey(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class),
-                        BasePathSelectionModeFactory.createBestPathSelectionStrategy()), GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy());
+        final List<BgpTableType> tables = ImmutableList.of(new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class));
+        final RIBImpl rib = new RIBImpl(this.clusterSingletonServiceProvider, new RibId(TEST_RIB_ID), new AsNumber(72L), new BgpId("127.0.0.1"), null,
+            this.ext1, this.dispatcher, this.codecFactory, getDomBroker(), tables, Collections.singletonMap(TABLE_KEY,
+            BasePathSelectionModeFactory.createBestPathSelectionStrategy()), GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), null);
+        rib.instantiateServiceInstance();
         rib.onGlobalContextUpdated(this.schemaService.getGlobalContext());
         assertTablesExists(tables, true);
         final BGPPeer peer = new BGPPeer("peer-" + this.mock.toString(), rib, PeerRole.Ibgp, null);
@@ -163,9 +175,7 @@ public class ParserToSalTest extends AbstractDataBrokerTest {
             final byte[] ret = new byte[input.length + 1];
             // ff
             ret[0] = -1;
-            for (int i = 0; i < input.length; i++) {
-                ret[i + 1] = input[i];
-            }
+            System.arraycopy(input, 0, ret, 1, input.length);
             return ret;
         });
     }