bug 8671 same client notified multiple times 24/58824/10
authorK.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
Tue, 13 Jun 2017 14:00:31 +0000 (19:30 +0530)
committerSam Hague <shague@redhat.com>
Fri, 16 Feb 2018 02:46:10 +0000 (02:46 +0000)
only leader node will initialize topology
each node listens for topology creation/add event
once it receives the add event opens the ovsdb port to clients
Now we are absolutely sure that topology node can be created for the
new incoming connections.

when a new node joins/leaves the cluster , the leader node
will reinit the topology which is a no op event

Change-Id: I45c319195f593d8bd99b19f07f5568492cf9077f
Signed-off-by: K.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundProvider.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundProvider.java

index 451c61b6bcac9a3d8d5425a3d70fbf3ded970253..ad1cf20969a488889aa66f8ce8e4f671663f7268 100644 (file)
@@ -7,7 +7,16 @@
  */
 package org.opendaylight.ovsdb.hwvtepsouthbound;
 
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+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.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.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
@@ -29,14 +38,12 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-
-public class HwvtepSouthboundProvider implements AutoCloseable {
+public class HwvtepSouthboundProvider implements ClusteredDataTreeChangeListener<Topology>, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
     private static final String ENTITY_TYPE = "ovsdb-hwvtepsouthbound-provider";
@@ -55,6 +62,8 @@ public class HwvtepSouthboundProvider implements AutoCloseable {
     private HwvtepsbPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
     private HwvtepDataChangeListener hwvtepDTListener;
     private HwvtepReconciliationManager hwvtepReconciliationManager;
+    private AtomicBoolean registered = new AtomicBoolean(false);
+    private ListenerRegistration<HwvtepSouthboundProvider> operTopologyRegistration;
 
     public HwvtepSouthboundProvider(final DataBroker dataBroker,
             final EntityOwnershipService entityOwnershipServiceDependency,
@@ -88,17 +97,18 @@ public class HwvtepSouthboundProvider implements AutoCloseable {
         try {
             Optional<EntityOwnershipState> ownershipStateOpt = entityOwnershipService.getOwnershipState(instanceEntity);
             registration = entityOwnershipService.registerCandidate(instanceEntity);
-            if (ownershipStateOpt.isPresent()) {
-                EntityOwnershipState ownershipState = ownershipStateOpt.get();
-                if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
-                    ovsdbConnection.registerConnectionListener(cm);
-                    ovsdbConnection.startOvsdbManager();
-                }
-            }
         } catch (CandidateAlreadyRegisteredException e) {
             LOG.warn("HWVTEP Southbound Provider instance entity {} was already "
                     + "registered for ownership", instanceEntity, e);
         }
+        InstanceIdentifier<Topology> path = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
+        DataTreeIdentifier<Topology> treeId =
+                new DataTreeIdentifier<Topology>(LogicalDatastoreType.OPERATIONAL, path);
+
+        LOG.trace("Registering listener for path {}", treeId);
+        operTopologyRegistration = db.registerDataTreeChangeListener(treeId, this);
     }
 
     @Override
@@ -128,6 +138,10 @@ public class HwvtepSouthboundProvider implements AutoCloseable {
             hwvtepDTListener.close();
             hwvtepDTListener = null;
         }
+        if (operTopologyRegistration != null) {
+            operTopologyRegistration.close();
+            operTopologyRegistration = null;
+        }
     }
 
     private void initializeHwvtepTopology(LogicalDatastoreType type) {
@@ -160,8 +174,23 @@ public class HwvtepSouthboundProvider implements AutoCloseable {
         } else {
             LOG.info("*This* instance of HWVTEP southbound provider is set as a SLAVE instance");
         }
-        ovsdbConnection.registerConnectionListener(cm);
-        ovsdbConnection.startOvsdbManager();
+    }
+
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<Topology>> collection) {
+        if (!registered.getAndSet(true)) {
+            LOG.info("Starting the ovsdb port");
+            ovsdbConnection.registerConnectionListener(cm);
+            ovsdbConnection.startOvsdbManager();
+        }
+        //mdsal registration/deregistration in mdsal update callback should be avoided
+        new Thread(() -> {
+            if (operTopologyRegistration != null) {
+                operTopologyRegistration.close();
+                operTopologyRegistration = null;
+            }
+        }).start();
     }
 
     private class HwvtepsbPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {
index da4ba82edafee6c0985f6db478d2d07bbdc4aebd..cd712e2924023ba770cae37eb1bb4aa388f2b24e 100644 (file)
@@ -9,9 +9,16 @@ package org.opendaylight.ovsdb.southbound;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
+
+import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+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.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.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
@@ -32,11 +39,12 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class SouthboundProvider implements AutoCloseable {
+public class SouthboundProvider implements ClusteredDataTreeChangeListener<Topology>, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(SouthboundProvider.class);
     private static final String ENTITY_TYPE = "ovsdb-southbound-provider";
@@ -55,6 +63,8 @@ public class SouthboundProvider implements AutoCloseable {
     private final OvsdbConnection ovsdbConnection;
     private final InstanceIdentifierCodec instanceIdentifierCodec;
     private static final String SKIP_MONITORING_MANAGER_STATUS_PARAM = "skip-monitoring-manager-status";
+    private AtomicBoolean registered = new AtomicBoolean(false);
+    private ListenerRegistration<SouthboundProvider> operTopologyRegistration;
 
     public SouthboundProvider(final DataBroker dataBroker,
             final EntityOwnershipService entityOwnershipServiceDependency,
@@ -89,18 +99,18 @@ public class SouthboundProvider implements AutoCloseable {
         try {
             Optional<EntityOwnershipState> ownershipStateOpt = entityOwnershipService.getOwnershipState(instanceEntity);
             registration = entityOwnershipService.registerCandidate(instanceEntity);
-            if (ownershipStateOpt.isPresent()) {
-                EntityOwnershipState ownershipState = ownershipStateOpt.get();
-                if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
-                    ovsdbConnection.registerConnectionListener(cm);
-                    ovsdbConnection.startOvsdbManager();
-                    LOG.info("*This* instance of OVSDB southbound provider is set as a SLAVE instance");
-                }
-            }
         } catch (CandidateAlreadyRegisteredException e) {
             LOG.warn("OVSDB Southbound Provider instance entity {} was already "
                     + "registered for ownership", instanceEntity, e);
         }
+        InstanceIdentifier<Topology> path = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID));
+        DataTreeIdentifier<Topology> treeId =
+                new DataTreeIdentifier<Topology>(LogicalDatastoreType.OPERATIONAL, path);
+
+        LOG.trace("Registering listener for path {}", treeId);
+        operTopologyRegistration = db.registerDataTreeChangeListener(treeId, this);
     }
 
     @Override
@@ -115,6 +125,10 @@ public class SouthboundProvider implements AutoCloseable {
         ovsdbDataTreeChangeListener.close();
         registration.close();
         providerOwnershipChangeListener.close();
+        if (operTopologyRegistration != null) {
+            operTopologyRegistration.close();
+            operTopologyRegistration = null;
+        }
     }
 
     private void initializeOvsdbTopology(LogicalDatastoreType type) {
@@ -147,8 +161,22 @@ public class SouthboundProvider implements AutoCloseable {
         } else {
             LOG.info("*This* instance of OVSDB southbound provider is set as a SLAVE instance");
         }
-        ovsdbConnection.registerConnectionListener(cm);
-        ovsdbConnection.startOvsdbManager();
+    }
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<Topology>> collection) {
+        if (!registered.getAndSet(true)) {
+            LOG.info("Starting the ovsdb port");
+            ovsdbConnection.registerConnectionListener(cm);
+            ovsdbConnection.startOvsdbManager();
+            //mdsal registration/deregistration in mdsal update callback should be avoided
+            new Thread(() -> {
+                if (operTopologyRegistration != null) {
+                    operTopologyRegistration.close();
+                    operTopologyRegistration = null;
+                }
+            }).start();
+        }
     }
 
     private class SouthboundPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {