Cluster aware forwarding rule manager 59/32459/2
authorAnil Vishnoi <vishnoianil@gmail.com>
Wed, 13 Jan 2016 02:14:55 +0000 (18:14 -0800)
committerAnil Vishnoi <vishnoianil@gmail.com>
Wed, 13 Jan 2016 02:19:29 +0000 (18:19 -0800)
Forwarding rule manager can fail in 3-node cluster
if actionNodes cache is not populated properly
during the shard leader change. This patch
properly populates the internal activeNodes cache

Change-Id: I74c11d92b6d9cef6f001422dcb624ccdc61fd68b
Signed-off-by: Anil Vishnoi <vishnoianil@gmail.com>
applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/ForwardingRulesManager.java
applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/AbstractListeningCommiter.java
applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/ForwardingRulesManagerImpl.java

index f6255d9b941692e3d62704474a6f5503b8eedd32..81cc3f5b60da96684af320982a5d39ae159b0227 100644 (file)
@@ -48,6 +48,15 @@ public interface ForwardingRulesManager extends AutoCloseable {
      */
     public boolean isNodeActive(InstanceIdentifier<FlowCapableNode> ident);
 
+    /**
+     * Method returns information :
+     * "is Node with send InstanceIdentifier present in operational data store"?
+     *
+     * @param ident - the key of the node
+     * @return boolean - true if device is present in operational data store
+     */
+    public boolean checkNodeInOperationalDataStore(InstanceIdentifier<FlowCapableNode> ident);
+
     /**
      * Method add new {@link FlowCapableNode} to active Node Holder.
      * ActiveNodeHolder prevent unnecessary Operational/DS read for identify
index 76dd2ed8e9da09ee5f29d882a7b3d190321797e6..3cc3bed6e79be1e387918a58f4e7ac9ac513d46b 100644 (file)
@@ -99,7 +99,25 @@ public abstract class AbstractListeningCommiter <T extends DataObject> implement
 
     private boolean preConfigurationCheck(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
         Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!");
-        return provider.isNodeActive(nodeIdent);
+        // In single node cluster, node should be in local cache before we get any flow/group/meter
+        // data change event from data store. So first check should pass.
+        // In case of 3-node cluster, when shard leader changes, clustering will send blob of data
+        // present in operational data store and config data store. So ideally local node cache
+        // should get populated. But to handle a scenario where flow request comes before the blob
+        // of config/operational data gets processes, it won't find node in local cache and it will
+        // skip the flow/group/meter operational. This requires an addition check, where it reads
+        // node from operational data store and if it's present it calls flowNodeConnected to explictly
+        // trigger the event of new node connected.
+
+        if (!provider.isNodeActive(nodeIdent)) {
+            if (provider.checkNodeInOperationalDataStore(nodeIdent)) {
+                provider.getFlowNodeReconciliation().flowNodeConnected(nodeIdent);
+                return true;
+            } else {
+                return false;
+            }
+        }
+        return true;
     }
 }
 
index 619ddada02cf0f9397ef6b861525943f68308c34..0d83de55baf18be8c0049b39b3b9bdb8b217f22d 100644 (file)
@@ -8,13 +8,18 @@
 
 package org.opendaylight.openflowplugin.applications.frm.impl;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
 import java.util.Collections;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
+
+import com.google.common.util.concurrent.CheckedFuture;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.openflowplugin.applications.frm.FlowNodeReconciliation;
 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesCommiter;
@@ -25,6 +30,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService;
@@ -138,6 +144,29 @@ public class ForwardingRulesManagerImpl implements ForwardingRulesManager {
         return activeNodes.contains(ident);
     }
 
+    @Override
+    public boolean checkNodeInOperationalDataStore(InstanceIdentifier<FlowCapableNode> ident) {
+        boolean result = false;
+        InstanceIdentifier<Node> nodeIid = ident.firstIdentifierOf(Node.class);
+        final ReadOnlyTransaction transaction = dataService.newReadOnlyTransaction();
+        Optional<Node> optionalDataObject;
+        CheckedFuture<Optional<Node>, ReadFailedException> future = transaction.read(LogicalDatastoreType.OPERATIONAL, nodeIid);
+        try {
+            optionalDataObject = future.checkedGet();
+            if (optionalDataObject.isPresent()) {
+                result = true;
+            } else {
+                LOG.debug("{}: Failed to read {}",
+                        Thread.currentThread().getStackTrace()[1], nodeIid);
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read {} ", nodeIid, e);
+        }
+        transaction.close();
+
+        return result;
+    }
+
     @Override
     public void registrateNewNode(InstanceIdentifier<FlowCapableNode> ident) {
         if (!activeNodes.contains(ident)) {