/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
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 static org.easymock.EasyMock.anyShort;
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.core.test.MockThreadPoolService;
import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.*;
import net.floodlightcontroller.devicemanager.IDeviceListener;
import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IEntityClass;
import net.floodlightcontroller.devicemanager.SwitchPort;
import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.flowcache.FlowReconcileManager;
import net.floodlightcontroller.flowcache.IFlowReconcileService;
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPacket;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.restserver.RestApiServer;
import net.floodlightcontroller.storage.IStorageSourceService;
import net.floodlightcontroller.storage.memory.MemoryStorageSource;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.ITopologyService;
import static net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus.*;
import static org.junit.Assert.*;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPhysicalPort;
import org.openflow.protocol.OFType;
import org.openflow.protocol.OFPacketIn.OFPacketInReason;
import org.openflow.util.HexString;
public class DeviceManagerImplTest extends FloodlightTestCase {
protected OFPacketIn packetIn_1, packetIn_2, packetIn_3;
protected IPacket testARPReplyPacket_1, testARPReplyPacket_2,
testARPReplyPacket_3;
protected IPacket testARPReqPacket_1, testARPReqPacket_2;
protected byte[] testARPReplyPacket_1_Srld, testARPReplyPacket_2_Srld;
private byte[] testARPReplyPacket_3_Serialized;
MockFloodlightProvider mockFloodlightProvider;
DeviceManagerImpl deviceManager;
MemoryStorageSource storageSource;
FlowReconcileManager flowReconcileMgr;
private IOFSwitch makeSwitchMock(long id) {
IOFSwitch mockSwitch = createMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(id).anyTimes();
expect(mockSwitch.getStringId()).
andReturn(HexString.toHexString(id, 6)).anyTimes();
expect(mockSwitch.getPort(anyShort())).
andReturn(new OFPhysicalPort()).anyTimes();
expect(mockSwitch.portEnabled(isA(OFPhysicalPort.class))).
andReturn(true).anyTimes();
return mockSwitch;
}
@Before
public void setUp() throws Exception {
super.setUp();
FloodlightModuleContext fmc = new FloodlightModuleContext();
RestApiServer restApi = new RestApiServer();
MockThreadPoolService tp = new MockThreadPoolService();
fmc.addService(IThreadPoolService.class, tp);
mockFloodlightProvider = getMockFloodlightProvider();
deviceManager = new DeviceManagerImpl();
flowReconcileMgr = new FlowReconcileManager();
fmc.addService(IDeviceService.class, deviceManager);
storageSource = new MemoryStorageSource();
fmc.addService(IStorageSourceService.class, storageSource);
fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider);
fmc.addService(IRestApiService.class, restApi);
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
tp.init(fmc);
restApi.init(fmc);
storageSource.init(fmc);
deviceManager.init(fmc);
flowReconcileMgr.init(fmc);
storageSource.startUp(fmc);
deviceManager.startUp(fmc);
flowReconcileMgr.startUp(fmc);
tp.startUp(fmc);
IOFSwitch mockSwitch1 = makeSwitchMock(1L);
IOFSwitch mockSwitch10 = makeSwitchMock(10L);
IOFSwitch mockSwitch5 = makeSwitchMock(5L);
IOFSwitch mockSwitch50 = makeSwitchMock(50L);
Map<Long, IOFSwitch> switches = new HashMap<Long,IOFSwitch>();
switches.put(1L, mockSwitch1);
switches.put(10L, mockSwitch10);
switches.put(5L, mockSwitch5);
switches.put(50L, mockSwitch50);
mockFloodlightProvider.setSwitches(switches);
replay(mockSwitch1, mockSwitch5, mockSwitch10, mockSwitch50);
// Build our test packet
this.testARPReplyPacket_1 = new Ethernet()
.setSourceMACAddress("00:44:33:22:11:01")
.setDestinationMACAddress("00:11:22:33:44:55")
.setEtherType(Ethernet.TYPE_ARP)
.setVlanID((short)5)
.setPayload(
new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REPLY)
.setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
.setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
this.testARPReplyPacket_1_Srld = testARPReplyPacket_1.serialize();
// Another test packet with a different source IP
this.testARPReplyPacket_2 = new Ethernet()
.setSourceMACAddress("00:44:33:22:11:01")
.setDestinationMACAddress("00:11:22:33:44:55")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(
new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REPLY)
.setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
.setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
this.testARPReplyPacket_2_Srld = testARPReplyPacket_2.serialize();
this.testARPReplyPacket_3 = new Ethernet()
.setSourceMACAddress("00:44:33:22:11:01")
.setDestinationMACAddress("00:11:22:33:44:55")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(
new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REPLY)
.setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.3"))
.setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
this.testARPReplyPacket_3_Serialized = testARPReplyPacket_3.serialize();
// Build the PacketIn
this.packetIn_1 = ((OFPacketIn) mockFloodlightProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(this.testARPReplyPacket_1_Srld)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) this.testARPReplyPacket_1_Srld.length);
// Build the PacketIn
this.packetIn_2 = ((OFPacketIn) mockFloodlightProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(this.testARPReplyPacket_2_Srld)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) this.testARPReplyPacket_2_Srld.length);
// Build the PacketIn
this.packetIn_3 = ((OFPacketIn) mockFloodlightProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(this.testARPReplyPacket_3_Serialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) this.testARPReplyPacket_3_Serialized.length);
}
static EnumSet<DeviceField> testKeyFields;
static {
testKeyFields = EnumSet.of(MAC, VLAN, SWITCH, PORT);
}
public static class TestEntityClass implements IEntityClass {
@Override
public EnumSet<DeviceField> getKeyFields() {
return testKeyFields;
}
}
protected static IEntityClass testEC = new TestEntityClass();
public static class TestEntityClassifier extends DefaultEntityClassifier {
@Override
public Collection<IEntityClass> classifyEntity(Entity entity) {
if (entity.switchDPID >= 10L) {
return Arrays.asList(testEC);
}
return DefaultEntityClassifier.entityClasses;
}
@Override
public EnumSet<IDeviceService.DeviceField> getKeyFields() {
return testKeyFields;
}
}
@Test
public void testLastSeen() throws Exception {
Calendar c = Calendar.getInstance();
Date d1 = c.getTime();
Entity entity1 = new Entity(1L, null, null, null, null, d1);
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(1L, null, 1, null, null, c.getTime());
IDevice d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(c.getTime(), d.getLastSeen());
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(c.getTime(), d.getLastSeen());
deviceManager.startUp(null);
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(d1, d.getLastSeen());
d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(c.getTime(), d.getLastSeen());
}
@Test
public void testEntityLearning() throws Exception {
IDeviceListener mockListener =
createStrictMock(IDeviceListener.class);
deviceManager.addListener(mockListener);
deviceManager.setEntityClassifier(new TestEntityClassifier());
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getL2DomainId(anyLong())).
andReturn(1L).anyTimes();
expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())).
andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(10L, (short)1, 10L, (short)1)).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)1)).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(50L, (short)3, 50L, (short)3)).
andReturn(true).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
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());
Entity entity4 = new Entity(1L, null, 1, 1L, 1, new Date());
Entity entity5 = new Entity(2L, (short)4, 1, 5L, 2, new Date());
Entity entity6 = new Entity(2L, (short)4, 1, 50L, 3, new Date());
Entity entity7 = new Entity(2L, (short)4, 2, 50L, 3, new Date());
mockListener.deviceAdded(isA(IDevice.class));
replay(mockListener, mockTopology);
Device d1 = deviceManager.learnDeviceByEntity(entity1);
assertSame(d1, deviceManager.learnDeviceByEntity(entity1));
assertSame(d1, deviceManager.findDeviceByEntity(entity1));
assertArrayEquals(new IEntityClass[]{ DefaultEntityClassifier.entityClass },
d1.entityClasses);
assertArrayEquals(new Short[] { -1 }, d1.getVlanId());
assertArrayEquals(new Integer[] { }, d1.getIPv4Addresses());
assertEquals(1, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceAdded(isA(IDevice.class));
replay(mockListener);
Device d2 = deviceManager.learnDeviceByEntity(entity2);
assertFalse(d1.equals(d2));
assertNotSame(d1, d2);
assertArrayEquals(new IEntityClass[]{ testEC },
d2.entityClasses);
assertArrayEquals(new Short[] { -1 }, d2.getVlanId());
assertArrayEquals(new Integer[] { }, d2.getIPv4Addresses());
assertEquals(2, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
replay(mockListener);
Device d3 = deviceManager.learnDeviceByEntity(entity3);
assertNotSame(d2, d3);
assertArrayEquals(new IEntityClass[]{ testEC },
d3.entityClasses);
assertArrayEquals(new Integer[] { 1 },
d3.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) },
d3.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) },
d3.getAttachmentPoints(true));
assertArrayEquals(new Short[] { -1 },
d3.getVlanId());
assertEquals(2, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
replay(mockListener);
Device d4 = deviceManager.learnDeviceByEntity(entity4);
assertNotSame(d1, d4);
assertArrayEquals(new IEntityClass[]{ DefaultEntityClassifier.entityClass },
d4.entityClasses);
assertArrayEquals(new Integer[] { 1 },
d4.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d4.getAttachmentPoints());
assertArrayEquals(new Short[] { -1 },
d4.getVlanId());
assertEquals(2, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceAdded((isA(IDevice.class)));
replay(mockListener);
Device d5 = deviceManager.learnDeviceByEntity(entity5);
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 2) },
d5.getAttachmentPoints());
assertArrayEquals(new Short[] { (short) 4 },
d5.getVlanId());
assertEquals(2L, d5.getMACAddress());
assertEquals("00:00:00:00:00:02", d5.getMACAddressString());
verify(mockListener);
reset(mockListener);
mockListener.deviceAdded(isA(IDevice.class));
replay(mockListener);
Device d6 = deviceManager.learnDeviceByEntity(entity6);
assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) },
d6.getAttachmentPoints());
assertArrayEquals(new Short[] { (short) 4 },
d6.getVlanId());
assertEquals(4, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
replay(mockListener);
Device d7 = deviceManager.learnDeviceByEntity(entity7);
assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) },
d7.getAttachmentPoints());
assertArrayEquals(new Short[] { (short) 4 },
d7.getVlanId());
assertEquals(4, deviceManager.getAllDevices().size());
verify(mockListener);
}
@Test
public void testAttachmentPointLearning() throws Exception {
IDeviceListener mockListener =
createStrictMock(IDeviceListener.class);
deviceManager.addListener(mockListener);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getL2DomainId(1L)).
andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).
andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(10L)).
andReturn(10L).anyTimes();
expect(mockTopology.getL2DomainId(50L)).
andReturn(10L).anyTimes();
expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())).
andReturn(false).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
anyLong(), anyShort())).andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(5L, (short)1, 10L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(10L, (short)1, 50L, (short)1)).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Calendar c = Calendar.getInstance();
Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
Entity entity0 = new Entity(1L, null, null, null, null, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity4 = new Entity(1L, null, null, 50L, 1, c.getTime());
IDevice d;
SwitchPort[] aps;
Integer[] ips;
mockListener.deviceAdded(isA(IDevice.class));
replay(mockListener);
deviceManager.learnDeviceByEntity(entity1);
d = deviceManager.learnDeviceByEntity(entity0);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved((isA(IDevice.class)));
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved((isA(IDevice.class)));
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity3);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1),
new SwitchPort(10L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved((isA(IDevice.class)));
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity4);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1),
new SwitchPort(50L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
}
@Test
public void testAttachmentPointSuppression() throws Exception {
IDeviceListener mockListener =
createStrictMock(IDeviceListener.class);
deviceManager.addListener(mockListener);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getL2DomainId(1L)).
andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).
andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(10L)).
andReturn(10L).anyTimes();
expect(mockTopology.getL2DomainId(50L)).
andReturn(10L).anyTimes();
expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())).
andReturn(false).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
anyLong(), anyShort())).andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(5L, (short)1, 50L, (short)1)).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
// suppress (1L, 1) and (10L, 1)
deviceManager.addSuppressAPs(1L, (short)1);
deviceManager.addSuppressAPs(10L, (short)1);
Calendar c = Calendar.getInstance();
Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
Entity entity0 = new Entity(1L, null, null, null, null, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity4 = new Entity(1L, null, null, 50L, 1, c.getTime());
IDevice d;
SwitchPort[] aps;
Integer[] ips;
mockListener.deviceAdded(isA(IDevice.class));
replay(mockListener);
deviceManager.learnDeviceByEntity(entity1);
d = deviceManager.learnDeviceByEntity(entity0);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertEquals(0, aps.length);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved((isA(IDevice.class)));
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved((isA(IDevice.class)));
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity3);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved((isA(IDevice.class)));
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity4);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1),
new SwitchPort(50L, 1) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new Integer[] { 1 }, ips);
verify(mockListener);
}
@Test
public void testBDAttachmentPointLearning() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getL2DomainId(anyLong())).
andReturn(1L).anyTimes();
expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.isBroadcastDomainPort(1L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isBroadcastDomainPort(1L, (short)2)).
andReturn(true).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(1L, (short)1,
1L, (short)2)).andReturn(true).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(1L, (short)2,
1L, (short)1)).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Calendar c = Calendar.getInstance();
Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
c.add(Calendar.MILLISECOND,
(int)DeviceManagerImpl.NBD_TO_BD_TIMEDIFF_MS / 2);
Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime());
c.add(Calendar.MILLISECOND,
(int)DeviceManagerImpl.NBD_TO_BD_TIMEDIFF_MS / 2 + 1);
Entity entity3 = new Entity(1L, null, null, 1L, 2, c.getTime());
IDevice d;
SwitchPort[] aps;
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps);
// this timestamp is too soon; don't switch
d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps);
// it should switch when we learn with a timestamp after the
// timeout
d = deviceManager.learnDeviceByEntity(entity3);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2) }, aps);
}
@Test
public void testPacketIn() throws Exception {
byte[] dataLayerSource =
((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress();
// Mock up our expected behavior
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
deviceManager.topology = mockTopology;
Date currentDate = new Date();
// build our expected Device
Integer ipaddr = IPv4.toIPv4Address("192.168.1.1");
Device device =
new Device(deviceManager,
new Long(deviceManager.deviceKeyCounter),
new Entity(Ethernet.toLong(dataLayerSource),
(short)5,
ipaddr,
1L,
1,
currentDate),
DefaultEntityClassifier.entityClasses);
expect(mockTopology.isAllowed(EasyMock.anyLong(),
EasyMock.anyShort())).
andReturn(true).anyTimes();
// Start recording the replay on the mocks
replay(mockTopology);
// Get the listener and trigger the packet in
IOFSwitch switch1 = mockFloodlightProvider.getSwitches().get(1L);
mockFloodlightProvider.dispatchMessage(switch1, this.packetIn_1);
// Verify the replay matched our expectations
verify(mockTopology);
// Verify the device
Device rdevice = (Device)
deviceManager.findDevice(Ethernet.toLong(dataLayerSource),
(short)5, null, null, null);
assertEquals(device, rdevice);
assertEquals(new Short((short)5), rdevice.getVlanId()[0]);
Device result = null;
Iterator<? extends IDevice> dstiter =
deviceManager.queryClassDevices(device, null, null, ipaddr,
null, null);
if (dstiter.hasNext()) {
result = (Device)dstiter.next();
}
assertEquals(device, result);
device =
new Device(device,
new Entity(Ethernet.toLong(dataLayerSource),
(short)5,
ipaddr,
5L,
2,
currentDate),
DefaultEntityClassifier.entityClasses);
reset(mockTopology);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes();
// Start recording the replay on the mocks
replay(mockTopology);
// Get the listener and trigger the packet in
IOFSwitch switch5 = mockFloodlightProvider.getSwitches().get(5L);
mockFloodlightProvider.
dispatchMessage(switch5,
this.packetIn_1.setInPort((short)2));
// Verify the replay matched our expectations
verify(mockTopology);
// Verify the device
rdevice = (Device)
deviceManager.findDevice(Ethernet.toLong(dataLayerSource),
(short)5, null, null, null);
assertEquals(device, rdevice);
}
@Test
public void testEntityExpiration() throws Exception {
IDeviceListener mockListener =
createStrictMock(IDeviceListener.class);
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
mockListener.deviceMoved(isA(IDevice.class));
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.isBroadcastDomainPort(anyLong(),
anyShort())).
andReturn(false).anyTimes();
expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).andReturn(5L).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Calendar c = Calendar.getInstance();
Entity entity1 = new Entity(1L, null, 2, 1L, 1, c.getTime());
c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1);
Entity entity2 = new Entity(1L, null, 1, 5L, 1, c.getTime());
deviceManager.learnDeviceByEntity(entity1);
IDevice d = deviceManager.learnDeviceByEntity(entity2);
assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 1)},
d.getAttachmentPoints());
Iterator<? extends IDevice> diter =
deviceManager.queryClassDevices(d, null, null, 1, null, null);
assertTrue(diter.hasNext());
assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
diter = deviceManager.queryClassDevices(d, null, null, 2, null, null);
assertTrue(diter.hasNext());
assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
deviceManager.addListener(mockListener);
replay(mockListener);
deviceManager.entityCleanupTask.reschedule(0, null);
d = deviceManager.getDevice(d.getDeviceKey());
assertArrayEquals(new Integer[] { 2 }, d.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints());
diter = deviceManager.queryClassDevices(d, null, null, 2, null, null);
assertTrue(diter.hasNext());
assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
diter = deviceManager.queryClassDevices(d, null, null, 1, null, null);
assertFalse(diter.hasNext());
d = deviceManager.findDevice(1L, null, null, null, null);
assertArrayEquals(new Integer[] { 2 }, d.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints());
verify(mockListener);
}
@Test
public void testDeviceExpiration() throws Exception {
Calendar c = Calendar.getInstance();
c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1);
Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
Entity entity2 = new Entity(1L, null, 2, 5L, 1, c.getTime());
IDevice d = deviceManager.learnDeviceByEntity(entity2);
d = deviceManager.learnDeviceByEntity(entity1);
assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses());
deviceManager.entityCleanupTask.reschedule(0, null);
IDevice r = deviceManager.getDevice(d.getDeviceKey());
assertNull(r);
Iterator<? extends IDevice> diter =
deviceManager.queryClassDevices(d, null, null, 1, null, null);
assertFalse(diter.hasNext());
r = deviceManager.findDevice(1L, null, null, null, null);
assertNull(r);
}
@Test
public void testAttachmentPointFlapping() throws Exception {
Calendar c = Calendar.getInstance();
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.isBroadcastDomainPort(anyLong(),
anyShort())).
andReturn(false).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
anyLong(), anyShort())).andReturn(false).anyTimes();
expect(mockTopology.getL2DomainId(anyLong())).
andReturn(1L).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)1)).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(5L, (short)1, 10L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(10L, (short)1, 1L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(5L, (short)1, 1L, (short)1)).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime());
Entity entity1a = new Entity(1L, null, 1, 1L, 1, c.getTime());
Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime());
Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime());
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2);
entity1.setLastSeenTimestamp(c.getTime());
entity1a.setLastSeenTimestamp(c.getTime());
c.add(Calendar.MILLISECOND, 1);
entity2.setLastSeenTimestamp(c.getTime());
c.add(Calendar.MILLISECOND, 1);
entity3.setLastSeenTimestamp(c.getTime());
deviceManager.learnDeviceByEntity(entity1);
deviceManager.learnDeviceByEntity(entity1a);
deviceManager.learnDeviceByEntity(entity2);
IDevice d = deviceManager.learnDeviceByEntity(entity3);
// all entities are active, so entity3 should win
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1),
new SwitchPort(1L, 1,
DUPLICATE_DEVICE),
new SwitchPort(5L, 1,
DUPLICATE_DEVICE) },
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4);
entity1.setLastSeenTimestamp(c.getTime());
// all are still active; entity3 should still win
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1),
new SwitchPort(1L, 1,
DUPLICATE_DEVICE),
new SwitchPort(5L, 1,
DUPLICATE_DEVICE) },
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+1);
entity1.setLastSeenTimestamp(c.getTime());
assertEquals(entity1.getActiveSince(), entity1.getLastSeenTimestamp());
// entity1 should now be the only active entity
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints(true));
deviceManager.startUp(null);
c = Calendar.getInstance();
entity1.setActiveSince(c.getTime());
entity1.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity1);
// entity1 is only entity
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints());
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2);
entity2.setActiveSince(c.getTime());
entity2.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity2);
// entity2 is strictly later
assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) },
d.getAttachmentPoints());
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT);
entity1.setLastSeenTimestamp(c.getTime());
// entity 1 is strictly later
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints());
}
@Test
public void testAttachmentPointFlappingTwoCluster() throws Exception {
Calendar c = Calendar.getInstance();
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).andReturn(true).anyTimes();
expect(mockTopology.isBroadcastDomainPort(anyLong(),
anyShort())).
andReturn(false).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
anyLong(), anyShort())).andReturn(false).anyTimes();
expect(mockTopology.getL2DomainId(1L)).
andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).
andReturn(5L).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)2)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(1L, (short)2, 5L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(5L, (short)1, 5L, (short)2)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(1L, (short)2, 1L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)2)).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(5L, (short)2, 5L, (short)1)).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime());
Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime());
Entity entity3 = new Entity(1L, null, null, 5L, 1, c.getTime());
Entity entity4 = new Entity(1L, null, null, 5L, 2, c.getTime());
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2);
entity1.setLastSeenTimestamp(c.getTime());
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);
// all entities are active, so entities 2,4 should win
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2),
new SwitchPort(5L, 2) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2),
new SwitchPort(5L, 2),
new SwitchPort(1L, 1,
DUPLICATE_DEVICE),
new SwitchPort(5L, 1,
DUPLICATE_DEVICE) },
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT);
entity1.setLastSeenTimestamp(c.getTime());
// entities 3,4 are still in conflict, but 1 should be resolved
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 2) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 2),
new SwitchPort(5L, 1,
DUPLICATE_DEVICE) },
d.getAttachmentPoints(true));
entity3.setLastSeenTimestamp(c.getTime());
// no conflicts, 1 and 3 will win
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 1) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 1) },
d.getAttachmentPoints(true));
}
protected void doTestDeviceQuery() throws Exception {
Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date());
Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date());
Entity entity3 = new Entity(3L, (short)3, 3, 5L, 1, new Date());
Entity entity4 = new Entity(4L, (short)4, 3, 5L, 2, new Date());
Entity entity5 = new Entity(1L, (short)4, 3, 5L, 2, new Date());
deviceManager.learnDeviceByEntity(entity1);
deviceManager.learnDeviceByEntity(entity2);
deviceManager.learnDeviceByEntity(entity3);
deviceManager.learnDeviceByEntity(entity4);
Iterator<? extends IDevice> iter =
deviceManager.queryDevices(null, (short)1, 1, null, null);
int count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(1, count);
iter = deviceManager.queryDevices(null, (short)3, 3, null, null);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(1, count);
iter = deviceManager.queryDevices(null, (short)1, 3, null, null);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(0, count);
deviceManager.learnDeviceByEntity(entity5);
iter = deviceManager.queryDevices(null, (short)4, 3, null, null);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(2, count);
}
@Test
public void testDeviceIndex() throws Exception {
EnumSet<IDeviceService.DeviceField> indexFields =
EnumSet.noneOf(IDeviceService.DeviceField.class);
indexFields.add(IDeviceService.DeviceField.IPV4);
indexFields.add(IDeviceService.DeviceField.VLAN);
deviceManager.addIndex(false, indexFields);
doTestDeviceQuery();
}
@Test
public void testDeviceQuery() throws Exception {
doTestDeviceQuery();
}
protected void doTestDeviceClassQuery() throws Exception {
Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date());
Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date());
Entity entity3 = new Entity(3L, (short)3, 3, 5L, 1, new Date());
Entity entity4 = new Entity(4L, (short)4, 3, 5L, 2, new Date());
Entity entity5 = new Entity(1L, (short)4, 3, 5L, 2, new Date());
IDevice d = deviceManager.learnDeviceByEntity(entity1);
deviceManager.learnDeviceByEntity(entity2);
deviceManager.learnDeviceByEntity(entity3);
deviceManager.learnDeviceByEntity(entity4);
Iterator<? extends IDevice> iter =
deviceManager.queryClassDevices(d, null,
(short)1, 1, null, null);
int count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(1, count);
iter = deviceManager.queryClassDevices(d, null,
(short)3, 3, null, null);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(1, count);
iter = deviceManager.queryClassDevices(d, null,
(short)1, 3, null, null);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(0, count);
deviceManager.learnDeviceByEntity(entity5);
iter = deviceManager.queryClassDevices(d, null,
(short)4, 3, null, null);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(2, count);
}
@Test
public void testDeviceClassIndex() throws Exception {
EnumSet<IDeviceService.DeviceField> indexFields =
EnumSet.noneOf(IDeviceService.DeviceField.class);
indexFields.add(IDeviceService.DeviceField.IPV4);
indexFields.add(IDeviceService.DeviceField.VLAN);
deviceManager.addIndex(true, indexFields);
doTestDeviceClassQuery();
}
@Test
public void testDeviceClassQuery() throws Exception {
doTestDeviceClassQuery();
}
}