diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java index f1eb3e991aa1a8b005085d1cb46cbf74c306ffc7..5b32a31c85f32ef5e187775ad71e115b3eafc57f 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java @@ -17,10 +17,10 @@ package net.floodlightcontroller.devicemanager.internal; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.HashSet; import java.util.TreeSet; import org.openflow.util.HexString; @@ -28,6 +28,7 @@ import org.openflow.util.HexString; import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.SwitchPort; +import net.floodlightcontroller.topology.ITopologyService; /** * Concrete implementation of {@link IDevice} @@ -35,7 +36,8 @@ import net.floodlightcontroller.devicemanager.SwitchPort; */ public class Device implements IDevice { protected Long deviceKey; - + protected DeviceManagerImpl deviceManager; + protected Entity[] entities; protected IEntityClass[] entityClasses; @@ -47,13 +49,16 @@ public class Device implements IDevice { /** * Create a device from a set of entities + * @param deviceManager the device manager for this device * @param deviceKey the unique identifier for this device object * @param entity the initial entity for the device * @param entityClasses the entity classes associated with the entity */ - public Device(Long deviceKey, + public Device(DeviceManagerImpl deviceManager, + Long deviceKey, Entity entity, Collection<IEntityClass> entityClasses) { + this.deviceManager = deviceManager; this.deviceKey = deviceKey; this.entities = new Entity[] {entity}; this.macAddressString = @@ -64,17 +69,20 @@ public class Device implements IDevice { } /** - * Construct a new device with the given key and containing the provided - * entities and entity classes + * Construct a new device consisting of the entities from the old device + * plus an additional entity * @param device the old device object - * @param entities the entities for the device + * @param newEntity the entity to add * @param entityClasses the entity classes associated with the entities */ public Device(Device device, - Collection<Entity> entities, + Entity newEntity, Collection<IEntityClass> entityClasses) { - this.deviceKey = device.getDeviceKey(); - this.entities = entities.toArray(new Entity[entities.size()]); + this.deviceManager = device.deviceManager; + this.deviceKey = device.deviceKey; + this.entities = Arrays.<Entity>copyOf(device.entities, + device.entities.length + 1); + this.entities[this.entities.length - 1] = newEntity; Arrays.sort(this.entities); this.macAddressString = @@ -162,8 +170,31 @@ public class Device implements IDevice { } } - HashSet<SwitchPort> vals = new HashSet<SwitchPort>(); - for (Entity e : entities) { + // Find the most recent attachment point for each cluster + // XXX - TODO suppress flapping + Entity[] clentities = Arrays.<Entity>copyOf(entities, entities.length); + Arrays.sort(clentities, deviceManager.clusterIdComparator); + + ITopologyService topology = deviceManager.topology; + long prevCluster = 0; + int clEntIndex = -1; + for (int i = 0; i < clentities.length; i++) { + if (clentities[i].switchDPID == null) continue; + long curCluster = + topology.getSwitchClusterId(clentities[i].switchDPID); + if (prevCluster != curCluster) + clEntIndex += 1; + clentities[clEntIndex] = clentities[i]; + prevCluster = curCluster; + } + + if (clEntIndex < 0) { + return new SwitchPort[0]; + } + + ArrayList<SwitchPort> vals = new ArrayList<SwitchPort>(clEntIndex + 1); + for (int i = 0; i <= clEntIndex; i++) { + Entity e = clentities[i]; if (e.getSwitchDPID() != null && e.getSwitchPort() != null) { SwitchPort sp = new SwitchPort(e.getSwitchDPID(), diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java index f8dd1eda3081f0aaeb3874735f64182b4cdf5d84..99a589db0522bbbbaf5710fb850088eb5a9c3619 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; @@ -198,6 +199,11 @@ public class DeviceManagerImpl implements } } + /** + * Comparator for sorting by cluster ID + */ + public Comparator<Entity> clusterIdComparator; + // ********************* // IDeviceManagerService // ********************* @@ -353,8 +359,6 @@ public class DeviceManagerImpl implements @Override public void setEntityClassifier(IEntityClassifier classifier) { entityClassifier = classifier; - primaryIndex = new DeviceUniqueIndex(classifier.getKeyFields()); - secondaryIndexMap = new HashMap<EnumSet<DeviceField>, DeviceIndex>(); } @Override @@ -511,10 +515,46 @@ public class DeviceManagerImpl implements public void startUp(FloodlightModuleContext fmc) { if (entityClassifier == null) setEntityClassifier(new DefaultEntityClassifier()); + + primaryIndex = new DeviceUniqueIndex(entityClassifier.getKeyFields()); + secondaryIndexMap = new HashMap<EnumSet<DeviceField>, DeviceIndex>(); + deviceMap = new ConcurrentHashMap<Long, Device>(); classStateMap = new ConcurrentHashMap<IEntityClass, ClassState>(); - + clusterIdComparator = new Comparator<Entity>() { + @Override + public int compare(Entity e1, Entity e2) { + int r = 0; + + Long swdpid1 = e1.getSwitchDPID(); + Long swdpid2 = e2.getSwitchDPID(); + if (swdpid1 == null) + r = swdpid2 == null ? 0 : -1; + else if (swdpid2 == null) + r = 1; + else { + Long d1ClusterId = + topology.getSwitchClusterId(swdpid1); + Long d2ClusterId = + topology.getSwitchClusterId(swdpid2); + r = d1ClusterId.compareTo(d2ClusterId); + } + if (r != 0) return r; + + Date e1t = e1.getLastSeenTimestamp(); + Date e2t = e2.getLastSeenTimestamp(); + if (e1t == null) + r = e2t == null ? 0 : -1; + else if (e2t == null) + r = 1; + else + r = e1t.compareTo(e2t); + + return r; + } + }; + if (topology != null) { // Register to get updates from topology topology.addListener(this); @@ -807,13 +847,12 @@ public class DeviceManagerImpl implements } } if (deviceKey != null) { - // If the primary or secondary index contains the entity, - // update the entity timestamp, then use resulting device - // key to look up the device in the device map, and - // use the referenced Device below. + // If the primary or secondary index contains the entity + // use resulting device key to look up the device in the + // device map, and use the referenced Device below. device = deviceMap.get(deviceKey); if (device == null) - continue; + throw new IllegalStateException("Corrupted device index"); } else { // If the secondary index does not contain the entity, // create a new Device object containing the entity, and @@ -821,11 +860,12 @@ public class DeviceManagerImpl implements synchronized (deviceKeyLock) { deviceKey = Long.valueOf(deviceKeyCounter++); } - device = new Device(deviceKey, entity, classes); + device = new Device(this, deviceKey, entity, classes); // Add the new device to the primary map with a simple put deviceMap.put(deviceKey, device); + // update indices if (!updateIndices(device, deviceKey)) { if (deleteQueue == null) deleteQueue = new ArrayList<Long>(); @@ -835,6 +875,7 @@ public class DeviceManagerImpl implements updateSecondaryIndices(entity, classes, deviceKey); + // generate new device update deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(device, true, null)); @@ -856,62 +897,20 @@ public class DeviceManagerImpl implements // field (including updating the entity caches), preserving the // old timestamp of the entity. - Entity[] entities = device.getEntities(); - ArrayList<Entity> newEntities = null; - ArrayList<Entity> removedEntities = null; - EnumSet<DeviceField> changedFields = - findChangedFields(device, entity); - - // iterate backwards since we want indices for removed entities - // to update in reverse order - for (int i = entities.length - 1; i >= 0; i--) { - // XXX - TODO Handle port channels - // XXX - TODO Handle broadcast domains - // XXX - TODO Prevent flapping of entities - // XXX - TODO Handle unique indices - - Long edpid = entities[i].getSwitchDPID(); - Long cdpid = entity.getSwitchDPID(); - - // Remove attachment points in the same cluster - if (edpid != null && cdpid != null && - topology != null && - topology.inSameCluster(edpid, cdpid)) { - // XXX - TODO don't delete entities; we should just - // filter out the attachment points on read - removedEntities = - updateEntityList(removedEntities, entities[i]); - - changedFields.add(DeviceField.SWITCH); - - Entity shim = makeShimEntity(entity, entities[i], - device.getEntityClasses()); - newEntities = updateEntityList(newEntities, shim); - continue; - } - - newEntities = updateEntityList(newEntities, entities[i]); - } - newEntities = updateEntityList(newEntities, entity); - removeEntities(removedEntities, device.getEntityClasses()); + // XXX - TODO Prevent flapping of entities Device newDevice = new Device(device, - newEntities, classes); - - updateSecondaryIndices(entity, - newDevice.getEntityClasses(), - deviceKey); - for (Entity e : newEntities) { - updateSecondaryIndices(e, - newDevice.getEntityClasses(), - deviceKey); - } + entity, classes); + // generate updates + EnumSet<DeviceField> changedFields = + findChangedFields(device, entity); deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(device, false, changedFields)); + // update the device map with a replace call boolean res = deviceMap.replace(deviceKey, device, newDevice); // If replace returns false, restart the process from the // beginning (this implies another thread concurrently @@ -921,9 +920,13 @@ public class DeviceManagerImpl implements device = newDevice; + // update indices if (!updateIndices(device, deviceKey)) { continue; } + updateSecondaryIndices(entity, + device.getEntityClasses(), + deviceKey); break; } } @@ -1007,72 +1010,7 @@ public class DeviceManagerImpl implements } } } - - /** - * If there's information that would be lost about a device because - * we're removing an old entity, construct a "shim" entity to provide - * that information - * @param newentity the entity being added - * @param rementity the entity that's being removed - * @param classes the entity classes - * @return the entity, or null if no entity needed - */ - private Entity makeShimEntity(Entity newentity, Entity rementity, - IEntityClass[] classes) { - Set<DeviceField> nonkey = null; - - for (IEntityClass clazz : classes) { - if (nonkey == null) - nonkey = EnumSet.complementOf(clazz.getKeyFields()); - else - nonkey.removeAll(clazz.getKeyFields()); - } - Integer ipv4Address = null; - Short vlan = null; - - for (DeviceField f : nonkey) { - switch (f) { - case IPV4: - if (rementity.getIpv4Address() != null && - !rementity.getIpv4Address() - .equals(newentity.getIpv4Address())) - ipv4Address = rementity.getIpv4Address(); - break; - case VLAN: - if (rementity.getVlan() != null && - !rementity.getVlan() - .equals(newentity.getVlan())) - vlan = rementity.getVlan(); - break; - case MAC: - case PORT: - case SWITCH: - break; - default: - logger.warn("Unexpected device field {}", f); - } - } - - Entity shim = null; - if (ipv4Address != null || vlan != null) { - shim = new Entity(rementity.getMacAddress(), vlan, - ipv4Address, null, null, - rementity.getLastSeenTimestamp()); - } - return shim; - } - - private ArrayList<Entity> updateEntityList(ArrayList<Entity> list, - Entity entity) { - if (entity == null) return list; - if (list == null) - list = new ArrayList<Entity>(); - list.add(entity); - - return list; - } - private LinkedList<DeviceUpdate> updateUpdates(LinkedList<DeviceUpdate> list, DeviceUpdate update) { if (update == null) return list; diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java index 8ea54363236fd5a90aa089d3ad29a7d218eeb138..784b74fe0611d5004a500b53150f9c92c7da61c0 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java @@ -18,6 +18,7 @@ package net.floodlightcontroller.devicemanager.internal; import java.util.Arrays; +import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.EnumSet; @@ -29,6 +30,7 @@ import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.anyLong; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; @@ -157,6 +159,11 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.addListener(mockListener); deviceManager.setEntityClassifier(new TestEntityClassifier()); + ITopologyService mockTopology = createMock(ITopologyService.class); + expect(mockTopology.getSwitchClusterId(anyLong())). + andReturn(1L).anyTimes(); + deviceManager.topology = mockTopology; + Entity entity1 = new Entity(1L, null, null, 1L, 1, new Date()); Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date()); Entity entity3 = new Entity(1L, null, 1, 10L, 1, new Date()); @@ -164,9 +171,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Entity entity5 = new Entity(2L, (short)4, 1, 5L, 2, new Date()); Entity entity6 = new Entity(2L, (short)4, 1, 50L, 3, new Date()); - mockListener.deviceAdded(isA(IDevice.class)); - replay(mockListener); + replay(mockListener, mockTopology); Device d1 = deviceManager.learnDeviceByEntity(entity1); assertSame(d1, deviceManager.learnDeviceByEntity(entity1)); @@ -257,30 +263,27 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.addListener(mockListener); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.inSameCluster(1L, 2L)).andReturn(true).anyTimes(); - expect(mockTopology.inSameCluster(2L, 1L)).andReturn(true).anyTimes(); - - expect(mockTopology.inSameCluster(3L, 4L)).andReturn(true).anyTimes(); - expect(mockTopology.inSameCluster(4L, 3L)).andReturn(true).anyTimes(); - - expect(mockTopology.inSameCluster(1L, 3L)).andReturn(false).anyTimes(); - expect(mockTopology.inSameCluster(3L, 1L)).andReturn(false).anyTimes(); - expect(mockTopology.inSameCluster(1L, 4L)).andReturn(false).anyTimes(); - expect(mockTopology.inSameCluster(4L, 1L)).andReturn(false).anyTimes(); - - expect(mockTopology.inSameCluster(2L, 3L)).andReturn(false).anyTimes(); - expect(mockTopology.inSameCluster(3L, 2L)).andReturn(false).anyTimes(); - expect(mockTopology.inSameCluster(2L, 4L)).andReturn(false).anyTimes(); - expect(mockTopology.inSameCluster(4L, 2L)).andReturn(false).anyTimes(); + expect(mockTopology.getSwitchClusterId(1L)). + andReturn(1L).anyTimes(); + expect(mockTopology.getSwitchClusterId(2L)). + andReturn(1L).anyTimes(); + expect(mockTopology.getSwitchClusterId(3L)). + andReturn(3L).anyTimes(); + expect(mockTopology.getSwitchClusterId(4L)). + andReturn(3L).anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; - Entity entity1 = new Entity(1L, null, 1, 1L, 1, new Date()); - Entity entity2 = new Entity(1L, null, null, 2L, 1, new Date()); - Entity entity3 = new Entity(1L, null, null, 3L, 1, new Date()); - Entity entity4 = new Entity(1L, null, null, 4L, 1, new Date()); + Calendar c = Calendar.getInstance(); + Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); + c.add(1,Calendar.SECOND); + Entity entity2 = new Entity(1L, null, null, 2L, 1, c.getTime()); + c.add(1,Calendar.SECOND); + Entity entity3 = new Entity(1L, null, null, 3L, 1, c.getTime()); + c.add(1,Calendar.SECOND); + Entity entity4 = new Entity(1L, null, null, 4L, 1, c.getTime()); IDevice d; SwitchPort[] aps; @@ -316,8 +319,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { d = deviceManager.learnDeviceByEntity(entity3); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(3L, 1), - new SwitchPort(2L, 1) }, aps); + assertArrayEquals(new SwitchPort[] { new SwitchPort(2L, 1), + new SwitchPort(3L, 1) }, aps); ips = d.getIPv4Addresses(); assertArrayEquals(new Integer[] { 1 }, ips); verify(mockListener); @@ -339,7 +342,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { @Test public void testPacketIn() throws Exception { deviceManager.addIndex(true, true, EnumSet.of(DeviceField.IPV4)); - byte[] dataLayerSource = ((Ethernet)this.testPacket).getSourceMACAddress(); + byte[] dataLayerSource = + ((Ethernet)this.testPacket).getSourceMACAddress(); // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); @@ -356,7 +360,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // build our expected Device Integer ipaddr = IPv4.toIPv4Address("192.168.1.1"); Device device = - new Device(new Long(deviceManager.deviceKeyCounter), + new Device(deviceManager, + new Long(deviceManager.deviceKeyCounter), new Entity(Ethernet.toLong(dataLayerSource), (short)5, ipaddr, @@ -392,7 +397,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(device, result); device = - new Device(new Long(deviceManager.deviceKeyCounter), + new Device(device, new Entity(Ethernet.toLong(dataLayerSource), (short)5, ipaddr, @@ -406,7 +411,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockSwitch.getStringId()). andReturn("00:00:00:00:00:00:00:02").anyTimes(); expect(mockTopology.isInternal(2L, (short)2)).andReturn(false); - expect(mockTopology.inSameCluster(1L, 2L)).andReturn(true); + expect(mockTopology.getSwitchClusterId(1L)).andReturn(1L).anyTimes(); + expect(mockTopology.getSwitchClusterId(2L)).andReturn(1L).anyTimes(); // Start recording the replay on the mocks replay(mockSwitch, mockTopology); diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java index d2fbf581b9d056fbf442406f6a89f9199f6723ea..aacef4e102d6fcf4f1b58a26585890bfdf0256ab 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java @@ -1,6 +1,10 @@ package net.floodlightcontroller.devicemanager.test; +import java.util.Collections; +import java.util.Set; + import net.floodlightcontroller.devicemanager.IDevice; +import net.floodlightcontroller.devicemanager.IDeviceManagerAware; import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl; import net.floodlightcontroller.devicemanager.internal.Entity; @@ -16,17 +20,43 @@ public class MockDeviceManager extends DeviceManagerImpl { * @param ipv4Address the IP (can be null) * @param switchDPID the attachment point switch DPID (can be null) * @param switchPort the attachment point switch port (can be null) + * @param processUpdates if false, will not send updates. Note that this + * method is not thread safe if this is false * @return the device, either new or not */ public IDevice learnEntity(long macAddress, Short vlan, Integer ipv4Address, Long switchDPID, - Integer switchPort) { + Integer switchPort, + boolean processUpdates) { + Set<IDeviceManagerAware> listeners = deviceListeners; + if (!processUpdates) { + deviceListeners = Collections.<IDeviceManagerAware>emptySet(); + } + if (vlan != null && vlan.shortValue() <= 0) vlan = null; if (ipv4Address != null && ipv4Address == 0) ipv4Address = null; - return learnDeviceByEntity(new Entity(macAddress, vlan, - ipv4Address, switchDPID, - switchPort, null)); + IDevice res = learnDeviceByEntity(new Entity(macAddress, vlan, + ipv4Address, switchDPID, + switchPort, null)); + deviceListeners = listeners; + return res; + } + + /** + * Learn a device using the given characteristics. + * @param macAddress the MAC + * @param vlan the VLAN (can be null) + * @param ipv4Address the IP (can be null) + * @param switchDPID the attachment point switch DPID (can be null) + * @param switchPort the attachment point switch port (can be null) + * @return the device, either new or not + */ + public IDevice learnEntity(long macAddress, Short vlan, + Integer ipv4Address, Long switchDPID, + Integer switchPort) { + return learnEntity(macAddress, vlan, ipv4Address, + switchDPID, switchPort, true); } } diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java index 9b96785b98ceb828423a0ccbcb7d906467a6e284..7e4278eaa0ce6a8671fdf311513c8875e2ac7489 100644 --- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java +++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java @@ -33,13 +33,13 @@ import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.test.MockFloodlightProvider; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.devicemanager.internal.Device; -import net.floodlightcontroller.devicemanager.internal.Entity; +import net.floodlightcontroller.devicemanager.test.MockDeviceManager; import net.floodlightcontroller.counter.CounterStore; +import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.devicemanager.IDevice; import net.floodlightcontroller.devicemanager.IDeviceManagerService; -import net.floodlightcontroller.linkdiscovery.SwitchPortTuple; import net.floodlightcontroller.packet.Data; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; @@ -69,12 +69,12 @@ import org.openflow.protocol.action.OFActionOutput; public class ForwardingTest extends FloodlightTestCase { protected MockFloodlightProvider mockFloodlightProvider; protected FloodlightContext cntx; - protected IDeviceManagerService deviceManager; + protected MockDeviceManager deviceManager; protected IRoutingService routingEngine; protected Forwarding forwarding; protected ITopologyService topology; protected IOFSwitch sw1, sw2; - protected Device srcDevice, dstDevice1, dstDevice2; + protected IDevice srcDevice, dstDevice1, dstDevice2; protected OFPacketIn packetIn; protected OFPacketOut packetOut; protected IPacket testPacket; @@ -90,15 +90,23 @@ public class ForwardingTest extends FloodlightTestCase { cntx = new FloodlightContext(); mockFloodlightProvider = getMockFloodlightProvider(); forwarding = getForwarding(); - deviceManager = createMock(IDeviceManagerService.class); + deviceManager = new MockDeviceManager(); routingEngine = createMock(IRoutingService.class); topology = createMock(ITopologyService.class); - forwarding.setFloodlightProvider(mockFloodlightProvider); - forwarding.setDeviceManager(deviceManager); - forwarding.setRoutingEngine(routingEngine); - forwarding.setTopology(topology); - forwarding.setCounterStore(new CounterStore()); + FloodlightModuleContext fmc = new FloodlightModuleContext(); + fmc.addService(IFloodlightProviderService.class, + mockFloodlightProvider); + fmc.addService(ITopologyService.class, topology); + fmc.addService(IRoutingService.class, routingEngine); + fmc.addService(ICounterStoreService.class, new CounterStore()); + fmc.addService(IDeviceManagerService.class, deviceManager); + + forwarding.init(fmc); + deviceManager.init(fmc); + deviceManager.startUp(fmc); + forwarding.startUp(fmc); + // Mock switches sw1 = EasyMock.createNiceMock(IOFSwitch.class); expect(sw1.getId()).andReturn(1L).anyTimes(); @@ -157,29 +165,14 @@ public class ForwardingTest extends FloodlightTestCase { getDestinationAddress(); currentDate = new Date(); - Entity e = new Entity(Ethernet.toLong(dataLayerSource), - null, - networkSource, - 1L, - 1, - currentDate); - srcDevice = new Device(0L, e, DefaultEntityClassifier.entityClasses); - - e = new Entity(Ethernet.toLong(dataLayerDest), - null, - networkDest, - 2L, - 3, - currentDate); - dstDevice1 = new Device(1L, e, DefaultEntityClassifier.entityClasses); - - e = new Entity(Ethernet.toLong(dataLayerDest), - null, - networkDest, - 1L, - 3, - currentDate); - dstDevice2 = new Device(2L, e, DefaultEntityClassifier.entityClasses); + srcDevice = + deviceManager.learnEntity(Ethernet.toLong(dataLayerSource), + null, networkSource, + 1L, 1); + dstDevice1 = + deviceManager.learnEntity(Ethernet.toLong(dataLayerDest), + null, networkDest, + 2L, 3); // Mock Packet-in testPacketSerialized = testPacket.serialize(); @@ -277,9 +270,9 @@ public class ForwardingTest extends FloodlightTestCase { expectLastCall().anyTimes(); // Reset mocks, trigger the packet in, and validate results - replay(sw1, sw2, deviceManager, routingEngine, topology); + replay(sw1, sw2, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2,deviceManager, routingEngine); + verify(sw1, sw2, routingEngine); assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. @@ -301,6 +294,26 @@ public class ForwardingTest extends FloodlightTestCase { @Test public void testForwardSingleSwitchPath() throws Exception { // Set destination as local and Mock route + byte[] dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress(); + byte[] dataLayerDest = + ((Ethernet)testPacket).getDestinationMACAddress(); + int networkSource = + ((IPv4)((Ethernet)testPacket).getPayload()). + getSourceAddress(); + int networkDest = + ((IPv4)((Ethernet)testPacket).getPayload()). + getDestinationAddress(); + deviceManager.startUp(null); + + srcDevice = + deviceManager.learnEntity(Ethernet.toLong(dataLayerSource), + null, networkSource, + 1L, 1); + dstDevice2 = + deviceManager.learnEntity(Ethernet.toLong(dataLayerDest), + null, networkDest, + 1L, 3); + IDeviceManagerService.fcStore. put(cntx, IDeviceManagerService.CONTEXT_DST_DEVICE, @@ -331,9 +344,9 @@ public class ForwardingTest extends FloodlightTestCase { sw1.write(packetOut, cntx); // Reset mocks, trigger the packet in, and validate results - replay(sw1, sw2, deviceManager, routingEngine, topology); + replay(sw1, sw2, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2, deviceManager, routingEngine); + verify(sw1, sw2, routingEngine); } @Test @@ -344,9 +357,9 @@ public class ForwardingTest extends FloodlightTestCase { // Reset mocks, trigger the packet in, and validate results expect(topology.isIncomingBroadcastAllowedOnSwitchPort(1L, (short)1)).andReturn(true).anyTimes(); - replay(sw1, sw2, deviceManager, routingEngine, topology); + replay(sw1, sw2, routingEngine, topology); forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2,deviceManager, routingEngine); + verify(sw1, sw2, routingEngine); } }