blob: 7afb78a219b5e495133c74f8e22b16eb3012d3fd [file] [log] [blame]
/**
* 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 static org.easymock.EasyMock.*;
import java.util.ArrayList;
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 java.util.concurrent.ConcurrentHashMap;
import static org.easymock.EasyMock.expectLastCall;
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 net.floodlightcontroller.devicemanager.IDeviceListener;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IEntityClass;
import net.floodlightcontroller.devicemanager.IEntityClassifierService;
import net.floodlightcontroller.devicemanager.SwitchPort;
import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus;
import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl.ClassState;
import net.floodlightcontroller.devicemanager.test.MockEntityClassifier;
import net.floodlightcontroller.devicemanager.test.MockEntityClassifierMac;
import net.floodlightcontroller.devicemanager.test.MockFlexEntityClassifier;
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 org.junit.Assert.*;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Ignore;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Ignore //TODO broken 11/19/13, should fix
public class DeviceManagerImplTest extends FloodlightTestCase {
protected final static Logger logger =
LoggerFactory.getLogger(DeviceManagerImplTest.class);
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();
ITopologyService topology = createMock(ITopologyService.class);
fmc.addService(IThreadPoolService.class, tp);
mockFloodlightProvider = getMockFloodlightProvider();
deviceManager = new DeviceManagerImpl();
flowReconcileMgr = new FlowReconcileManager();
DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
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);
fmc.addService(IEntityClassifierService.class, entityClassifier);
fmc.addService(ITopologyService.class, topology);
tp.init(fmc);
restApi.init(fmc);
storageSource.init(fmc);
deviceManager.init(fmc);
flowReconcileMgr.init(fmc);
entityClassifier.init(fmc);
storageSource.startUp(fmc);
deviceManager.startUp(fmc);
flowReconcileMgr.startUp(fmc);
tp.startUp(fmc);
entityClassifier.startUp(fmc);
reset(topology);
topology.addListener(deviceManager);
expectLastCall().anyTimes();
replay(topology);
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);
}
@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.entityClassifier= new MockEntityClassifier();
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));
assertEquals(DefaultEntityClassifier.entityClass ,
d1.entityClass);
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);
assertNotSame(d1.getDeviceKey(), d2.getDeviceKey());
assertEquals(MockEntityClassifier.testEC, d2.entityClass);
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);
assertEquals(d2.getDeviceKey(), d3.getDeviceKey());
assertEquals(MockEntityClassifier.testEC, d3.entityClass);
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);
assertEquals(d1.getDeviceKey(), d4.getDeviceKey());
assertEquals(DefaultEntityClassifier.entityClass, d4.entityClass);
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);
assertNotSame(d6, d7);
assertEquals(d6.getDeviceKey(), d7.getDeviceKey());
assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) },
d7.getAttachmentPoints());
assertArrayEquals(new Short[] { (short) 4 },
d7.getVlanId());
assertEquals(4, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
replay(mockListener);
reset(deviceManager.topology);
deviceManager.topology.addListener(deviceManager);
expectLastCall().times(1);
replay(deviceManager.topology);
deviceManager.entityClassifier = new MockEntityClassifierMac();
deviceManager.startUp(null);
Entity entityNoClass = new Entity(5L, (short)1, 5, -1L, 1, new Date());
assertEquals(null, deviceManager.learnDeviceByEntity(entityNoClass));
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(aps.length, 0);
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); // There is no device movement here; no not needed.
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)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT/ 2);
Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime());
c.add(Calendar.MILLISECOND,
(int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT / 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);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(EasyMock.anyLong(),
EasyMock.anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(EasyMock.anyLong(),
EasyMock.anyShort(),
EasyMock.anyLong(),
EasyMock.anyShort())).andReturn(false).
anyTimes();
expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
replay(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.entityClass);
// 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));
reset(mockTopology);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).
anyTimes();
expect(mockTopology.isConsistent(EasyMock.anyLong(),
EasyMock.anyShort(),
EasyMock.anyLong(),
EasyMock.anyShort())).andReturn(false).
anyTimes();
expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(),
EasyMock.anyShort()))
.andReturn(false)
.anyTimes();
expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes();
expect(mockTopology.isInSameBroadcastDomain(1L, (short)1, 5L, (short)2)).
andReturn(false).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);
}
/**
* Note: Entity expiration does not result in device moved notification.
* @throws Exception
*/
public void doTestEntityExpiration() throws Exception {
IDeviceListener mockListener =
createStrictMock(IDeviceListener.class);
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.isBroadcastDomainPort(1L, (short)1)).andReturn(false).anyTimes();
expect(mockTopology.isBroadcastDomainPort(5L, (short)1)).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());
// Attachment points are not removed, previous ones are still valid.
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 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());
// Attachment points are not removed, previous ones are still valid.
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 1) },
d.getAttachmentPoints());
verify(mockListener);
}
public void doTestDeviceExpiration() throws Exception {
IDeviceListener mockListener =
createStrictMock(IDeviceListener.class);
mockListener.deviceRemoved(isA(IDevice.class));
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());
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(EasyMock.anyLong(),
EasyMock.anyShort())).
andReturn(true).
anyTimes();
expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes();
expect(mockTopology.isConsistent(EasyMock.anyLong(),
EasyMock.anyShort(),
EasyMock.anyLong(),
EasyMock.anyShort())).andReturn(false).
anyTimes();
expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(),
EasyMock.anyShort())).
andReturn(false).anyTimes();
replay(mockTopology);
IDevice d = deviceManager.learnDeviceByEntity(entity2);
d = deviceManager.learnDeviceByEntity(entity1);
assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses());
deviceManager.addListener(mockListener);
replay(mockListener);
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);
verify(mockListener);
}
/*
* A ConcurrentHashMap for devices (deviceMap) that can be used to test
* code that specially handles concurrent modification situations. In
* particular, we overwrite values() and will replace / remove all the
* elements returned by values.
*
* The remove flag in the constructor specifies if devices returned by
* values() should be removed or replaced.
*/
protected static class ConcurrentlyModifiedDeviceMap
extends ConcurrentHashMap<Long, Device> {
private static final long serialVersionUID = 7784938535441180562L;
protected boolean remove;
public ConcurrentlyModifiedDeviceMap(boolean remove) {
super();
this.remove = remove;
}
@Override
public Collection<Device> values() {
// Get the values from the real map and copy them since
// the collection returned by values can reflect changed
Collection<Device> devs = new ArrayList<Device>(super.values());
for (Device d: devs) {
if (remove) {
// We remove the device from the underlying map
super.remove(d.getDeviceKey());
} else {
super.remove(d.getDeviceKey());
// We add a different Device instance with the same
// key to the map. We'll do some hackery so the device
// is different enough to compare differently in equals
// but otherwise looks the same.
// It's ugly but it works.
Entity[] curEntities = new Entity[d.getEntities().length];
int i = 0;
// clone entities
for (Entity e: d.getEntities()) {
curEntities[i] = new Entity (e.macAddress,
e.vlan,
e.ipv4Address,
e.switchDPID,
e.switchPort,
e.lastSeenTimestamp);
if (e.vlan == null)
curEntities[i].vlan = (short)1;
else
curEntities[i].vlan = (short)((e.vlan + 1 % 4095)+1);
i++;
}
Device newDevice = new Device(d, curEntities[0]);
newDevice.entities = curEntities;
assertEquals(false, newDevice.equals(d));
super.put(newDevice.getDeviceKey(), newDevice);
}
}
return devs;
}
}
@Test
public void testEntityExpiration() throws Exception {
doTestEntityExpiration();
}
@Test
public void testDeviceExpiration() throws Exception {
doTestDeviceExpiration();
}
/* Test correct entity cleanup behavior when a concurrent modification
* occurs.
*/
@Test
public void testEntityExpirationConcurrentModification() throws Exception {
deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false);
doTestEntityExpiration();
}
/* Test correct entity cleanup behavior when a concurrent remove
* occurs.
*/
@Test
public void testDeviceExpirationConcurrentRemove() throws Exception {
deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(true);
doTestDeviceExpiration();
}
/* Test correct entity cleanup behavior when a concurrent modification
* occurs.
*/
@Test
public void testDeviceExpirationConcurrentModification() throws Exception {
deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false);
doTestDeviceExpiration();
}
@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(1L, (short)1, 10L, (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();
expect(mockTopology.isConsistent(10L, (short)1, 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 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());
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);
// all entities are active, so entity3 should win
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1),},
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4);
entity1.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity1);
// all are still active; entity3 should still win
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
new SwitchPort(5L, 1,
ErrorStatus.DUPLICATE_DEVICE),
new SwitchPort(10L, 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());
// 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));
}
@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());
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);
// 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)},
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, 1);
entity1.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity1);
// all entities are active, so entities 2,4 should win
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(1L, 2, ErrorStatus.DUPLICATE_DEVICE)},
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+1);
entity1.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity1);
// 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)},
d.getAttachmentPoints(true));
entity3.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity3);
// 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);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
replay(mockTopology);
doTestDeviceQuery();
}
@Test
public void testDeviceQuery() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
replay(mockTopology);
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);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
replay(mockTopology);
doTestDeviceClassQuery();
}
@Test
public void testDeviceClassQuery() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
replay(mockTopology);
doTestDeviceClassQuery();
}
@Test
public void testFindDevice() {
boolean exceptionCaught;
deviceManager.entityClassifier= new MockEntityClassifierMac();
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
replay(mockTopology);
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 entity2b = new Entity(22L, (short)2, 2, 1L, 2, new Date());
Entity entity3 = new Entity(3L, (short)1, 3, 2L, 1, new Date());
Entity entity4 = new Entity(4L, (short)2, 4, 2L, 2, new Date());
Entity entity5 = new Entity(5L, (short)1, 5, 3L, 1, new Date());
IDevice d1 = deviceManager.learnDeviceByEntity(entity1);
IDevice d2 = deviceManager.learnDeviceByEntity(entity2);
IDevice d3 = deviceManager.learnDeviceByEntity(entity3);
IDevice d4 = deviceManager.learnDeviceByEntity(entity4);
IDevice d5 = deviceManager.learnDeviceByEntity(entity5);
// Make sure the entity classifier worked as expected
assertEquals(MockEntityClassifierMac.testECMac1, d1.getEntityClass());
assertEquals(MockEntityClassifierMac.testECMac1, d2.getEntityClass());
assertEquals(MockEntityClassifierMac.testECMac2, d3.getEntityClass());
assertEquals(MockEntityClassifierMac.testECMac2, d4.getEntityClass());
assertEquals(DefaultEntityClassifier.entityClass,
d5.getEntityClass());
// Look up the device using findDevice() which uses only the primary
// index
assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(),
entity1.getVlan(),
entity1.getIpv4Address(),
entity1.getSwitchDPID(),
entity1.getSwitchPort()));
// port changed. Device will be found through class index
assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(),
entity1.getVlan(),
entity1.getIpv4Address(),
entity1.getSwitchDPID(),
entity1.getSwitchPort()+1));
// VLAN changed. No device matches
assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(),
(short)42,
entity1.getIpv4Address(),
entity1.getSwitchDPID(),
entity1.getSwitchPort()));
assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(),
null,
entity1.getIpv4Address(),
entity1.getSwitchDPID(),
entity1.getSwitchPort()));
assertEquals(d2, deviceManager.findDeviceByEntity(entity2));
assertEquals(null, deviceManager.findDeviceByEntity(entity2b));
assertEquals(d3, deviceManager.findDevice(entity3.getMacAddress(),
entity3.getVlan(),
entity3.getIpv4Address(),
entity3.getSwitchDPID(),
entity3.getSwitchPort()));
// switch and port not set. throws exception
exceptionCaught = false;
try {
assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(),
entity3.getVlan(),
entity3.getIpv4Address(),
null,
null));
}
catch (IllegalArgumentException e) {
exceptionCaught = true;
}
if (!exceptionCaught)
fail("findDevice() did not throw IllegalArgumentException");
assertEquals(d4, deviceManager.findDeviceByEntity(entity4));
assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(),
entity5.getVlan(),
entity5.getIpv4Address(),
entity5.getSwitchDPID(),
entity5.getSwitchPort()));
// switch and port not set. throws exception (swith/port are key
// fields of IEntityClassifier but not d5.entityClass
exceptionCaught = false;
try {
assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(),
entity5.getVlan(),
entity5.getIpv4Address(),
null,
null));
}
catch (IllegalArgumentException e) {
exceptionCaught = true;
}
if (!exceptionCaught)
fail("findDevice() did not throw IllegalArgumentException");
Entity entityNoClass = new Entity(5L, (short)1, 5, -1L, 1, new Date());
assertEquals(null, deviceManager.findDeviceByEntity(entityNoClass));
// Now look up destination devices
assertEquals(d1, deviceManager.findDestDevice(d2,
entity1.getMacAddress(),
entity1.getVlan(),
entity1.getIpv4Address()));
assertEquals(d1, deviceManager.findDestDevice(d2,
entity1.getMacAddress(),
entity1.getVlan(),
null));
assertEquals(null, deviceManager.findDestDevice(d2,
entity1.getMacAddress(),
(short) -1,
0));
}
@Test
public void testGetIPv4Addresses() {
// Looks like Date is only 1s granularity
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
expect(mockTopology.isConsistent(EasyMock.anyLong(),
EasyMock.anyShort(),
EasyMock.anyLong(),
EasyMock.anyShort()))
.andReturn(false)
.anyTimes();
expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(),
EasyMock.anyShort()))
.andReturn(false)
.anyTimes();
expect(mockTopology.isInSameBroadcastDomain(EasyMock.anyLong(),
EasyMock.anyShort(),
EasyMock.anyLong(),
EasyMock.anyShort())).
andReturn(false).anyTimes();
replay(mockTopology);
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);
}
// TODO: this test should really go into a separate class that collects
// unit tests for Device
@Test
public void testGetSwitchPortVlanId() {
Entity entity1 = new Entity(1L, (short)1, null, 10L, 1, new Date());
Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date());
Entity entity3 = new Entity(1L, (short)3, null, 1L, 1, new Date());
Entity entity4 = new Entity(1L, (short)42, null, 1L, 1, new Date());
Entity[] entities = new Entity[] { entity1, entity2,
entity3, entity4
};
Device d = new Device(null,1L, null, null, Arrays.asList(entities), null);
SwitchPort swp1x1 = new SwitchPort(1L, 1);
SwitchPort swp1x2 = new SwitchPort(1L, 2);
SwitchPort swp2x1 = new SwitchPort(2L, 1);
SwitchPort swp10x1 = new SwitchPort(10L, 1);
assertArrayEquals(new Short[] { -1, 1},
d.getSwitchPortVlanIds(swp10x1));
assertArrayEquals(new Short[] { 3, 42},
d.getSwitchPortVlanIds(swp1x1));
assertArrayEquals(new Short[0],
d.getSwitchPortVlanIds(swp1x2));
assertArrayEquals(new Short[0],
d.getSwitchPortVlanIds(swp2x1));
}
@Test
public void testReclassifyDevice() {
MockFlexEntityClassifier flexClassifier =
new MockFlexEntityClassifier();
deviceManager.entityClassifier= flexClassifier;
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(anyLong(),
anyShort())).
andReturn(true).anyTimes();
expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
expect(mockTopology.isConsistent(EasyMock.anyLong(),
EasyMock.anyShort(),
EasyMock.anyLong(),
EasyMock.anyShort()))
.andReturn(false)
.anyTimes();
expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(),
EasyMock.anyShort()))
.andReturn(false)
.anyTimes();
replay(mockTopology);
//flexClassifier.createTestEntityClass("Class1");
Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date());
Entity entity1b = new Entity(1L, (short)2, 1, 1L, 1, new Date());
Entity entity2 = new Entity(2L, (short)1, 2, 2L, 2, new Date());
Entity entity2b = new Entity(2L, (short)2, 2, 2L, 2, new Date());
Device d1 = deviceManager.learnDeviceByEntity(entity1);
Device d2 = deviceManager.learnDeviceByEntity(entity2);
Device d1b = deviceManager.learnDeviceByEntity(entity1b);
Device d2b = deviceManager.learnDeviceByEntity(entity2b);
d1 = deviceManager.getDeviceIteratorForQuery(entity1.getMacAddress(),
entity1.getVlan(), entity1.getIpv4Address(),
entity1.getSwitchDPID(), entity1.getSwitchPort())
.next();
d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(),
entity1b.getVlan(), entity1b.getIpv4Address(),
entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next();
assertEquals(d1, d1b);
d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(),
entity2.getVlan(), entity2.getIpv4Address(),
entity2.getSwitchDPID(), entity2.getSwitchPort()).next();
d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(),
entity2b.getVlan(), entity2b.getIpv4Address(),
entity2b.getSwitchDPID(), entity2b.getSwitchPort()).next();
assertEquals(d2, d2b);
IEntityClass eC1 = flexClassifier.createTestEntityClass("C1");
IEntityClass eC2 = flexClassifier.createTestEntityClass("C2");
flexClassifier.addVlanEntities((short)1, eC1);
flexClassifier.addVlanEntities((short)2, eC1);
deviceManager.reclassifyDevice(d1);
deviceManager.reclassifyDevice(d2);
d1 = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity1));
d1b = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity1b));
assertEquals(d1, d1b);
d2 = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity2));
d2b = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity2b));
assertEquals(d2, d2b);
flexClassifier.addVlanEntities((short)1, eC2);
deviceManager.reclassifyDevice(d1);
deviceManager.reclassifyDevice(d2);
d1 = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity1));
d1b = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity1b));
d2 = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity2));
d2b = deviceManager.deviceMap.get(
deviceManager.primaryIndex.findByEntity(entity2b));
assertNotSame(d1, d1b);
assertNotSame(d2, d2b);
flexClassifier.addVlanEntities((short)1, eC1);
deviceManager.reclassifyDevice(d1);
deviceManager.reclassifyDevice(d2);
ClassState classState = deviceManager.classStateMap.get(eC1.getName());
Long deviceKey1 = null;
Long deviceKey1b = null;
Long deviceKey2 = null;
Long deviceKey2b = null;
deviceKey1 =
classState.classIndex.findByEntity(entity1);
deviceKey1b =
classState.classIndex.findByEntity(entity1b);
deviceKey2 =
classState.classIndex.findByEntity(entity2);
deviceKey2b =
classState.classIndex.findByEntity(entity2b);
assertEquals(deviceKey1, deviceKey1b);
assertEquals(deviceKey2, deviceKey2b);
}
}