Bug-1421 - MD-SAL app cannot create a flow entry which adds a VLAN tag with the speci...
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / HandshakeManagerImpl.java
index e7e0a98eff9da18ec28012c2ed85ca3340ea62ab..db88573e8209fb0a7f6ff959aa0054771aa823d3 100644 (file)
@@ -10,8 +10,10 @@ package org.opendaylight.openflowplugin.openflow.md.core;
 import java.util.List;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
+import org.opendaylight.openflowplugin.ConnectionException;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloInput;
@@ -40,7 +42,7 @@ public class HandshakeManagerImpl implements HandshakeManager {
     private Short version;
     private ErrorHandler errorHandler;
     
-    private long maxTimeout = 1000;
+    private long maxTimeout = 8000;
     private TimeUnit maxTimeoutUnit = TimeUnit.MILLISECONDS;
     private Short highestVersion;
 
@@ -73,28 +75,37 @@ public class HandshakeManagerImpl implements HandshakeManager {
     }
 
     @Override
-    public synchronized void run() {
-        LOG.info("handshake STARTED");
-        setActiveXid(20L);
-        HelloMessage receivedHelloLoc = receivedHello;
-        
-        if (receivedHelloLoc == null) {
-            // first Hello sending
-            sendHelloMessage(highestVersion, getNextXid());
-            lastProposedVersion = highestVersion;
-            LOG.debug("ret - firstHello+wait");
+    public void shake() {
+
+        if (version != null) {
+            // Some switches respond with a second HELLO acknowledging our HELLO
+            // but we've already completed the handshake based on the negotiated
+            // version and have registered this switch.
+            LOG.debug("Hello recieved after handshake already settled ... ignoring.");
             return;
         }
-        
-        // process the 2. and later hellos
-        Short remoteVersion = receivedHelloLoc.getVersion();
-        List<Elements> elements = receivedHelloLoc.getElements();
-        setActiveXid(receivedHelloLoc.getXid());
-        List<Boolean> remoteVersionBitmap = MessageFactory.digVersions(elements);
-        LOG.debug("Hello message: version={}, bitmap={}, xid={}", remoteVersion, 
-                remoteVersionBitmap, receivedHelloLoc.getXid());
+
+        LOG.trace("handshake STARTED");
+        setActiveXid(20L);
+        HelloMessage receivedHelloLoc = receivedHello;
         
         try {
+            if (receivedHelloLoc == null) {
+                // first Hello sending
+                sendHelloMessage(highestVersion, getNextXid());
+                lastProposedVersion = highestVersion;
+                LOG.trace("ret - firstHello+wait");
+                return;
+            }
+
+            // process the 2. and later hellos
+            Short remoteVersion = receivedHelloLoc.getVersion();
+            List<Elements> elements = receivedHelloLoc.getElements();
+            setActiveXid(receivedHelloLoc.getXid());
+            List<Boolean> remoteVersionBitmap = MessageFactory.digVersions(elements);
+            LOG.debug("Hello message: version={}, bitmap={}, xid={}", remoteVersion, 
+                    remoteVersionBitmap, receivedHelloLoc.getXid());
+        
             if (useVersionBitmap && remoteVersionBitmap != null) {
                 // versionBitmap on both sides -> ONE STEP DECISION
                 handleVersionBitmapNegotiation(elements);
@@ -105,25 +116,34 @@ public class HandshakeManagerImpl implements HandshakeManager {
         } catch (Exception ex) {
             errorHandler.handleException(ex, null);
             connectionAdapter.disconnect();
-            LOG.debug("ret - "+ex.getMessage());
+            LOG.trace("ret - shake fail: {}", ex.getMessage());
         }
     }
 
     /**
      * @param remoteVersion
+     * @throws Exception 
      */
-    private void handleStepByStepVersionNegotiation(Short remoteVersion) {
+    private void handleStepByStepVersionNegotiation(Short remoteVersion) throws Exception {
         LOG.debug("remoteVersion:{} lastProposedVersion:{}, highestVersion:{}", 
                 remoteVersion, lastProposedVersion, highestVersion);
+        
+        if (lastProposedVersion == null) {
+            // first hello has not been sent yet, send it and either wait for next remote 
+            // version or proceed
+            lastProposedVersion = proposeNextVersion(remoteVersion);
+            sendHelloMessage(lastProposedVersion, getNextXid());
+        }
+        
         if (remoteVersion == lastProposedVersion) {
             postHandshake(lastProposedVersion, getNextXid());
-            LOG.debug("ret - OK - switch answered with lastProposedVersion");
+            LOG.trace("ret - OK - switch answered with lastProposedVersion");
         } else {
             checkNegotiationStalling(remoteVersion);
 
             if (remoteVersion > (lastProposedVersion == null ? highestVersion : lastProposedVersion)) {
                 // wait for next version
-                LOG.debug("ret - wait");
+                LOG.trace("ret - wait");
             } else {
                 //propose lower version
                 handleLowerVersionProposal(remoteVersion);
@@ -133,8 +153,9 @@ public class HandshakeManagerImpl implements HandshakeManager {
 
     /**
      * @param remoteVersion
+     * @throws Exception 
      */
-    private void handleLowerVersionProposal(Short remoteVersion) {
+    private void handleLowerVersionProposal(Short remoteVersion) throws Exception {
         Short proposedVersion;
         // find the version from header version field
         proposedVersion = proposeNextVersion(remoteVersion);
@@ -142,21 +163,26 @@ public class HandshakeManagerImpl implements HandshakeManager {
         sendHelloMessage(proposedVersion, getNextXid());
 
         if (proposedVersion != remoteVersion) {
-            LOG.debug("ret - sent+wait");
+            LOG.trace("ret - sent+wait");
         } else {
-            LOG.debug("ret - sent+OK");
+            LOG.trace("ret - sent+OK");
             postHandshake(proposedVersion, getNextXid());
         }
     }
 
     /**
      * @param elements
+     * @throws Exception 
      */
-    private void handleVersionBitmapNegotiation(List<Elements> elements) {
+    private void handleVersionBitmapNegotiation(List<Elements> elements) throws Exception {
         Short proposedVersion;
         proposedVersion = proposeCommonBitmapVersion(elements);
+        if (lastProposedVersion == null) {
+            // first hello has not been sent yet
+            sendHelloMessage(proposedVersion, getNextXid());
+        }
         postHandshake(proposedVersion, getNextXid());
-        LOG.debug("ret - OK - versionBitmap");
+        LOG.trace("ret - OK - versionBitmap");
     }
     
     /**
@@ -182,6 +208,7 @@ public class HandshakeManagerImpl implements HandshakeManager {
         if (lastReceivedVersion != null && lastReceivedVersion.equals(remoteVersion)) {
             throw new IllegalStateException("version negotiation stalled: version = "+remoteVersion);
         }
+        lastReceivedVersion = remoteVersion;
     }
 
     @Override
@@ -246,34 +273,40 @@ public class HandshakeManagerImpl implements HandshakeManager {
      * send hello reply without versionBitmap
      * @param helloVersion
      * @param helloXid
+     * @throws Exception 
      */
-    protected void sendHelloMessage(Short helloVersion, Long helloXid) {
+    private void sendHelloMessage(Short helloVersion, Long helloXid) throws Exception {
         //Short highestVersion = ConnectionConductor.versionOrder.get(0);
         //final Long helloXid = 21L;
         HelloInput helloInput = MessageFactory.createHelloInput(helloVersion, helloXid, versionOrder);
         
-        LOG.debug("sending first hello message: version{}, xid={}, version bitmap={}", 
+        LOG.debug("sending hello message: version{}, xid={}, version bitmap={}", 
                 helloVersion, helloXid, MessageFactory.digVersions(helloInput.getElements()));
         
         try {
             RpcResult<Void> helloResult = connectionAdapter.hello(helloInput).get(maxTimeout, maxTimeoutUnit);
             RpcUtil.smokeRpc(helloResult);
             LOG.debug("FIRST HELLO sent.");
-        } catch (Throwable e) {
-            LOG.debug("FIRST HELLO sending failed.");
-            errorHandler.handleException(e, null);
+        } catch (Exception e) {
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("FIRST HELLO sent.", e);
+            }
+            throw new ConnectionException("FIRST HELLO sending failed because of connection issue.");
         }
     }
 
+
     /**
      * after handshake set features, register to session
      * @param proposedVersion
      * @param xId
+     * @throws Exception 
      */
-    protected void postHandshake(Short proposedVersion, Long xid) {
+    protected void postHandshake(Short proposedVersion, Long xid) throws Exception {
         // set version
         version = proposedVersion;
-        LOG.debug("version set: " + proposedVersion);
+
+        LOG.debug("version set: {}", proposedVersion);
         // request features
         GetFeaturesInputBuilder featuresBuilder = new GetFeaturesInputBuilder();
         featuresBuilder.setVersion(version).setXid(xid);
@@ -292,15 +325,20 @@ public class HandshakeManagerImpl implements HandshakeManager {
                     featureOutput.getDatapathId());
             LOG.debug("obtained features: auxiliaryId={}",
                     featureOutput.getAuxiliaryId());
-            LOG.info("handshake SETTLED: version={}, datapathId={}, auxiliaryId={}", 
+            LOG.trace("handshake SETTLED: version={}, datapathId={}, auxiliaryId={}", 
                     version, featureOutput.getDatapathId(), featureOutput.getAuxiliaryId());
             
             handshakeListener.onHandshakeSuccessfull(featureOutput, proposedVersion);
-        } catch (Throwable e) {
-            //handshake failed
-            LOG.error("issuing disconnect during handshake, reason: "+e.getMessage());
-            errorHandler.handleException(e, null);
+        } catch (TimeoutException e) {
+            // handshake failed
+            LOG.warn("issuing disconnect during handshake, reason: future expired", e);
+            connectionAdapter.disconnect();
+            throw e;
+        } catch (Exception e) {
+            // handshake failed
+            LOG.warn("issuing disconnect during handshake, reason - RPC: {}", e.getMessage(), e);
             connectionAdapter.disconnect();
+            throw e;
         }
         
         LOG.debug("postHandshake DONE");