From: Anil Vishnoi Date: Wed, 13 Jan 2016 02:14:55 +0000 (-0800) Subject: Cluster aware forwarding rule manager X-Git-Tag: release/beryllium~25^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=7c4fe4fe96197adf2c4b8b29e9546366c0a50527;p=openflowplugin.git Cluster aware forwarding rule manager 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 --- diff --git a/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/ForwardingRulesManager.java b/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/ForwardingRulesManager.java index f6255d9b94..81cc3f5b60 100644 --- a/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/ForwardingRulesManager.java +++ b/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/ForwardingRulesManager.java @@ -48,6 +48,15 @@ public interface ForwardingRulesManager extends AutoCloseable { */ public boolean isNodeActive(InstanceIdentifier 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 ident); + /** * Method add new {@link FlowCapableNode} to active Node Holder. * ActiveNodeHolder prevent unnecessary Operational/DS read for identify diff --git a/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/AbstractListeningCommiter.java b/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/AbstractListeningCommiter.java index 76dd2ed8e9..3cc3bed6e7 100644 --- a/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/AbstractListeningCommiter.java +++ b/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/AbstractListeningCommiter.java @@ -99,7 +99,25 @@ public abstract class AbstractListeningCommiter implement private boolean preConfigurationCheck(final InstanceIdentifier 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; } } diff --git a/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/ForwardingRulesManagerImpl.java b/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/ForwardingRulesManagerImpl.java index 619ddada02..0d83de55ba 100644 --- a/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/ForwardingRulesManagerImpl.java +++ b/applications/forwardingrules-manager/src/main/java/org/opendaylight/openflowplugin/applications/frm/impl/ForwardingRulesManagerImpl.java @@ -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 ident) { + boolean result = false; + InstanceIdentifier nodeIid = ident.firstIdentifierOf(Node.class); + final ReadOnlyTransaction transaction = dataService.newReadOnlyTransaction(); + Optional optionalDataObject; + CheckedFuture, 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 ident) { if (!activeNodes.contains(ident)) {