From 8f8e4e50c170808d3c476015c77031c19145abfd Mon Sep 17 00:00:00 2001 From: Gregor Maier <gregor.maier@bigswitch.com> Date: Mon, 9 Jul 2012 13:27:35 -0700 Subject: [PATCH] Fix DeviceManager bug: Device.getIPv4Addresses() * Fixed couple of bugs in Device.getIPv4Addresses(). * Add more debugging output to DeviceManagerImpl --- .../devicemanager/internal/Device.java | 13 +-- .../internal/DeviceManagerImpl.java | 12 ++- .../internal/DeviceManagerImplTest.java | 95 +++++++++++++++++++ 3 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java index 349bd1f42..b0b33794f 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java @@ -27,7 +27,6 @@ import java.util.TreeSet; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.openflow.util.HexString; - import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; import net.floodlightcontroller.devicemanager.web.DeviceSerializer; import net.floodlightcontroller.devicemanager.IDevice; @@ -163,14 +162,6 @@ public class Device implements IDevice { // XXX - TODO we can cache this result. Let's find out if this // is really a performance bottleneck first though. - if (entities.length == 1) { - if (entities[0].getIpv4Address() != null) { - return new Integer[]{ entities[0].getIpv4Address() }; - } else { - return new Integer[0]; - } - } - TreeSet<Integer> vals = new TreeSet<Integer>(); for (Entity e : entities) { if (e.getIpv4Address() == null) continue; @@ -182,6 +173,8 @@ public class Device implements IDevice { deviceManager.queryClassByEntity(entityClass, ipv4Fields, e); while (devices.hasNext()) { Device d = devices.next(); + if (deviceKey.equals(d.getDeviceKey())) + continue; for (Entity se : d.entities) { if (se.getIpv4Address() != null && se.getIpv4Address().equals(e.getIpv4Address()) && @@ -195,8 +188,6 @@ public class Device implements IDevice { if (!validIP) break; } - if (!validIP) - break; if (validIP) vals.add(e.getIpv4Address()); diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java index ca36f1f86..bd1b07ace 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java @@ -340,9 +340,11 @@ IFlowReconcileListener, IInfoProvider, IHAListener { ipv4Address = null; Entity e = new Entity(macAddress, vlan, ipv4Address, null, null, null); - if (!allKeyFieldsPresent(e, source.getEntityClass().getKeyFields())) { - throw new IllegalArgumentException("Not all key fields specified." - + " Required fields: " + entityClassifier.getKeyFields()); + if (!allKeyFieldsPresent(e, source.getEntityClass().getKeyFields()) || + source == null) { + throw new IllegalArgumentException("Not all key fields and/or " + + " no source device specified. Required fields: " + + entityClassifier.getKeyFields()); } return findDestByEntity(source, e); } @@ -993,6 +995,10 @@ IFlowReconcileListener, IInfoProvider, IHAListener { deviceKey = Long.valueOf(deviceKeyCounter++); } device = allocateDevice(deviceKey, entity, entityClass); + if (logger.isDebugEnabled()) { + logger.debug("New device created: {} deviceKey={}", + device, deviceKey); + } // Add the new device to the primary map with a simple put deviceMap.put(deviceKey, device); diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java index 3119bd611..2a45a1882 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java @@ -17,6 +17,7 @@ package net.floodlightcontroller.devicemanager.internal; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.EnumSet; @@ -304,6 +305,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Device d2 = deviceManager.learnDeviceByEntity(entity2); assertFalse(d1.equals(d2)); assertNotSame(d1, d2); + assertNotSame(d1.getDeviceKey(), d2.getDeviceKey()); assertEquals(MockEntityClassifier.testEC, d2.entityClass); assertArrayEquals(new Short[] { -1 }, d2.getVlanId()); assertArrayEquals(new Integer[] { }, d2.getIPv4Addresses()); @@ -317,6 +319,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Device d3 = deviceManager.learnDeviceByEntity(entity3); assertNotSame(d2, d3); + assertEquals(d2.getDeviceKey(), d3.getDeviceKey()); assertEquals(MockEntityClassifier.testEC, d3.entityClass); assertArrayEquals(new Integer[] { 1 }, d3.getIPv4Addresses()); @@ -336,6 +339,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Device d4 = deviceManager.learnDeviceByEntity(entity4); assertNotSame(d1, d4); + assertEquals(d1.getDeviceKey(), d4.getDeviceKey()); assertEquals(DefaultEntityClassifier.entityClass, d4.entityClass); assertArrayEquals(new Integer[] { 1 }, d4.getIPv4Addresses()); @@ -378,6 +382,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { replay(mockListener); Device d7 = deviceManager.learnDeviceByEntity(entity7); + assertNotSame(d6, d7); + assertEquals(d6.getDeviceKey(), d7.getDeviceKey()); assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) }, d7.getAttachmentPoints()); assertArrayEquals(new Short[] { (short) 4 }, @@ -1254,4 +1260,93 @@ public class DeviceManagerImplTest extends FloodlightTestCase { (short) -1, 0)); } + + @Test + public void testGetIPv4Addresses() { + // Looks like Date is only 1s granularity + + Entity e1 = new Entity(1L, (short)1, null, null, null, new Date(2000)); + Device d1 = deviceManager.learnDeviceByEntity(e1); + assertArrayEquals(new Integer[0], d1.getIPv4Addresses()); + + + Entity e2 = new Entity(2L, (short)2, 2, null, null, new Date(2000)); + Device d2 = deviceManager.learnDeviceByEntity(e2); + d2 = deviceManager.learnDeviceByEntity(e2); + assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); + // More than one entity + Entity e2b = new Entity(2L, (short)2, null, 2L, 2, new Date(3000)); + d2 = deviceManager.learnDeviceByEntity(e2b); + assertEquals(2, d2.entities.length); + assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); + // and now add an entity with an IP + Entity e2c = new Entity(2L, (short)2, 2, 2L, 3, new Date(3000)); + d2 = deviceManager.learnDeviceByEntity(e2c); + assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); + assertEquals(3, d2.entities.length); + + // Other devices with different IPs shouldn't interfere + Entity e3 = new Entity(3L, (short)3, 3, null, null, new Date(4000)); + Entity e3b = new Entity(3L, (short)3, 3, 3L, 3, new Date(4400)); + Device d3 = deviceManager.learnDeviceByEntity(e3); + d3 = deviceManager.learnDeviceByEntity(e3b); + assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); + assertArrayEquals(new Integer[] { 3 }, d3.getIPv4Addresses()); + + // Add another IP to d3 + Entity e3c = new Entity(3L, (short)3, 33, 3L, 3, new Date(4400)); + d3 = deviceManager.learnDeviceByEntity(e3c); + Integer[] ips = d3.getIPv4Addresses(); + Arrays.sort(ips); + assertArrayEquals(new Integer[] { 3, 33 }, ips); + + // Add another device that also claims IP2 but is older than e2 + Entity e4 = new Entity(4L, (short)4, 2, null, null, new Date(1000)); + Entity e4b = new Entity(4L, (short)4, null, 4L, 4, new Date(1000)); + Device d4 = deviceManager.learnDeviceByEntity(e4); + assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); + assertArrayEquals(new Integer[0], d4.getIPv4Addresses()); + // add another entity to d4 + d4 = deviceManager.learnDeviceByEntity(e4b); + assertArrayEquals(new Integer[0], d4.getIPv4Addresses()); + + // Make e4 and e4a newer + Entity e4c = new Entity(4L, (short)4, 2, null, null, new Date(5000)); + Entity e4d = new Entity(4L, (short)4, null, 4L, 5, new Date(5000)); + d4 = deviceManager.learnDeviceByEntity(e4c); + d4 = deviceManager.learnDeviceByEntity(e4d); + assertArrayEquals(new Integer[0], d2.getIPv4Addresses()); + // FIXME: d4 should not return IP4 + assertArrayEquals(new Integer[] { 2 }, d4.getIPv4Addresses()); + + // Add another newer entity to d2 but with different IP + Entity e2d = new Entity(2L, (short)2, 22, 4L, 6, new Date(6000)); + d2 = deviceManager.learnDeviceByEntity(e2d); + assertArrayEquals(new Integer[] { 22 }, d2.getIPv4Addresses()); + assertArrayEquals(new Integer[] { 2 }, d4.getIPv4Addresses()); + + // new IP for d2,d4 but with same timestamp. Both devices get the IP + Entity e2e = new Entity(2L, (short)2, 42, 2L, 4, new Date(7000)); + d2 = deviceManager.learnDeviceByEntity(e2e); + ips= d2.getIPv4Addresses(); + Arrays.sort(ips); + assertArrayEquals(new Integer[] { 22, 42 }, ips); + Entity e4e = new Entity(4L, (short)4, 42, 4L, 7, new Date(7000)); + d4 = deviceManager.learnDeviceByEntity(e4e); + ips= d4.getIPv4Addresses(); + Arrays.sort(ips); + assertArrayEquals(new Integer[] { 2, 42 }, ips); + + // add a couple more IPs + Entity e2f = new Entity(2L, (short)2, 4242, 2L, 5, new Date(8000)); + d2 = deviceManager.learnDeviceByEntity(e2f); + ips= d2.getIPv4Addresses(); + Arrays.sort(ips); + assertArrayEquals(new Integer[] { 22, 42, 4242 }, ips); + Entity e4f = new Entity(4L, (short)4, 4242, 4L, 8, new Date(9000)); + d4 = deviceManager.learnDeviceByEntity(e4f); + ips= d4.getIPv4Addresses(); + Arrays.sort(ips); + assertArrayEquals(new Integer[] { 2, 42, 4242 }, ips); + } } -- GitLab