DeviceManagerImpl implements IDeviceService, IOFMessageListener, ITopologyListener, IFloodlightModule, IEntityClassListener, IInfoProvider { protected Device learnDeviceByEntity(Entity entity) { ArrayList<Long> deleteQueue = null; LinkedList<DeviceUpdate> deviceUpdates = null; Device device = null; while (true) { deviceUpdates = null; Long deviceKey = primaryIndex.findByEntity(entity); IEntityClass entityClass = null; if (deviceKey == null) { entityClass = entityClassifier.classifyEntity(entity); if (entityClass == null) { device = null; break; } ClassState classState = getClassState(entityClass); if (classState.classIndex != null) { deviceKey = classState.classIndex.findByEntity(entity); } } if (deviceKey != null) { device = deviceMap.get(deviceKey); if (device == null) { if (logger.isDebugEnabled()) { logger.debug("No device for deviceKey {} while " + "while processing entity {}", deviceKey, entity); } continue; } } else { if (entity.hasSwitchPort() && !topology.isAttachmentPointPort(entity.getSwitchDPID(), entity.getSwitchPort())) { cntDeviceOnInternalPortNotLearned.increment(); if (logger.isDebugEnabled()) { logger.debug("Not learning new device on internal" + " link: {}", entity); } device = null; break; } if (!isEntityAllowed(entity, entityClass)) { cntPacketNotAllowed.increment(); if (logger.isDebugEnabled()) { logger.debug("PacketIn is not allowed {} {}", entityClass.getName(), entity); } device = null; break; } deviceKey = deviceKeyCounter.getAndIncrement(); device = allocateDevice(deviceKey, entity, entityClass); deviceMap.put(deviceKey, device); if (!updateIndices(device, deviceKey)) { if (deleteQueue == null) deleteQueue = new ArrayList<Long>(); deleteQueue.add(deviceKey); continue; } updateSecondaryIndices(entity, entityClass, deviceKey); cntNewDevice.increment(); if (logger.isDebugEnabled()) { logger.debug("New device created: {} deviceKey={}, entity={}", new Object[]{device, deviceKey, entity}); } deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(device, ADD, null)); break; } if (!isEntityAllowed(entity, device.getEntityClass())) { cntPacketNotAllowed.increment(); if (logger.isDebugEnabled()) { logger.info("PacketIn is not allowed {} {}", device.getEntityClass().getName(), entity); } return null; } if (entity.hasSwitchPort() && !topology.isAttachmentPointPort(entity.getSwitchDPID(), entity.getSwitchPort())) { cntPacketOnInternalPortForKnownDevice.increment(); break; } int entityindex = -1; if ((entityindex = device.entityIndex(entity)) >= 0) { Date lastSeen = entity.getLastSeenTimestamp(); if (lastSeen == null) { lastSeen = new Date(); entity.setLastSeenTimestamp(lastSeen); } device.entities[entityindex].setLastSeenTimestamp(lastSeen); } else { entityindex = -(entityindex + 1); Device newDevice = allocateDevice(device, entity, entityindex); EnumSet<DeviceField> changedFields = findChangedFields(device, entity); boolean res = deviceMap.replace(deviceKey, device, newDevice); if (!res) continue; device = newDevice; if (!updateIndices(device, deviceKey)) { continue; } updateSecondaryIndices(entity, device.getEntityClass(), deviceKey); cntNewEntity.increment(); if (changedFields.size() > 0) { cntDeviceChanged.increment(); deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(newDevice, CHANGE, changedFields)); } } if (entity.hasSwitchPort()) { boolean moved = device.updateAttachmentPoint(entity.getSwitchDPID(), entity.getSwitchPort(), entity.getLastSeenTimestamp()); if (moved) { sendDeviceMovedNotification(device); if (logger.isTraceEnabled()) { logger.trace("Device moved: attachment points {}," + "entities {}", device.attachmentPoints, device.entities); } } else { if (logger.isTraceEnabled()) { logger.trace("Device attachment point updated: " + "attachment points {}," + "entities {}", device.attachmentPoints, device.entities); } } } break; } if (deleteQueue != null) { for (Long l : deleteQueue) { Device dev = deviceMap.get(l); this.deleteDevice(dev); } } processUpdates(deviceUpdates); deviceSyncManager.storeDeviceThrottled(device); return device; }  @Override IDevice getDevice(Long deviceKey); @Override IDevice findDevice(MacAddress macAddress, VlanVid vlan,
			IPv4Address ipv4Address, DatapathId switchDPID,
			OFPort switchPort); @Override IDevice findClassDevice(IEntityClass entityClass, MacAddress macAddress,
			VlanVid vlan, IPv4Address ipv4Address); @Override Collection<? extends IDevice> getAllDevices(); @Override void addIndex(boolean perClass,
			EnumSet<DeviceField> keyFields); @Override Iterator<? extends IDevice> queryDevices(MacAddress macAddress,
			VlanVid vlan,
			IPv4Address ipv4Address,
			DatapathId switchDPID,
			OFPort switchPort); @Override Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
			MacAddress macAddress,
			VlanVid vlan,
			IPv4Address ipv4Address,
			DatapathId switchDPID,
			OFPort switchPort); @Override void addListener(IDeviceListener listener); @Override void addSuppressAPs(DatapathId swId, OFPort port); @Override void removeSuppressAPs(DatapathId swId, OFPort port); @Override Set<SwitchPort> getSuppressAPs(); @Override Map<String, Object> getInfo(String type); @Override String getName(); @Override boolean isCallbackOrderingPrereq(OFType type, String name); @Override boolean isCallbackOrderingPostreq(OFType type, String name); @Override Command receive(IOFSwitch sw, OFMessage msg,
			FloodlightContext cntx); @Override Collection<Class<? extends IFloodlightService>> getModuleServices(); @Override Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls(); @Override Collection<Class<? extends IFloodlightService>> getModuleDependencies(); @Override void init(FloodlightModuleContext fmc); @Override void startUp(FloodlightModuleContext fmc); boolean isValidAttachmentPoint(DatapathId switchDPID,
			OFPort switchPort); @Override void topologyChanged(List<LDUpdate> updateList); @Override void entityClassChanged(Set<String> entityClassNames); static final String MODULE_NAME; static final String PACKAGE; public IDebugCounter cntIncoming; public IDebugCounter cntReconcileRequest; public IDebugCounter cntReconcileNoSource; public IDebugCounter cntReconcileNoDest; public IDebugCounter cntInvalidSource; public IDebugCounter cntInvalidDest; public IDebugCounter cntNoSource; public IDebugCounter cntNoDest; public IDebugCounter cntDhcpClientNameSnooped; public IDebugCounter cntDeviceOnInternalPortNotLearned; public IDebugCounter cntPacketNotAllowed; public IDebugCounter cntNewDevice; public IDebugCounter cntPacketOnInternalPortForKnownDevice; public IDebugCounter cntNewEntity; public IDebugCounter cntDeviceChanged; public IDebugCounter cntDeviceMoved; public IDebugCounter cntCleanupEntitiesRuns; public IDebugCounter cntEntityRemovedTimeout; public IDebugCounter cntDeviceDeleted; public IDebugCounter cntDeviceReclassifyDelete; public IDebugCounter cntDeviceStrored; public IDebugCounter cntDeviceStoreThrottled; public IDebugCounter cntDeviceRemovedFromStore; public IDebugCounter cntSyncException; public IDebugCounter cntDevicesFromStore; public IDebugCounter cntConsolidateStoreRuns; public IDebugCounter cntConsolidateStoreDevicesRemoved; public IDebugCounter cntTransitionToMaster; public AttachmentPointComparator apComparator; public SingletonTask entityCleanupTask; }
@Test public void testAttachmentPointFlapping() throws Exception { Calendar c = Calendar.getInstance(); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes(); expect(mockTopology.getL2DomainId(DatapathId.of(anyLong()))). andReturn(DatapathId.of(1L)).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))). andReturn(true).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Entity entity1 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(1), c.getTime()); Entity entity1a = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(1), c.getTime()); Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(10L), OFPort.of(1), c.getTime()); entity1.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2); entity1a.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity2.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity3.setLastSeenTimestamp(c.getTime()); IDevice d; d = deviceManager.learnDeviceByEntity(entity1); d = deviceManager.learnDeviceByEntity(entity1a); d = deviceManager.learnDeviceByEntity(entity2); d = deviceManager.learnDeviceByEntity(entity3); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)),}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(1), ErrorStatus.DUPLICATE_DEVICE), new SwitchPort(DatapathId.of(10L), OFPort.of(1), ErrorStatus.DUPLICATE_DEVICE) }, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+2000); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); assertEquals(entity1.getActiveSince(), entity1.getLastSeenTimestamp()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, d.getAttachmentPoints(true)); }
@Test public void testAttachmentPointFlappingTwoCluster() throws Exception { Calendar c = Calendar.getInstance(); ITopologyService mockTopology = createMock(ITopologyService.class); expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes(); expect(mockTopology.getL2DomainId(DatapathId.of(1L))). andReturn(DatapathId.of(1L)).anyTimes(); expect(mockTopology.getL2DomainId(DatapathId.of(5L))). andReturn(DatapathId.of(5L)).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(2))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(2), DatapathId.of(5L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(5L), OFPort.of(2))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(2), DatapathId.of(1L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(2))). andReturn(false).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(2), DatapathId.of(5L), OFPort.of(1))). andReturn(false).anyTimes(); Date topologyUpdateTime = new Date(); expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; Entity entity1 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(1), c.getTime()); Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(2), c.getTime()); Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(1), c.getTime()); Entity entity4 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(2), c.getTime()); entity1.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2); c.add(Calendar.MILLISECOND, 1); entity2.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity3.setLastSeenTimestamp(c.getTime()); c.add(Calendar.MILLISECOND, 1); entity4.setLastSeenTimestamp(c.getTime()); deviceManager.learnDeviceByEntity(entity1); deviceManager.learnDeviceByEntity(entity2); deviceManager.learnDeviceByEntity(entity3); IDevice d = deviceManager.learnDeviceByEntity(entity4); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(2)), new SwitchPort(DatapathId.of(5L), OFPort.of(2)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(2)), new SwitchPort(DatapathId.of(5L), OFPort.of(2))}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, 1); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(2)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(2)), new SwitchPort(DatapathId.of(1L), OFPort.of(2), ErrorStatus.DUPLICATE_DEVICE)}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+1); entity1.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity1); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(2)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(2))}, d.getAttachmentPoints(true)); entity3.setLastSeenTimestamp(c.getTime()); d = deviceManager.learnDeviceByEntity(entity3); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(1)) }, d.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), new SwitchPort(DatapathId.of(5L), OFPort.of(1)) }, d.getAttachmentPoints(true)); }
@Test public void testGetIPv4Addresses() { ITopologyService mockTopology = createMock(ITopologyService.class); deviceManager.topology = mockTopology; expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))). andReturn(true).anyTimes(); expect(mockTopology.getL2DomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes(); expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()), OFPort.of(EasyMock.anyShort()), DatapathId.of(EasyMock.anyLong()), OFPort.of(EasyMock.anyShort()))) .andReturn(false) .anyTimes(); expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()), OFPort.of(EasyMock.anyShort()))) .andReturn(false) .anyTimes(); expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(EasyMock.anyLong()), OFPort.of(EasyMock.anyShort()), DatapathId.of(EasyMock.anyLong()), OFPort.of(EasyMock.anyShort()))). andReturn(false).anyTimes(); replay(mockTopology); Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), null, null, null, new Date(2000)); Device d1 = deviceManager.learnDeviceByEntity(e1); assertArrayEquals(new Integer[0], d1.getIPv4Addresses()); Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), null, null, new Date(2000)); Device d2 = deviceManager.learnDeviceByEntity(e2); d2 = deviceManager.learnDeviceByEntity(e2); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses()); Entity e2b = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), null, DatapathId.of(2L), OFPort.of(2), new Date(3000)); d2 = deviceManager.learnDeviceByEntity(e2b); assertEquals(2, d2.entities.length); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses()); Entity e2c = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(2L), OFPort.of(3), new Date(3000)); d2 = deviceManager.learnDeviceByEntity(e2c); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses()); assertEquals(3, d2.entities.length); Entity e3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), null, null, new Date(4000)); Entity e3b = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), DatapathId.of(3L), OFPort.of(3), new Date(4400)); Device d3 = deviceManager.learnDeviceByEntity(e3); d3 = deviceManager.learnDeviceByEntity(e3b); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses()); assertArrayEquals(new IPv4Address[] { IPv4Address.of(3) }, d3.getIPv4Addresses()); Entity e3c = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(33), DatapathId.of(3L), OFPort.of(3), new Date(4400)); d3 = deviceManager.learnDeviceByEntity(e3c); IPv4Address[] ips = d3.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new IPv4Address[] { IPv4Address.of(3), IPv4Address.of(33) }, ips); Entity e4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(2), null, null, new Date(1000)); Entity e4b = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), null, DatapathId.of(4L), OFPort.of(4), new Date(1000)); Device d4 = deviceManager.learnDeviceByEntity(e4); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses()); assertArrayEquals(new IPv4Address[0], d4.getIPv4Addresses()); d4 = deviceManager.learnDeviceByEntity(e4b); assertArrayEquals(new IPv4Address[0], d4.getIPv4Addresses()); Entity e4c = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(2), null, null, new Date(5000)); Entity e4d = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), null, DatapathId.of(4L), OFPort.of(5), new Date(5000)); d4 = deviceManager.learnDeviceByEntity(e4c); d4 = deviceManager.learnDeviceByEntity(e4d); assertArrayEquals(new IPv4Address[0], d2.getIPv4Addresses()); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d4.getIPv4Addresses()); Entity e2d = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(22), DatapathId.of(4L), OFPort.of(6), new Date(6000)); d2 = deviceManager.learnDeviceByEntity(e2d); assertArrayEquals(new IPv4Address[] { IPv4Address.of(22) }, d2.getIPv4Addresses()); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d4.getIPv4Addresses()); Entity e2e = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(42), DatapathId.of(2L), OFPort.of(4), new Date(7000)); d2 = deviceManager.learnDeviceByEntity(e2e); ips= d2.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new IPv4Address[] { IPv4Address.of(22), IPv4Address.of(42) }, ips); Entity e4e = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(42), DatapathId.of(4L), OFPort.of(7), new Date(7000)); d4 = deviceManager.learnDeviceByEntity(e4e); ips= d4.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2), IPv4Address.of(42) }, ips); Entity e2f = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(4242), DatapathId.of(2L), OFPort.of(5), new Date(8000)); d2 = deviceManager.learnDeviceByEntity(e2f); ips= d2.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new IPv4Address[] { IPv4Address.of(22), IPv4Address.of(42), IPv4Address.of(4242) }, ips); Entity e4f = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(4242), DatapathId.of(4L), OFPort.of(8), new Date(9000)); d4 = deviceManager.learnDeviceByEntity(e4f); ips= d4.getIPv4Addresses(); Arrays.sort(ips); assertArrayEquals(new IPv4Address[] { IPv4Address.of(2), IPv4Address.of(42), IPv4Address.of(4242) }, ips); }