From bacac89e890e21e1a4a8a18538738a3c96536ebc Mon Sep 17 00:00:00 2001
From: Gregor Maier <gregor.maier@bigswitch.com>
Date: Fri, 23 Mar 2012 20:05:51 -0700
Subject: [PATCH] Attachment point move suppresion when moving from
 non-broadcast domain port to broadcast domain port wasn't working. Fixed.

---
 .../internal/DeviceManagerImpl.java           | 54 +++++++++++++------
 .../internal/DeviceManagerImplTest.java       | 12 +++++
 2 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 9219206b1..434347a5f 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -812,6 +812,14 @@ public class DeviceManagerImpl implements IDeviceManagerService, IOFMessageListe
         match.loadFromPacket(pi.getPacketData(), pi.getInPort(), sw.getId());
         // Add this packet-in to event history
         evHistPktIn(match);
+        if (log.isTraceEnabled())
+            log.trace("Entering packet_in processing sw {}, port {}. {} --> {}, type {}",
+                      new Object[] { sw.getStringId(), pi.getInPort(), 
+                               HexString.toHexString(match.getDataLayerSource()),
+                               HexString.toHexString(match.getDataLayerDestination()),
+                               match.getDataLayerType()
+                      });
+                      
 
         // Create attachment point/update network address if required
         SwitchPortTuple switchPort = new SwitchPortTuple(sw, pi.getInPort());
@@ -835,6 +843,13 @@ public class DeviceManagerImpl implements IDeviceManagerService, IOFMessageListe
                                 cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
         int nwSrc = getSrcNwAddr(eth, dlAddr);
         Device device = devMgrMaps.getDeviceByDataLayerAddr(dlAddr);
+        if (log.isTraceEnabled()) {
+            long dstAddr = Ethernet.toLong(match.getDataLayerDestination());
+            Device dstDev = devMgrMaps.getDeviceByDataLayerAddr(dstAddr);
+            log.trace("    Src.AttachmentPts: {}", device.getAttachmentPointsMap().keySet());
+            if (dstDev != null)
+	            log.trace("    Dst.AttachmentPts: {}", dstDev.getAttachmentPointsMap().keySet());
+        }
         Date currentDate = new Date(); 
         if (device != null) { 
             // Write lock is expensive, check if we have an update first
@@ -853,37 +868,44 @@ public class DeviceManagerImpl implements IDeviceManagerService, IOFMessageListe
             // Copy-replace of device would be too expensive here
             device.setLastSeen(currentDate);
             updateDevice = device.shouldWriteLastSeenToStorage();
-            attachmentPoint = device.getAttachmentPoint(switchPort);
 
             // If the attachment point moves from a non-broadcast domain
             // port to a broadcast domain port too quickly, ignore learning
             // the broadcast domain attachment point.
-            if (attachmentPoint != null) {
+            for ( DeviceAttachmentPoint oldDap : device.getAttachmentPoints() ) {
                 // if the two switches are in the same cluster
                 // and if currSw,CurrPort is not in broadcast domain
-                long currSw = attachmentPoint.getSwitchPort().getSw().getId();
-                short currPort = attachmentPoint.getSwitchPort().getPort();
+                long currSw = oldDap.getSwitchPort().getSw().getId();
+                short currPort = oldDap.getSwitchPort().getPort();
                 long newSw = switchPort.getSw().getId();
                 short newPort = switchPort.getPort();
-                if (topology.getSwitchClusterId(currSw) == topology.getSwitchClusterId(newSw)) {
-                    if (topology.isBroadcastDomainPort(currSw, currPort) == false) {
-                        if (topology.isBroadcastDomainPort(newSw, newPort) == true) {
-                            // only if the last seen
-                            if (currentDate.getTime() -
-                                    attachmentPoint.getLastSeen().getTime() < 300000) {
-                                // if the packet was seen within the last 5 minutes, we should ignore.
-                                // it should also ignore processing the packet.
-                                return Command.STOP;
-                            }
+                if ( (topology.getSwitchClusterId(currSw) == topology.getSwitchClusterId(newSw)) &&
+                        (topology.isBroadcastDomainPort(currSw, currPort) == false) &&
+                        (topology.isBroadcastDomainPort(newSw, newPort) == true)) {
+                    long dt = currentDate.getTime() -
+                            oldDap.getLastSeen().getTime() ;
+                    if (dt < 300000) {
+                        // if the packet was seen within the last 5 minutes, we should ignore.
+                        // it should also ignore processing the packet.
+                        if (log.isTraceEnabled()) {
+                            log.trace("Surpressing too quick move of {} from non broadcast domain port {} {}" +
+                                    " to broadcast domain port {} {}. Last seen on non-BD {} sec ago",
+                                    new Object[] { HexString.toHexString(match.getDataLayerSource()),
+                                                   oldDap.getSwitchPort().getSw().getStringId(), currPort,
+                                                   switchPort.getSw().getStringId(), newPort,
+                                                   dt/1000 }
+                                    );
                         }
+                        return Command.STOP;
                     }
                 }
             }
-
+            
             if (isGratArp(eth)) {
                 clearAttachmentPoints = true;
             }
 
+            attachmentPoint = device.getAttachmentPoint(switchPort);
             if (attachmentPoint != null) {
                 updateAttachmentPointLastSeen = true;
             } else {
@@ -1019,6 +1041,8 @@ public class DeviceManagerImpl implements IDeviceManagerService, IOFMessageListe
             }
 
         } else { // device is null 
+            if (log.isTraceEnabled())
+                log.trace("   new device");
             handleNewDevice(match.getDataLayerSource(), currentDate,
                     switchPort, nwSrc, vlan);
         }
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index 19f5e8b2f..e9af403a8 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -444,6 +444,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                            .andReturn(false).atLeastOnce();
         expect(mockTopology.isInternal(1L, (short)2))
                            .andReturn(false).atLeastOnce();
+        expect(mockTopology.getSwitchClusterId(1L))
+                           .andReturn(1L).atLeastOnce();
+        expect(mockTopology.isBroadcastDomainPort(1L, (short)1))
+                           .andReturn(false).atLeastOnce();
+        expect(mockTopology.isBroadcastDomainPort(1L, (short)2))
+                           .andReturn(false).atLeastOnce();
         deviceManager.setTopology(mockTopology);
 
         // Start recording the replay on the mocks
@@ -532,6 +538,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                            .andReturn(false).atLeastOnce();
         expect(mockTopology.isInternal(1L, (short)2))
                            .andReturn(false).atLeastOnce();
+        expect(mockTopology.getSwitchClusterId(1L))
+                           .andReturn(1L).atLeastOnce();
+        expect(mockTopology.isBroadcastDomainPort(1L, (short)1))
+                           .andReturn(false).atLeastOnce();
+        expect(mockTopology.isBroadcastDomainPort(1L, (short)2))
+                           .andReturn(false).atLeastOnce();
         deviceManager.setTopology(mockTopology);
 
         // Start recording the replay on the mocks
-- 
GitLab