/**
* 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.anyLong;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.anyShort;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.isA;
import static org.easymock.EasyMock.or;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IListener.Command;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.HARole;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.debugcounter.IDebugCounterService;
import net.floodlightcontroller.debugcounter.MockDebugCounterService;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IDeviceListener;
import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.devicemanager.SwitchPort;
import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField;
import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus;
import net.floodlightcontroller.devicemanager.IEntityClass;
import net.floodlightcontroller.devicemanager.IEntityClassifierService;
import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl.ClassState;
import net.floodlightcontroller.devicemanager.internal.DeviceSyncRepresentation.SyncEntity;
import net.floodlightcontroller.devicemanager.test.MockEntityClassifier;
import net.floodlightcontroller.devicemanager.test.MockEntityClassifierMac;
import net.floodlightcontroller.devicemanager.test.MockFlexEntityClassifier;
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.Data;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPacket;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.packet.IPv6;
import net.floodlightcontroller.packet.UDP;
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 org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketInReason;import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IPv6Address;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.VlanVid;
import org.sdnplatform.sync.IClosableIterator;
import org.sdnplatform.sync.IStoreClient;
import org.sdnplatform.sync.ISyncService;
import org.sdnplatform.sync.Versioned;
import org.sdnplatform.sync.test.MockSyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DeviceManagerImplTest extends FloodlightTestCase {
protected static Logger logger =
LoggerFactory.getLogger(DeviceManagerImplTest.class);
protected OFPacketIn testARPReplyPacketIn_1, testARPReplyPacketIn_2;
protected OFPacketIn testUDPPacketIn;
protected OFPacketIn testUDPIPv6PacketIn;
protected OFPacketIn testUDPIPv6RevPacketIn;
protected IPacket testARPReplyPacket_1, testARPReplyPacket_2;
protected Ethernet testUDPPacket;
protected Ethernet testUDPIPv6Packet;
protected Ethernet testUDPIPv6RevPacket;
protected byte[] testARPReplyPacket_1_Srld, testARPReplyPacket_2_Srld;
protected byte[] testUDPPacketSrld;
private MockSyncService syncService;
private IStoreClient<String, DeviceSyncRepresentation> storeClient;
DeviceManagerImpl deviceManager;
MemoryStorageSource storageSource;
IDebugCounterService debugCounterService;
private IOFSwitch makeSwitchMock(DatapathId id) {
IOFSwitch mockSwitch = createMock(IOFSwitch.class);
OFPortDesc mockPortDesc = createMock(OFPortDesc.class);
OFPort port = OFPort.of(1);
expect(mockSwitch.getId()).andReturn(id).anyTimes();
expect(mockSwitch.getPort(OFPort.of(1))).andReturn(mockPortDesc).anyTimes();
expect(mockPortDesc.getPortNo()).andReturn(port).anyTimes();
return mockSwitch;
}
/*
* return an EasyMock ITopologyService that's setup so that it will
* answer all questions a device or device manager will ask
* (isAttachmentPointPort, etc.) in a way so that every port is a
* non-BD, attachment point port.
* The returned mock is still in record mode
*/
private ITopologyService makeMockTopologyAllPortsAp() {
ITopologyService mockTopology = createMock(ITopologyService.class);
mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
expectLastCall().andReturn(true).anyTimes();
mockTopology.getClusterId(DatapathId.of(anyLong()));
expectLastCall().andReturn(DatapathId.of(1L)).anyTimes();
mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
expectLastCall().andReturn(false).anyTimes();
mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()));
expectLastCall().andReturn(false).anyTimes();
mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong()));
expectLastCall().andReturn(false).anyTimes();
return mockTopology;
}
@Override
@Before
public void setUp() throws Exception {
doSetUp(HARole.ACTIVE);
}
public void doSetUp(HARole initialRole) throws Exception {
super.setUp();
this.syncService = new MockSyncService();
FloodlightModuleContext fmc = new FloodlightModuleContext();
RestApiServer restApi = new RestApiServer();
MockThreadPoolService tp = new MockThreadPoolService();
ITopologyService topology = createMock(ITopologyService.class);
fmc.addService(IThreadPoolService.class, tp);
mockFloodlightProvider = getMockFloodlightProvider();
mockFloodlightProvider.setRole(initialRole, "");
debugCounterService = new MockDebugCounterService();
deviceManager = new DeviceManagerImpl();
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(IEntityClassifierService.class, entityClassifier);
fmc.addService(ITopologyService.class, topology);
fmc.addService(ISyncService.class, syncService);
fmc.addService(IDebugCounterService.class, debugCounterService);
tp.init(fmc);
restApi.init(fmc);
storageSource.init(fmc);
deviceManager.init(fmc);
entityClassifier.init(fmc);
syncService.init(fmc);
storageSource.startUp(fmc);
deviceManager.startUp(fmc);
tp.startUp(fmc);
entityClassifier.startUp(fmc);
syncService.startUp(fmc);
this.storeClient =
this.syncService.getStoreClient(DeviceManagerImpl.DEVICE_SYNC_STORE_NAME,
String.class, DeviceSyncRepresentation.class);
reset(topology);
topology.addListener(deviceManager);
expectLastCall().anyTimes();
replay(topology);
IOFSwitch mockSwitch1 = makeSwitchMock(DatapathId.of(1L));
IOFSwitch mockSwitch10 = makeSwitchMock(DatapathId.of(10L));
IOFSwitch mockSwitch5 = makeSwitchMock(DatapathId.of(5L));
IOFSwitch mockSwitch50 = makeSwitchMock(DatapathId.of(50L));
Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>();
switches.put(DatapathId.of(1L), mockSwitch1);
switches.put(DatapathId.of(10L), mockSwitch10);
switches.put(DatapathId.of(5L), mockSwitch5);
switches.put(DatapathId.of(50L), mockSwitch50);
getMockSwitchService().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(EthType.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(MacAddress.of("00:44:33:22:11:01"))
.setSenderProtocolAddress(IPv4Address.of("192.168.1.1"))
.setTargetHardwareAddress(MacAddress.of("00:11:22:33:44:55"))
.setTargetProtocolAddress(IPv4Address.of("192.168.1.2")));
this.testARPReplyPacket_1_Srld = testARPReplyPacket_1.serialize();
// Another test packet with the same ARP payload as packet 1 but with
// a different source MAC. (i.e., sender MAC and source MAC differ)
this.testARPReplyPacket_2 = new Ethernet()
.setSourceMACAddress("00:99:88:77:66:55")
.setDestinationMACAddress("00:11:22:33:44:55")
.setEtherType(EthType.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(MacAddress.of("00:44:33:22:11:01"))
.setSenderProtocolAddress(IPv4Address.of("192.168.1.1"))
.setTargetHardwareAddress(MacAddress.of("00:11:22:33:44:55"))
.setTargetProtocolAddress(IPv4Address.of("192.168.1.2")));
this.testARPReplyPacket_2_Srld = testARPReplyPacket_2.serialize();
// This packet reverses the MACs and IP from testARPReplyPacket_1
this.testUDPPacket = (Ethernet) new Ethernet()
.setSourceMACAddress("00:11:22:33:44:55")
.setDestinationMACAddress("00:44:33:22:11:01")
.setEtherType(EthType.IPv4)
.setVlanID((short)5)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setSourceAddress("192.168.1.2")
.setDestinationAddress("192.168.1.1")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
updateUDPPacketIn();
// This packet is used to test forming an entity from an IPv6 packet
this.testUDPIPv6Packet = (Ethernet) new Ethernet()
.setSourceMACAddress("00:11:22:33:44:55")
.setDestinationMACAddress("00:44:33:22:11:01")
.setEtherType(EthType.IPv6)
.setVlanID((short)5)
.setPayload(
new IPv6()
.setHopLimit((byte) 128)
.setSourceAddress(IPv6Address.of(1,1))
.setDestinationAddress(IPv6Address.of(2,2))
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
// This packet reverses the above
this.testUDPIPv6RevPacket = (Ethernet) new Ethernet()
.setSourceMACAddress("00:44:33:22:11:01")
.setDestinationMACAddress("00:11:22:33:44:55")
.setEtherType(EthType.IPv6)
.setVlanID((short)5)
.setPayload(
new IPv6()
.setHopLimit((byte) 128)
.setSourceAddress(IPv6Address.of(2,2))
.setDestinationAddress(IPv6Address.of(1,1))
.setPayload(new UDP()
.setSourcePort((short) 5001)
.setDestinationPort((short) 5000)
.setPayload(new Data(new byte[] {0x01}))));
// Build the PacketIn
this.testARPReplyPacketIn_1 = OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
.setBufferId(OFBufferId.NO_BUFFER)
.setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(1)).build())
.setData(this.testARPReplyPacket_1_Srld)
.setReason(OFPacketInReason.NO_MATCH)
.build();
// Build the PacketIn
this.testARPReplyPacketIn_2 = OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
.setBufferId(OFBufferId.NO_BUFFER)
.setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(1)).build())
.setData(this.testARPReplyPacket_2_Srld)
.setReason(OFPacketInReason.NO_MATCH)
.build();
this.testUDPIPv6PacketIn = OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
.setBufferId(OFBufferId.NO_BUFFER)
.setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(1)).build())
.setData(this.testUDPIPv6Packet.serialize())
.setReason(OFPacketInReason.NO_MATCH)
.build();
this.testUDPIPv6RevPacketIn = OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
.setBufferId(OFBufferId.NO_BUFFER)
.setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(1)).build())
.setData(this.testUDPIPv6RevPacket.serialize())
.setReason(OFPacketInReason.NO_MATCH)
.build();
}
/**
* Updates testUDPPacketIn and testUDPPacketSrld from testUDPPacket
* To be called after testUDPPacket has been mangled.
*/
private void updateUDPPacketIn() {
this.testUDPPacketSrld = this.testUDPPacket.serialize();
// Build the PacketIn
this.testUDPPacketIn = OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
.setBufferId(OFBufferId.NO_BUFFER)
.setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(3)).build())
.setData(this.testUDPPacketSrld)
.setReason(OFPacketInReason.NO_MATCH)
.build();
}
@Test
public void testLastSeen() throws Exception {
Calendar c = Calendar.getInstance();
Date d1 = c.getTime();
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO /* untagged*/, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, d1);
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO /* untagged*/, IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, 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 =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").atLeastOnce();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
deviceManager.entityClassifier= new MockEntityClassifier();
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(50L), OFPort.of(3), DatapathId.of(50L), OFPort.of(3))).
andReturn(true).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
deviceManager.topology = mockTopology;
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), new Date());
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), new Date());
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity5 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(2), new Date());
Entity entity6 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(50L), OFPort.of(3), new Date());
Entity entity7 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(50L), OFPort.of(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.getEntityClass());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d1.getVlanId());
assertArrayEquals(new IPv4Address[] { }, 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.getEntityClass());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d2.getVlanId());
assertArrayEquals(new IPv4Address[] { }, 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.getEntityClass());
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) },
d3.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) },
d3.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) },
d3.getAttachmentPoints(true));
assertArrayEquals(new VlanVid[] { VlanVid.ZERO },
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.getEntityClass());
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) },
d4.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) },
d4.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO },
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(DatapathId.of(5L), OFPort.of(2)) },
d5.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(4) },
d5.getVlanId());
assertEquals(MacAddress.of(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(DatapathId.of(50L), OFPort.of(3)) },
d6.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(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(DatapathId.of(50L), OFPort.of(3)) },
d7.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(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(MacAddress.of(5L), VlanVid.ofVlan(1), IPv4Address.of(5), IPv6Address.NONE, DatapathId.of(-1L), OFPort.of(1), new Date());
assertEquals(null, deviceManager.learnDeviceByEntity(entityNoClass));
verify(mockListener);
}
@Test
public void testEntityLearningIPv6() throws Exception {
IDeviceListener mockListener =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").atLeastOnce();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
deviceManager.entityClassifier= new MockEntityClassifier();
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(50L), OFPort.of(3), DatapathId.of(50L), OFPort.of(3))).
andReturn(true).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
deviceManager.topology = mockTopology;
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), new Date());
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.of(1, 1), DatapathId.of(10L), OFPort.of(1), new Date());
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.of(1, 1), DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity5 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(1, 1), DatapathId.of(5L), OFPort.of(2), new Date());
Entity entity6 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(1, 1), DatapathId.of(50L), OFPort.of(3), new Date());
Entity entity7 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(2, 2), DatapathId.of(50L), OFPort.of(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.getEntityClass());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d1.getVlanId());
assertArrayEquals(new IPv6Address[] { }, d1.getIPv6Addresses());
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.getEntityClass());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d2.getVlanId());
assertArrayEquals(new IPv6Address[] { }, d2.getIPv6Addresses());
assertEquals(2, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceIPV6AddrChanged(isA(IDevice.class));
replay(mockListener);
Device d3 = deviceManager.learnDeviceByEntity(entity3);
assertNotSame(d2, d3);
assertEquals(d2.getDeviceKey(), d3.getDeviceKey());
assertEquals(MockEntityClassifier.testEC, d3.getEntityClass());
assertArrayEquals(new IPv6Address[] { IPv6Address.of(1, 1) },
d3.getIPv6Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) },
d3.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) },
d3.getAttachmentPoints(true));
assertArrayEquals(new VlanVid[] { VlanVid.ZERO },
d3.getVlanId());
assertEquals(2, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceIPV6AddrChanged(isA(IDevice.class));
replay(mockListener);
Device d4 = deviceManager.learnDeviceByEntity(entity4);
assertNotSame(d1, d4);
assertEquals(d1.getDeviceKey(), d4.getDeviceKey());
assertEquals(DefaultEntityClassifier.entityClass, d4.getEntityClass());
assertArrayEquals(new IPv6Address[] { IPv6Address.of(1, 1) },
d4.getIPv6Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) },
d4.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO },
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(DatapathId.of(5L), OFPort.of(2)) },
d5.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(4) },
d5.getVlanId());
assertEquals(MacAddress.of(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(DatapathId.of(50L), OFPort.of(3)) },
d6.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(4) },
d6.getVlanId());
assertEquals(4, deviceManager.getAllDevices().size());
verify(mockListener);
reset(mockListener);
mockListener.deviceIPV6AddrChanged(isA(IDevice.class));
replay(mockListener);
Device d7 = deviceManager.learnDeviceByEntity(entity7);
assertNotSame(d6, d7);
assertEquals(d6.getDeviceKey(), d7.getDeviceKey());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(50L), OFPort.of(3)) },
d7.getAttachmentPoints());
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(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(MacAddress.of(5L), VlanVid.ofVlan(1), IPv4Address.NONE, IPv6Address.of(5, 5), DatapathId.of(-1L), OFPort.of(1), new Date());
assertEquals(null, deviceManager.learnDeviceByEntity(entityNoClass));
verify(mockListener);
}
private void doTestEntityOrdering(boolean computeInsertionPoint) throws Exception {
Entity e = new Entity(MacAddress.of(10L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, Entity.NO_DATE);
IEntityClass ec = createNiceMock(IEntityClass.class);
Device d = new Device(deviceManager, 1L, e, ec);
int expectedLength = 1;
Long[] macs = new Long[] { 5L, // new first element
15L, // new last element
7L, // insert in middle
12L, // insert in middle
6L, // insert at idx 1
14L, // insert at idx length-2
1L,
20L
};
for (Long mac: macs) {
e = new Entity(MacAddress.of(mac), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, Entity.NO_DATE);
int insertionPoint;
if (computeInsertionPoint) {
insertionPoint = -(Arrays.binarySearch(d.entities, e)+1);
} else {
insertionPoint = -1;
}
d = deviceManager.allocateDevice(d, e, insertionPoint);
expectedLength++;
assertEquals(expectedLength, d.entities.length);
for (int i = 0; i < d.entities.length-1; i++)
assertEquals(-1, d.entities[i].compareTo(d.entities[i+1]));
}
}
@Test
public void testEntityOrderingExternal() throws Exception {
doTestEntityOrdering(true);
}
@Test
public void testEntityOrderingInternal() throws Exception {
doTestEntityOrdering(false);
}
@Test
public void testAttachmentPointLearning() throws Exception {
IDeviceListener mockListener =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").atLeastOnce();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(1L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(5L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(10L))).
andReturn(DatapathId.of(10L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(50L))).
andReturn(DatapathId.of(10L)).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
andReturn(false).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()),
DatapathId.of(anyLong()))).andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(50L), OFPort.of(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(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
Entity entity0 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(50L), OFPort.of(1), c.getTime());
IDevice d;
SwitchPort[] aps;
IPv4Address[] 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(DatapathId.of(1L), OFPort.of(1)) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(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(DatapathId.of(5L), OFPort.of(1)) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(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(DatapathId.of(5L), OFPort.of(1)), new SwitchPort(DatapathId.of(10L), OFPort.of(1))}, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(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(DatapathId.of(5L), OFPort.of(1)),
new SwitchPort(DatapathId.of(50L), OFPort.of(1)) }, aps);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) }, ips);
verify(mockListener);
}
private void verifyEntityArray(Entity[] expected, Device d) {
Arrays.sort(expected);
assertArrayEquals(expected, d.entities);
}
@Test
public void testNoLearningOnInternalPorts() throws Exception {
IDeviceListener mockListener =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").anyTimes();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(1L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(2L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(3L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(4L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
.andReturn(false).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
.andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(or(eq(DatapathId.of(1L)), eq(DatapathId.of(3L))), OFPort.of(anyShort())))
.andReturn(true).anyTimes();
// Switches 2 and 4 have only internal ports
expect(mockTopology.isAttachmentPointPort(or(eq(DatapathId.of(2L)), eq(DatapathId.of(4L))), OFPort.of(anyShort())))
.andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(3L), OFPort.of(1)))
.andReturn(false).once();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Calendar c = Calendar.getInstance();
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(1), c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(3L), OFPort.of(1), c.getTime());
c.add(Calendar.SECOND, 1);
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(4), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(1), c.getTime());
IDevice d;
SwitchPort[] aps;
IPv4Address[] ips;
mockListener.deviceAdded(isA(IDevice.class));
expectLastCall().once();
replay(mockListener);
// cannot learn device internal ports
d = deviceManager.learnDeviceByEntity(entity2);
assertNull(d);
d = deviceManager.learnDeviceByEntity(entity4);
assertNull(d);
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity1 } , (Device)d);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) }, ips);
verify(mockListener);
reset(mockListener);
replay(mockListener);
// don't learn
d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity1 } , (Device)d);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) }, ips);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved(isA(IDevice.class));
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
replay(mockListener);
// learn
d = deviceManager.learnDeviceByEntity(entity3);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(3L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity1, entity3 } , (Device)d);
ips = d.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1), IPv4Address.of(3) }, ips);
verify(mockListener);
reset(mockListener);
replay(mockListener);
// don't learn
d = deviceManager.learnDeviceByEntity(entity4);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(3L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity1, entity3 } , (Device)d);
ips = d.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1), IPv4Address.of(3) }, ips);
verify(mockListener);
}
@Test
public void testAttachmentPointSuppression() throws Exception {
IDeviceListener mockListener =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").anyTimes();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(1L))). /* two different OpenFlow islands, 1 and 10 */
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(5L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(10L))).
andReturn(DatapathId.of(10L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(50L))).
andReturn(DatapathId.of(10L)).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
.andReturn(false).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
.andReturn(false).anyTimes();
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
.andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(50L), OFPort.of(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(DatapathId.of(1L), OFPort.of(1));
deviceManager.addSuppressAPs(DatapathId.of(10L), OFPort.of(1));
Calendar c = Calendar.getInstance();
/* OpenFlow island 1 */
Entity entity0 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, c.getTime());
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime()); /* suppressed */
c.add(Calendar.SECOND, 1);
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), c.getTime());
c.add(Calendar.SECOND, 1);
/* OpenFlow island 10 */
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), c.getTime()); /* suppressed */
c.add(Calendar.SECOND, 1);
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(50L), OFPort.of(1), c.getTime());
IDevice d;
SwitchPort[] aps;
IPv4Address[] ips;
/* When the device is first added we should expect an add event */
mockListener.deviceAdded(isA(IDevice.class));
/* It's also given an IPv4 address when the second entity is learned, so listeners should be notified */
mockListener.deviceIPV4AddrChanged((isA(IDevice.class)));
replay(mockListener);
/* Device is learned w/o attachment point */
deviceManager.learnDeviceByEntity(entity0);
/* Device is "seen" with a suppressed AP now, so we shouldn't learn the AP but still keep the entity */
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertEquals(aps.length, 0);
verifyEntityArray(new Entity[] { entity0 , entity1} , (Device)d);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(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(DatapathId.of(5L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity0, entity1, entity2 } , (Device)d);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) }, ips);
verify(mockListener);
reset(mockListener);
replay(mockListener);
d = deviceManager.learnDeviceByEntity(entity3);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(5L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity0, entity1, entity2, entity3 } , (Device)d);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(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(DatapathId.of(5L), OFPort.of(1)),
new SwitchPort(DatapathId.of(50L), OFPort.of(1)) }, aps);
verifyEntityArray(new Entity[] { entity0, entity1, entity2, entity3, entity4} , (Device)d);
ips = d.getIPv4Addresses();
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1) }, ips);
verify(mockListener);
}
@Test
public void testBDAttachmentPointLearning() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(2))).
andReturn(true).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(1L), DatapathId.of(1L))).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(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(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
c.add(Calendar.MILLISECOND,
(int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT/ 2);
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), c.getTime());
c.add(Calendar.MILLISECOND,
(int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT / 2 + 1);
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), c.getTime());
IDevice d;
SwitchPort[] aps;
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(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(DatapathId.of(1L), OFPort.of(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(DatapathId.of(1L), OFPort.of(2)) }, aps);
}
/**
* This test verifies that the learning behavior on OFPP_LOCAL ports.
* Once a host is learned on OFPP_LOCAL, it is allowed to move only from
* one OFPP_LOCAL to another OFPP_LOCAL port.
* @throws Exception
*/
@Test
public void testLOCALAttachmentPointLearning() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.LOCAL)).
andReturn(false).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(2))).
andReturn(true).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(1L), DatapathId.of(1L))).andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(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(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
c.add(Calendar.MILLISECOND,
(int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT/ 2);
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.LOCAL, c.getTime());
c.add(Calendar.MILLISECOND,
(int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT + 1);
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), c.getTime());
IDevice d;
SwitchPort[] aps;
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, aps);
// Ensure that the attachment point changes to OFPP_LOCAL
d = deviceManager.learnDeviceByEntity(entity2);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.LOCAL) }, aps);
// Even though the new attachment point is consistent with old
// and the time has elapsed, OFPP_LOCAL attachment point should
// be maintained.
d = deviceManager.learnDeviceByEntity(entity3);
assertEquals(1, deviceManager.getAllDevices().size());
aps = d.getAttachmentPoints();
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.LOCAL) }, aps);
}
private static void
mockTopologyForPacketInTests(ITopologyService mockTopology) {
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).
anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()),
DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()))).andReturn(false).
anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()),
DatapathId.of(anyLong())))
.andReturn(false).anyTimes();
}
private Command dispatchPacketIn(long swId, OFPacketIn pi,
FloodlightContext cntx) {
IOFSwitch sw = getMockSwitchService().getSwitch(DatapathId.of(swId));
Ethernet eth = new Ethernet();
eth.deserialize(pi.getData(), 0, pi.getData().length);
IFloodlightProviderService.bcStore.put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
eth);
return deviceManager.receive(sw, pi, cntx);
}
/**
* Verify that the given device exactly matches the given fields. E.g.,
* if ip is not null we expect the device to have exactly one IP address.
* swId and port are the attachment point port.
* Vlan and ip are optional all other fields must be specified.
* @return
*/
private static void verifyDevice(IDevice d, MacAddress mac, VlanVid vlan, IPv4Address ipv4,
IPv6Address ipv6, DatapathId swId, OFPort port) {
assertNotNull(d);
if (!mac.equals(MacAddress.NONE)) {
assertEquals(mac, d.getMACAddress());
}
if (vlan != null) {
assertArrayEquals(new VlanVid[] { vlan }, d.getVlanId());
}
if (!ipv4.equals(IPv4Address.NONE)) {
assertArrayEquals(new IPv4Address[] { ipv4 }, d.getIPv4Addresses());
}
if (!ipv6.equals(IPv6Address.NONE)) {
assertArrayEquals(new IPv6Address[] { ipv6 }, d.getIPv6Addresses());
}
if (!swId.equals(DatapathId.NONE) && !port.equals(OFPort.ZERO)) {
SwitchPort expectedAp = new SwitchPort(swId, port);
assertArrayEquals(new SwitchPort[] { expectedAp }, d.getAttachmentPoints());
}
}
@Test
@org.junit.Ignore /* TODO figure out why this fails periodically */
public void testPacketInBasic() throws Exception {
MacAddress deviceMac =
((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress();
OFPacketIn packetIn = testARPReplyPacketIn_1;
IPv4Address ipaddr = IPv4Address.of("192.168.1.1");
// Mock up our expected behavior
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
FloodlightContext cntx = new FloodlightContext();
Command cmd = dispatchPacketIn(1L, packetIn, cntx);
verify(mockTopology);
assertEquals(Command.CONTINUE, cmd);
// Verify the device
Device rdevice = (Device)
deviceManager.findDevice(deviceMac,
VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(rdevice, deviceMac, VlanVid.ofVlan(5), ipaddr, IPv6Address.NONE, DatapathId.of(1), OFPort.of(1));
IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(rdevice, cntxSrcDev);
IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
Device result = null;
Iterator<? extends IDevice> dstiter =
deviceManager.queryDevices(MacAddress.NONE, null /* any VLAN here */, ipaddr,
IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
if (dstiter.hasNext()) {
result = (Device)dstiter.next();
}
assertFalse("There shouldn't be more than 1 device", dstiter.hasNext());
assertEquals(rdevice, result);
//-----------------
// Test packetIn again with a different source port. Should be
// the same device
reset(mockTopology);
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
// trigger the packet in
cntx = new FloodlightContext();
packetIn = packetIn.createBuilder().setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(2)).build()).build();
cmd = dispatchPacketIn(5L, packetIn, cntx);
verify(mockTopology);
// Verify the replay matched our expectations
assertEquals(Command.CONTINUE, cmd);
// Verify the device
rdevice = (Device)
deviceManager.findDevice(deviceMac,
VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(rdevice, deviceMac, VlanVid.ofVlan(5), ipaddr, IPv6Address.NONE, DatapathId.of(5), OFPort.of(2)); //TODO periodic failure
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(rdevice, cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
// There can be only one device
assertEquals(1, deviceManager.getAllDevices().size());
//----------------------------
// Test packetIn with a different packet going the reverse direction.
// We should now get source and dest device in the context
//==> The destination device in this step has been learned just before
MacAddress srcMac = testUDPPacket.getSourceMACAddress();
MacAddress dstMac = deviceMac;
reset(mockTopology);
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
// trigger the packet in
cntx = new FloodlightContext();
cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
verify(mockTopology);
assertEquals(Command.CONTINUE, cmd);
IDevice srcDev =
deviceManager.findDevice(srcMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(srcDev, srcMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1), testUDPPacketIn.getMatch().get(MatchField.IN_PORT));
IDevice dstDev =
deviceManager.findDevice(dstMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(dstDev, dstMac, VlanVid.ofVlan(5), ipaddr, IPv6Address.NONE, DatapathId.of(5), OFPort.of(2));
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(srcDev, cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertEquals(dstDev, cntxDstDev);
assertEquals(2, deviceManager.getAllDevices().size());
}
@Test
@org.junit.Ignore /* TODO figure out why this fails periodically */
public void testPacketInBasicIPv6() throws Exception {
MacAddress deviceMac =
((Ethernet)this.testUDPIPv6Packet).getSourceMACAddress();
OFPacketIn packetIn = testUDPIPv6PacketIn;
IPv6Address ipaddr = IPv6Address.of(1, 1);
// Mock up our expected behavior
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
FloodlightContext cntx = new FloodlightContext();
Command cmd = dispatchPacketIn(1L, packetIn, cntx);
verify(mockTopology);
assertEquals(Command.CONTINUE, cmd);
// Verify the device
Device rdevice = (Device)
deviceManager.findDevice(deviceMac,
VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(rdevice, deviceMac, VlanVid.ofVlan(5), IPv4Address.NONE, ipaddr, DatapathId.of(1), OFPort.of(1));
IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(rdevice, cntxSrcDev);
IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
Device result = null;
Iterator<? extends IDevice> dstiter =
deviceManager.queryDevices(MacAddress.NONE, null /* any VLAN here */, IPv4Address.NONE,
ipaddr, DatapathId.NONE, OFPort.ZERO);
if (dstiter.hasNext()) {
result = (Device)dstiter.next();
}
assertFalse("There shouldn't be more than 1 device", dstiter.hasNext());
assertEquals(rdevice, result);
//-----------------
// Test packetIn again with a different source port. Should be
// the same device
reset(mockTopology);
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
// trigger the packet in
cntx = new FloodlightContext();
packetIn = packetIn.createBuilder().setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch().setExact(MatchField.IN_PORT, OFPort.of(2)).build()).build();
cmd = dispatchPacketIn(5L, packetIn, cntx);
verify(mockTopology);
// Verify the replay matched our expectations
assertEquals(Command.CONTINUE, cmd);
// Verify the device
rdevice = (Device)
deviceManager.findDevice(deviceMac,
VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(rdevice, deviceMac, VlanVid.ofVlan(5), IPv4Address.NONE, ipaddr, DatapathId.of(5), OFPort.of(2)); //TODO periodic failure
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(rdevice, cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
// There can be only one device
assertEquals(1, deviceManager.getAllDevices().size());
//----------------------------
// Test packetIn with a different packet going the reverse direction.
// We should now get source and dest device in the context
//==> The destination device in this step has been learned just before
MacAddress srcMac = testUDPIPv6RevPacket.getSourceMACAddress();
MacAddress dstMac = deviceMac;
reset(mockTopology);
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
// trigger the packet in
cntx = new FloodlightContext();
cmd = dispatchPacketIn(1L, testUDPIPv6RevPacketIn, cntx);
verify(mockTopology);
assertEquals(Command.CONTINUE, cmd);
IDevice srcDev =
deviceManager.findDevice(srcMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(srcDev, srcMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1), testUDPIPv6PacketIn.getMatch().get(MatchField.IN_PORT));
IDevice dstDev =
deviceManager.findDevice(dstMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(dstDev, dstMac, VlanVid.ofVlan(5), IPv4Address.NONE, ipaddr, DatapathId.of(5), OFPort.of(2));
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(srcDev, cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertEquals(dstDev, cntxDstDev);
assertEquals(2, deviceManager.getAllDevices().size());
}
/**
* This test ensures the device manager learns the source device
* corresponding to the senderHardwareAddress and senderProtocolAddress
* in an ARP response whenever the senderHardwareAddress is different
* from the source MAC address of the Ethernet frame.
*
* @throws Exception
*/
@Test
public void testDeviceLearningFromArpResponseData() throws Exception {
ARP arp = (ARP)((Ethernet)this.testARPReplyPacket_2).getPayload();
MacAddress senderMac = arp.getSenderHardwareAddress();
MacAddress sourceMac =
((Ethernet)this.testARPReplyPacket_2)
.getSourceMACAddress();
IPv4Address ipaddr = IPv4Address.of("192.168.1.1");
OFPacketIn packetIn = testARPReplyPacketIn_2;
// Mock up our expected behavior
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
FloodlightContext cntx = new FloodlightContext();
Command cmd = dispatchPacketIn(1L, packetIn, cntx);
verify(mockTopology);
assertEquals(Command.CONTINUE, cmd);
// Verify the device for the sender HW address
IDevice senderDev = (Device)
deviceManager.findDevice(senderMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
verifyDevice(senderDev, senderMac, VlanVid.ofVlan(5), ipaddr, IPv6Address.NONE, DatapathId.of(1), OFPort.of(1));
IDevice result = null;
Iterator<? extends IDevice> dstiter =
deviceManager.queryDevices(MacAddress.NONE, null /* any VLAN here */, ipaddr,
IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
if (dstiter.hasNext()) {
result = (Device)dstiter.next();
}
assertFalse("There shouldn't be more than 1 device", dstiter.hasNext());
assertEquals(senderDev, result);
// Verify the device for the source MAC
IDevice srcDev = (Device)
deviceManager.findDevice(sourceMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
// must NOT learn IP on this device
verifyDevice(srcDev, sourceMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.of(1));
assertFalse("Device must differ", srcDev.equals(senderDev));
// Context is annotated with this device, not the device associated
// with ARP sender address
IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(srcDev, cntxSrcDev);
assertEquals(2, deviceManager.getAllDevices().size());
}
@Test
public void testPacketInInvalidSrcMac() throws Exception {
// Mock up our expected behavior
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
FloodlightContext cntx = new FloodlightContext();
testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(0L));
updateUDPPacketIn();
Command cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.STOP, cmd);
IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertNull(cntxSrcDev);
IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(-1L));
updateUDPPacketIn();
cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.STOP, cmd);
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertNull(cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
// MAC with only the multicast bit set
testUDPPacket.setSourceMACAddress(new byte[] { 1, 0, 0, 0, 0, 0 });
updateUDPPacketIn();
cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.STOP, cmd);
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertNull(cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
// Now use a real MAC. We should get a src device
testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(1L));
updateUDPPacketIn();
cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.CONTINUE, cmd);
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
verifyDevice(cntxSrcDev, MacAddress.of(1), VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1), testUDPPacketIn.getMatch().get(MatchField.IN_PORT));
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
verify(mockTopology);
}
@Test
public void testPacketInInvalidDstMac() throws Exception {
// Mock up our expected behavior
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
mockTopologyForPacketInTests(mockTopology);
replay(mockTopology);
FloodlightContext cntx = new FloodlightContext();
MacAddress srcMac = testUDPPacket.getSourceMACAddress();
MacAddress dstMac = testUDPPacket.getDestinationMACAddress();
// Prime device manager with the source device
Command cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.CONTINUE, cmd);
IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
verifyDevice(cntxSrcDev, srcMac, VlanVid.ofVlan(5), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1), testUDPPacketIn.getMatch().get(MatchField.IN_PORT));
IDevice cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
IDevice expectedSrcDev = cntxSrcDev;
// Create a device for the destination. We can use testARPPacketIn_1
// for that.
cntx = new FloodlightContext();
// Prime device manager with the source device
cmd = dispatchPacketIn(1L, testARPReplyPacketIn_1, cntx);
assertEquals(Command.CONTINUE, cmd);
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
// yes: we check that cntxSrcDev matched dstMAC because we are
// just adding the dest device
IPv4Address ip = IPv4Address.of("192.168.1.1");
verifyDevice(cntxSrcDev, dstMac, VlanVid.ofVlan(5), ip, IPv6Address.NONE, DatapathId.of(1), testARPReplyPacketIn_1.getMatch().get(MatchField.IN_PORT));
// yes: we set the expected dst device to the current srcDev
IDevice expectedDstDev = cntxSrcDev;
//-------------------------------
// Let the real tests begin
cntx = new FloodlightContext();
testUDPPacket.setDestinationMACAddress(Ethernet.toByteArray(0L));
updateUDPPacketIn();
cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.STOP, cmd);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertNull(cntxDstDev);
// use a real dest mac
cntx = new FloodlightContext();
testUDPPacket.setDestinationMACAddress(dstMac);
updateUDPPacketIn();
cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx);
assertEquals(Command.CONTINUE, cmd);
cntxSrcDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
assertEquals(expectedSrcDev, cntxSrcDev);
cntxDstDev = IDeviceService.fcStore.get(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
assertEquals(expectedDstDev, cntxDstDev);
verify(mockTopology);
}
/**
* Note: Entity expiration does not result in device moved notification.
* @throws Exception
*/
public void doTestEntityExpiration() throws Exception {
IDeviceListener mockListener =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").anyTimes();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(1))).andReturn(false).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(5L), OFPort.of(1))).andReturn(false).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); /* different islands */
expect(mockTopology.getClusterId(DatapathId.of(5L))).andReturn(DatapathId.of(5L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Calendar c = Calendar.getInstance();
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); /* go back in time s.t. entity1 is 1ms away from timing out WRT entity2 */
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), c.getTime());
deviceManager.learnDeviceByEntity(entity1);
IDevice d = deviceManager.learnDeviceByEntity(entity2); /* learn entity2 from "the past." */
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1), IPv4Address.of(2) }, d.getIPv4Addresses());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(1))},
d.getAttachmentPoints());
Iterator<? extends IDevice> diter =
deviceManager.queryClassDevices(d.getEntityClass(),
MacAddress.NONE, VlanVid.ZERO /* untagged here */, IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertTrue(diter.hasNext());
assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
diter = deviceManager.queryClassDevices(d.getEntityClass(),
MacAddress.NONE, VlanVid.ZERO /* untagged here */, IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertTrue(diter.hasNext());
assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
mockListener.deviceMoved(isA(IDevice.class)); /* the device really should move, since it's losing an attachment point along with having its DPID changed */
mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
replay(mockListener);
deviceManager.entityCleanupTask.reschedule(0, null);
d = deviceManager.getDevice(d.getDeviceKey());
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d.getIPv4Addresses());
// Attachment points are not removed, previous ones are still valid.
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(1)) },
d.getAttachmentPoints());
diter = deviceManager.queryClassDevices(d.getEntityClass(),
MacAddress.NONE, VlanVid.ZERO /* untagged here */, IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertTrue(diter.hasNext());
assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
diter = deviceManager.queryClassDevices(d.getEntityClass(),
MacAddress.NONE, VlanVid.ZERO /* untagged here */, IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertFalse(diter.hasNext());
d = deviceManager.findDevice(MacAddress.of(1L), VlanVid.ZERO /* untagged here */, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d.getIPv4Addresses());
// Attachment points are not removed, previous ones are still valid.
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(1)) },
d.getAttachmentPoints());
verify(mockListener);
}
public void doTestDeviceExpiration() throws Exception {
IDeviceListener mockListener =
createMock(IDeviceListener.class);
expect(mockListener.getName()).andReturn("mockListener").anyTimes();
expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject()))
.andReturn(false).atLeastOnce();
Calendar c = Calendar.getInstance();
c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1);
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), c.getTime());
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()))).
andReturn(true).
anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(5L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()),
DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()))).andReturn(false).
anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()))).
andReturn(false).anyTimes();
replay(mockTopology);
IDevice d = deviceManager.learnDeviceByEntity(entity2);
d = deviceManager.learnDeviceByEntity(entity1);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(1), IPv4Address.of(2) }, d.getIPv4Addresses());
replay(mockListener);
deviceManager.addListener(mockListener);
verify(mockListener);
reset(mockListener);
mockListener.deviceRemoved(isA(IDevice.class));
replay(mockListener);
deviceManager.entityCleanupTask.reschedule(0, null);
IDevice r = deviceManager.getDevice(d.getDeviceKey());
assertNull(r);
Iterator<? extends IDevice> diter =
deviceManager.queryClassDevices(d.getEntityClass(),
MacAddress.NONE, VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertFalse(diter.hasNext());
r = deviceManager.findDevice(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
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.
// clone entities
Device newDevice = d;
for (Entity e: d.getEntities()) {
Entity newEntity = new Entity (e.macAddress,
e.vlan,
e.ipv4Address,
e.ipv6Address,
e.switchDPID,
e.switchPort,
e.lastSeenTimestamp);
if (newEntity.vlan.equals(VlanVid.ZERO)) {
newEntity.vlan = VlanVid.ofVlan(1);
} else {
newEntity.vlan = VlanVid.ofVlan((e.vlan.getVlan() + 1 % 4095) + 1);
}
newDevice = new Device(newDevice, newEntity, -1);
}
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(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(false).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
.andReturn(false).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))).
andReturn(true).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(10L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(10L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
/* All w/same activeSince stamp, c.getTime() */
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
Entity entity1a = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), c.getTime());
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), c.getTime());
entity1.setLastSeenTimestamp(c.getTime()); /* same as activeSince */
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2);
entity1a.setLastSeenTimestamp(c.getTime()); /* halfway timed out for entity1 */
c.add(Calendar.MILLISECOND, 1);
entity2.setLastSeenTimestamp(c.getTime()); /* small increment; still below entity1 timeout */
c.add(Calendar.MILLISECOND, 1);
entity3.setLastSeenTimestamp(c.getTime()); /* small increment; still below entity1 timeout */
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(DatapathId.of(10L), OFPort.of(1)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)),},
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4);
entity1.setLastSeenTimestamp(c.getTime()); /* entity1 now is 3/4 the way to a timeout, but still is active */
d = deviceManager.learnDeviceByEntity(entity1); /* we're going back to an old AP here within its active window (the "flapping") */
// all are still active; entity3 should still win
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(1),
ErrorStatus.DUPLICATE_DEVICE),
new SwitchPort(DatapathId.of(1L), OFPort.of(1),
ErrorStatus.DUPLICATE_DEVICE) },
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+2000);
entity1.setLastSeenTimestamp(c.getTime()); /* now "relearn" entity1 for a time beyond all others' timeouts; thus entity1 should be the only remaining AP */
d = deviceManager.learnDeviceByEntity(entity1);
assertEquals(entity1.getActiveSince(), entity1.getLastSeenTimestamp());
// entity1 should now be the only active entity
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) },
d.getAttachmentPoints(true));
}
@Test
public void testAttachmentPointFlappingTwoCluster() throws Exception {
Calendar c = Calendar.getInstance();
ITopologyService mockTopology = createMock(ITopologyService.class);
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(false).anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
.andReturn(false).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(1L))).
andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(5L))).
andReturn(DatapathId.of(5L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(2))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(2), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(1), DatapathId.of(5L), OFPort.of(2))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(2), DatapathId.of(1L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(2))).
andReturn(false).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(5L), OFPort.of(2), DatapathId.of(5L), OFPort.of(1))).
andReturn(false).anyTimes();
Date topologyUpdateTime = new Date();
expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
anyTimes();
replay(mockTopology);
deviceManager.topology = mockTopology;
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), c.getTime());
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), c.getTime());
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), c.getTime());
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(5L), OFPort.of(2), c.getTime());
entity1.setLastSeenTimestamp(c.getTime());
c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2);
c.add(Calendar.MILLISECOND, 1);
entity2.setLastSeenTimestamp(c.getTime());
c.add(Calendar.MILLISECOND, 1);
entity3.setLastSeenTimestamp(c.getTime());
c.add(Calendar.MILLISECOND, 1);
entity4.setLastSeenTimestamp(c.getTime());
deviceManager.learnDeviceByEntity(entity1);
deviceManager.learnDeviceByEntity(entity2);
deviceManager.learnDeviceByEntity(entity3);
IDevice d = deviceManager.learnDeviceByEntity(entity4);
// all entities are active, so entities 2,4 should win
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(2)),
new SwitchPort(DatapathId.of(5L), OFPort.of(2)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(2)),
new SwitchPort(DatapathId.of(5L), OFPort.of(2))},
d.getAttachmentPoints(true));
c.add(Calendar.MILLISECOND, 1);
entity1.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity1);
// all entities are active, so entities 2,4 should win
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(2)),
new SwitchPort(DatapathId.of(5L), OFPort.of(2)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(2)),
new SwitchPort(DatapathId.of(5L), OFPort.of(2)),
new SwitchPort(DatapathId.of(1L), OFPort.of(1), 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(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(2)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(2))},
d.getAttachmentPoints(true));
entity3.setLastSeenTimestamp(c.getTime());
d = deviceManager.learnDeviceByEntity(entity3);
// no conflicts, 1 and 3 will win
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(1)) },
d.getAttachmentPoints());
assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)),
new SwitchPort(DatapathId.of(5L), OFPort.of(1)) },
d.getAttachmentPoints(true));
}
protected void doTestDeviceQuery() throws Exception {
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), new Date());
Entity entity3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), new Date());
Entity entity4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(2), new Date());
Entity entity5 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(4), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(2), new Date());
Device d1 = deviceManager.learnDeviceByEntity(entity1);
deviceManager.learnDeviceByEntity(entity2);
Device d3 = deviceManager.learnDeviceByEntity(entity3);
Device d4 = deviceManager.learnDeviceByEntity(entity4);
IDevice d;
Iterator<? extends IDevice> iter =
deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
int count = 0;
while (iter.hasNext()) {
count += 1;
d = iter.next();
assertEquals(d1.getDeviceKey(), d.getDeviceKey());
}
assertEquals(1, count);
iter = deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
while (iter.hasNext()) {
count += 1;
d = iter.next();
assertEquals(d3.getDeviceKey(), d.getDeviceKey());
}
assertEquals(1, count);
iter = deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(1), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(0, count);
Device d5 = deviceManager.learnDeviceByEntity(entity5);
iter = deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(4), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
Set<Long> deviceKeysFromIterator = new HashSet<Long>();
while (iter.hasNext()) {
count += 1;
d = iter.next();
deviceKeysFromIterator.add(d.getDeviceKey());
}
Set<Long> expectedDeviceKeys = new HashSet<Long>();
expectedDeviceKeys.add(d4.getDeviceKey());
expectedDeviceKeys.add(d5.getDeviceKey());
assertEquals(expectedDeviceKeys, deviceKeysFromIterator);
assertEquals(2, count);
iter = deviceManager.queryDevices(MacAddress.of(1L), null /* don't care (want 1 and 4) NOT VlanVid.ZERO-->untagged */,
IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
deviceKeysFromIterator = new HashSet<Long>();
while (iter.hasNext()) {
count += 1;
d = iter.next();
deviceKeysFromIterator.add(d.getDeviceKey());
}
expectedDeviceKeys = new HashSet<Long>();
expectedDeviceKeys.add(d1.getDeviceKey());
expectedDeviceKeys.add(d5.getDeviceKey());
assertEquals(expectedDeviceKeys, deviceKeysFromIterator);
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);
indexFields = EnumSet.noneOf(IDeviceService.DeviceField.class);
deviceManager.addIndex(false, indexFields);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
replay(mockTopology);
doTestDeviceQuery();
}
@Test
public void testDeviceQuery() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
replay(mockTopology);
doTestDeviceQuery();
}
protected void doTestDeviceClassQuery() throws Exception {
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), new Date());
Entity entity3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(1), new Date());
Entity entity4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(2), new Date());
Entity entity5 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(4), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(5L), OFPort.of(2), new Date());
IDevice d1 = deviceManager.learnDeviceByEntity(entity1);
IDevice d2 = deviceManager.learnDeviceByEntity(entity2);
IDevice d3 = deviceManager.learnDeviceByEntity(entity3);
IDevice d4 = deviceManager.learnDeviceByEntity(entity4);
assertEquals(d1.getEntityClass(), d2.getEntityClass());
assertEquals(d1.getEntityClass(), d3.getEntityClass());
assertEquals(d1.getEntityClass(), d4.getEntityClass());
IDevice d;
Iterator<? extends IDevice> iter =
deviceManager.queryClassDevices(d1.getEntityClass(), MacAddress.NONE,
VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
int count = 0;
while (iter.hasNext()) {
count += 1;
d = iter.next();
assertEquals(d1.getDeviceKey(), d.getDeviceKey());
}
assertEquals(1, count);
iter = deviceManager.queryClassDevices(d1.getEntityClass(), MacAddress.NONE,
VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
while (iter.hasNext()) {
count += 1;
d = iter.next();
assertEquals(d3.getDeviceKey(), d.getDeviceKey());
}
assertEquals(1, count);
iter = deviceManager.queryClassDevices(d1.getEntityClass(), MacAddress.NONE,
VlanVid.ofVlan(1), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
while (iter.hasNext()) {
count += 1;
iter.next();
}
assertEquals(0, count);
IDevice d5 = deviceManager.learnDeviceByEntity(entity5);
assertEquals(d1.getEntityClass(), d5.getEntityClass());
iter = deviceManager.queryClassDevices(d1.getEntityClass(), MacAddress.NONE,
VlanVid.ofVlan(4), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
count = 0;
Set<Long> deviceKeysFromIterator = new HashSet<Long>();
while (iter.hasNext()) {
count += 1;
d = iter.next();
deviceKeysFromIterator.add(d.getDeviceKey());
}
Set<Long> expectedDeviceKeys = new HashSet<Long>();
expectedDeviceKeys.add(d4.getDeviceKey());
expectedDeviceKeys.add(d5.getDeviceKey());
assertEquals(expectedDeviceKeys, deviceKeysFromIterator);
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(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
replay(mockTopology);
doTestDeviceClassQuery();
}
@Test
public void testDeviceClassQuery() throws Exception {
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
replay(mockTopology);
doTestDeviceClassQuery();
}
@Test
public void testFindDevice() throws FloodlightModuleException {
boolean exceptionCaught;
deviceManager.entityClassifier= new MockEntityClassifierMac();
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
replay(mockTopology);
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), new Date());
Entity entity2b = new Entity(MacAddress.of(22L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(2), new Date());
Entity entity3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(1), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(1), new Date());
Entity entity4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(2), IPv4Address.of(4), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(2), new Date());
Entity entity5 = new Entity(MacAddress.of(5L), VlanVid.ofVlan(1), IPv4Address.of(5), IPv6Address.NONE, DatapathId.of(3L), OFPort.of(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.getIpv6Address(),
entity1.getSwitchDPID(),
entity1.getSwitchPort()));
// port changed. Device will be found through class index
assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(),
entity1.getVlan(),
entity1.getIpv4Address(),
entity1.getIpv6Address(),
entity1.getSwitchDPID(),
OFPort.of(entity1.getSwitchPort().getPortNumber()+1)));
// VLAN changed. No device matches
assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(),
VlanVid.ofVlan(42),
entity1.getIpv4Address(),
entity1.getIpv6Address(),
entity1.getSwitchDPID(),
entity1.getSwitchPort()));
assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(),
VlanVid.ZERO,
entity1.getIpv4Address(),
entity1.getIpv6Address(),
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.getIpv6Address(),
entity3.getSwitchDPID(),
entity3.getSwitchPort()));
// switch and port not set. throws exception
exceptionCaught = false;
try {
assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(),
entity3.getVlan(),
entity3.getIpv4Address(),
entity3.getIpv6Address(),
DatapathId.NONE,
OFPort.ZERO));
}
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.getIpv6Address(),
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(),
entity5.getIpv6Address(),
DatapathId.NONE,
OFPort.ZERO));
}
catch (IllegalArgumentException e) {
exceptionCaught = true;
}
if (!exceptionCaught)
fail("findDevice() did not throw IllegalArgumentException");
Entity entityNoClass = new Entity(MacAddress.of(5L), VlanVid.ofVlan(1), IPv4Address.of(5), IPv6Address.NONE, DatapathId.of(-1L), OFPort.of(1), new Date());
assertEquals(null, deviceManager.findDeviceByEntity(entityNoClass));
// Now look up destination devices
assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(),
entity1.getMacAddress(),
entity1.getVlan(),
entity1.getIpv4Address(),
entity1.getIpv6Address()));
assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(),
entity1.getMacAddress(),
entity1.getVlan(),
IPv4Address.NONE,
entity1.getIpv6Address()));
assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(),
entity1.getMacAddress(),
VlanVid.ZERO,
IPv4Address.NONE,
entity1.getIpv6Address()));
}
@Test
public void testGetIPv4Addresses() {
// Looks like Date is only 1s granularity
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()),
DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(EasyMock.anyLong()),
DatapathId.of(EasyMock.anyLong()))).
andReturn(false).anyTimes();
replay(mockTopology);
Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(2000));
Device d1 = deviceManager.learnDeviceByEntity(e1);
assertArrayEquals(new IPv4Address[0], d1.getIPv4Addresses());
Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(2000));
Device d2 = deviceManager.learnDeviceByEntity(e2);
d2 = deviceManager.learnDeviceByEntity(e2);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses());
// More than one entity
Entity e2b = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(2L), OFPort.of(2), new Date(3000));
d2 = deviceManager.learnDeviceByEntity(e2b);
assertEquals(2, d2.entities.length);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses());
// and now add an entity with an IP
Entity e2c = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(3), new Date(3000));
d2 = deviceManager.learnDeviceByEntity(e2c);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses());
assertEquals(3, d2.entities.length);
// Other devices with different IPs shouldn't interfere
Entity e3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(4000));
Entity e3b = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(3L), OFPort.of(3), new Date(4400));
Device d3 = deviceManager.learnDeviceByEntity(e3);
d3 = deviceManager.learnDeviceByEntity(e3b);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses());
assertArrayEquals(new IPv4Address[] { IPv4Address.of(3) }, d3.getIPv4Addresses());
// Add another IP to d3
Entity e3c = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(33), IPv6Address.NONE, DatapathId.of(3L), OFPort.of(3), new Date(4400));
d3 = deviceManager.learnDeviceByEntity(e3c);
IPv4Address[] ips = d3.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(3), IPv4Address.of(33) }, ips);
// Add another device that also claims IP2 but is older than e2
Entity e4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(1000));
Entity e4b = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(4), new Date(1000));
Device d4 = deviceManager.learnDeviceByEntity(e4);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d2.getIPv4Addresses());
assertArrayEquals(new IPv4Address[0], d4.getIPv4Addresses());
// add another entity to d4
d4 = deviceManager.learnDeviceByEntity(e4b);
assertArrayEquals(new IPv4Address[0], d4.getIPv4Addresses());
// Make e4 and e4a newer
Entity e4c = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(5000));
Entity e4d = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(5000));
d4 = deviceManager.learnDeviceByEntity(e4c);
d4 = deviceManager.learnDeviceByEntity(e4d);
assertArrayEquals(new IPv4Address[0], d2.getIPv4Addresses());
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d4.getIPv4Addresses());
// Add another newer entity to d2 but with different IP
Entity e2d = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(22), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(6), new Date(6000));
d2 = deviceManager.learnDeviceByEntity(e2d);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(22) }, d2.getIPv4Addresses());
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2) }, d4.getIPv4Addresses());
// new IP for d2,d4 but with same timestamp. Both devices get the IP
Entity e2e = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(42), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(4), new Date(7000));
d2 = deviceManager.learnDeviceByEntity(e2e);
ips= d2.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(22), IPv4Address.of(42) }, ips);
Entity e4e = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(42), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(7), new Date(7000));
d4 = deviceManager.learnDeviceByEntity(e4e);
ips= d4.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2), IPv4Address.of(42) }, ips);
// add a couple more IPs
Entity e2f = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(4242), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(5), new Date(8000));
d2 = deviceManager.learnDeviceByEntity(e2f);
ips= d2.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(22), IPv4Address.of(42), IPv4Address.of(4242) }, ips);
Entity e4f = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(4242), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(8), new Date(9000));
d4 = deviceManager.learnDeviceByEntity(e4f);
ips= d4.getIPv4Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv4Address[] { IPv4Address.of(2), IPv4Address.of(42), IPv4Address.of(4242) }, ips);
}
@Test
public void testGetIPv6Addresses() {
// Looks like Date is only 1s granularity
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()),
DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
expect(mockTopology.isInSameArchipelago(DatapathId.of(EasyMock.anyLong()),
DatapathId.of(EasyMock.anyLong()))).
andReturn(false).anyTimes();
replay(mockTopology);
Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(2000));
Device d1 = deviceManager.learnDeviceByEntity(e1);
assertArrayEquals(new IPv6Address[0], d1.getIPv6Addresses());
Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.of(2, 2), DatapathId.NONE, OFPort.ZERO, new Date(2000));
Device d2 = deviceManager.learnDeviceByEntity(e2);
d2 = deviceManager.learnDeviceByEntity(e2);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d2.getIPv6Addresses());
// More than one entity
Entity e2b = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(2L), OFPort.of(2), new Date(3000));
d2 = deviceManager.learnDeviceByEntity(e2b);
assertEquals(2, d2.entities.length);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d2.getIPv6Addresses());
// and now add an entity with an IP
Entity e2c = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.of(2, 2), DatapathId.of(2L), OFPort.of(3), new Date(3000));
d2 = deviceManager.learnDeviceByEntity(e2c);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d2.getIPv6Addresses());
assertEquals(3, d2.entities.length);
// Other devices with different IPs shouldn't interfere
Entity e3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.NONE, IPv6Address.of(3, 3), DatapathId.NONE, OFPort.ZERO, new Date(4000));
Entity e3b = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.NONE, IPv6Address.of(3, 3), DatapathId.of(3L), OFPort.of(3), new Date(4400));
Device d3 = deviceManager.learnDeviceByEntity(e3);
d3 = deviceManager.learnDeviceByEntity(e3b);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d2.getIPv6Addresses());
assertArrayEquals(new IPv6Address[] { IPv6Address.of(3, 3) }, d3.getIPv6Addresses());
// Add another IP to d3
Entity e3c = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.NONE, IPv6Address.of(33, 33), DatapathId.of(3L), OFPort.of(3), new Date(4400));
d3 = deviceManager.learnDeviceByEntity(e3c);
IPv6Address[] ips = d3.getIPv6Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(3, 3), IPv6Address.of(33, 33) }, ips);
// Add another device that also claims IP2 but is older than e2
Entity e4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(2, 2), DatapathId.NONE, OFPort.ZERO, new Date(1000));
Entity e4b = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(4), new Date(1000));
Device d4 = deviceManager.learnDeviceByEntity(e4);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d2.getIPv6Addresses());
assertArrayEquals(new IPv6Address[0], d4.getIPv6Addresses());
// add another entity to d4
d4 = deviceManager.learnDeviceByEntity(e4b);
assertArrayEquals(new IPv6Address[0], d4.getIPv6Addresses());
// Make e4 and e4a newer
Entity e4c = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(2, 2), DatapathId.NONE, OFPort.ZERO, new Date(5000));
Entity e4d = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(5000));
d4 = deviceManager.learnDeviceByEntity(e4c);
d4 = deviceManager.learnDeviceByEntity(e4d);
assertArrayEquals(new IPv6Address[0], d2.getIPv6Addresses());
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d4.getIPv6Addresses());
// Add another newer entity to d2 but with different IP
Entity e2d = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.of(22, 22), DatapathId.of(4L), OFPort.of(6), new Date(6000));
d2 = deviceManager.learnDeviceByEntity(e2d);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(22, 22) }, d2.getIPv6Addresses());
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2) }, d4.getIPv6Addresses());
// new IP for d2,d4 but with same timestamp. Both devices get the IP
Entity e2e = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.of(42, 42), DatapathId.of(2L), OFPort.of(4), new Date(7000));
d2 = deviceManager.learnDeviceByEntity(e2e);
ips= d2.getIPv6Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(22, 22), IPv6Address.of(42, 42) }, ips);
Entity e4e = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(42, 42), DatapathId.of(4L), OFPort.of(7), new Date(7000));
d4 = deviceManager.learnDeviceByEntity(e4e);
ips= d4.getIPv6Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2), IPv6Address.of(42, 42) }, ips);
// add a couple more IPs
Entity e2f = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.of(4242, 4242), DatapathId.of(2L), OFPort.of(5), new Date(8000));
d2 = deviceManager.learnDeviceByEntity(e2f);
ips= d2.getIPv6Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(22, 22), IPv6Address.of(42, 42), IPv6Address.of(4242, 4242) }, ips);
Entity e4f = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.of(4242, 4242), DatapathId.of(4L), OFPort.of(8), new Date(9000));
d4 = deviceManager.learnDeviceByEntity(e4f);
ips= d4.getIPv6Addresses();
Arrays.sort(ips);
assertArrayEquals(new IPv6Address[] { IPv6Address.of(2, 2), IPv6Address.of(42, 42), IPv6Address.of(4242, 4242) }, ips);
}
@Test
public void testGetSwitchPortVlanId() {
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(10L), OFPort.of(1), new Date());
Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(3), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(42), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity[] entities = new Entity[] { entity1, entity2,
entity3, entity4
};
Device d = new Device(null,1L, null, null, null,
Arrays.asList(entities), null);
SwitchPort swp1x1 = new SwitchPort(DatapathId.of(1L), OFPort.of(1));
SwitchPort swp1x2 = new SwitchPort(DatapathId.of(1L), OFPort.of(2));
SwitchPort swp2x1 = new SwitchPort(DatapathId.of(2L), OFPort.of(1));
SwitchPort swp10x1 = new SwitchPort(DatapathId.of(10L), OFPort.of(1));
assertArrayEquals(new VlanVid[] { VlanVid.ZERO, VlanVid.ofVlan(1)},
d.getSwitchPortVlanIds(swp10x1));
assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(3), VlanVid.ofVlan(42)},
d.getSwitchPortVlanIds(swp1x1));
assertArrayEquals(new VlanVid[0],
d.getSwitchPortVlanIds(swp1x2));
assertArrayEquals(new VlanVid[0],
d.getSwitchPortVlanIds(swp2x1));
}
@Test
public void testReclassifyDevice() throws FloodlightModuleException {
MockFlexEntityClassifier flexClassifier =
new MockFlexEntityClassifier();
deviceManager.entityClassifier= flexClassifier;
deviceManager.startUp(null);
ITopologyService mockTopology = createMock(ITopologyService.class);
deviceManager.topology = mockTopology;
expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort()))).
andReturn(true).anyTimes();
expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort()),
DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
OFPort.of(EasyMock.anyShort())))
.andReturn(false)
.anyTimes();
replay(mockTopology);
//flexClassifier.createTestEntityClass("Class1");
Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(1), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(2), new Date());
Entity entity2b = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.of(2L), OFPort.of(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.getIpv6Address(),
entity1.getSwitchDPID(), entity1.getSwitchPort())
.next();
d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(),
entity1b.getVlan(), entity1b.getIpv4Address(), entity1b.getIpv6Address(),
entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next();
assertEquals(d1, d1b);
d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(),
entity2.getVlan(), entity2.getIpv4Address(), entity2.getIpv6Address(),
entity2.getSwitchDPID(), entity2.getSwitchPort()).next();
d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(),
entity2b.getVlan(), entity2b.getIpv4Address(), entity2b.getIpv6Address(),
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);
}
@Test
public void testSyncEntity() {
Date d1 = new Date();
Date d2 = new Date(1);
Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), d1);
e1.setActiveSince(d2);
SyncEntity se1 = new SyncEntity(e1);
assertEntityEquals(e1, se1);
assertEquals(1L, se1.macAddress);
assertEquals(2, se1.vlan);
assertEquals(3, se1.ipv4Address);
assertEquals(4L, se1.switchDPID);
assertEquals(5, se1.switchPort);
assertEquals(d1, se1.lastSeenTimestamp);
assertEquals(d2, se1.activeSince);
assertNotSame(d1, se1.lastSeenTimestamp);
assertNotSame(d2, se1.activeSince);
Entity e2 = new Entity(MacAddress.of(42L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, Entity.NO_DATE);
SyncEntity se2 = new SyncEntity(e2);
assertEntityEquals(e2, se2);
SyncEntity se3 = new SyncEntity();
SyncEntity se4 = new SyncEntity();
se3.lastSeenTimestamp = new Date(1000);
se4.lastSeenTimestamp = new Date(2000);
assertTrue("", se3.compareTo(se4) < 0);
assertTrue("", se4.compareTo(se3) > 0);
se4.lastSeenTimestamp = new Date(1000);
assertTrue("", se3.compareTo(se4) == 0);
assertTrue("", se4.compareTo(se3) == 0);
se4.lastSeenTimestamp = new Date(500);
assertTrue("", se3.compareTo(se4) > 0);
assertTrue("", se4.compareTo(se3) < 0);
}
/* Test basic DeviceSyncRepresentation behavior */
@Test
public void testDeviceSyncRepresentationBasics() {
DeviceSyncRepresentation dsr = new DeviceSyncRepresentation();
assertNull(dsr.getKey());
assertNull(dsr.getEntities());
dsr.setKey("MyKey");
assertEquals("MyKey", dsr.getKey());
assertEquals("MyKey", dsr.toString());
List<SyncEntity> entities = new ArrayList<SyncEntity>();
Entity e1a = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1000));
Entity e1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1));
entities.add(new SyncEntity(e1a));
entities.add(new SyncEntity(e1b));
// e1b comes before e1 (lastSeen) but we add it after it to test
// sorting
dsr.setEntities(entities);
assertEquals(2, dsr.getEntities().size());
// e1b has earlier time
assertEquals(e1b, dsr.getEntities().get(0).asEntity());
assertEquals(e1a, dsr.getEntities().get(1).asEntity());
dsr.setKey(null);
dsr.setEntities(null);
assertNull(dsr.getKey());
assertNull(dsr.getEntities());
}
@Test
public void testDeviceSyncRepresentationFromDevice() {
ITopologyService mockTopology = makeMockTopologyAllPortsAp();
replay(mockTopology);
deviceManager.topology = mockTopology;
deviceManager.entityClassifier = new MockEntityClassifier();
//**************************************
// Test 1: a single entity
Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1000));
Device d1 = deviceManager.learnDeviceByEntity(e1);
assertEquals("Sanity check failed. Device doesn't have the expected " +
"entity class. Something with the test setup is strange",
"DefaultEntityClass", d1.getEntityClass().getName());
assertEquals("Sanity check failed. Device doesn't have the expected " +
"entity class. Something with the test setup is strange",
EnumSet.of(DeviceField.MAC, DeviceField.VLAN),
d1.getEntityClass().getKeyFields());
Long deviceKey = d1.getDeviceKey();
DeviceSyncRepresentation dsr1 = new DeviceSyncRepresentation(d1);
assertEquals("DefaultEntityClass::00:00:00:00:00:01::[0x2]::",
dsr1.getKey());
assertEquals(1, dsr1.getEntities().size());
assertEquals(e1, dsr1.getEntities().get(0).asEntity());
//**************************************
// Test 1b: same device, now with a second entity (no IP).
// this second entity has a lastSeen time that is earlier than the
// first entity
Entity e1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1));
d1 = deviceManager.learnDeviceByEntity(e1b);
assertEquals("Sanity check failed. Should still be same device but " +
"deviceKeys differs", deviceKey, d1.getDeviceKey());
dsr1 = new DeviceSyncRepresentation(d1);
assertEquals("DefaultEntityClass::00:00:00:00:00:01::[0x2]::",
dsr1.getKey());
assertEquals(2, dsr1.getEntities().size());
// Entities are ordered by their lastSeen time. e1b should come
// before e1.
assertEquals(e1, dsr1.getEntities().get(1).asEntity());
assertEquals(e1b, dsr1.getEntities().get(0).asEntity());
//**************************************
// Test 1c: same device with a third entity that does not have a
// switch port. It should be added to the DeviceSyncRepresentation
Entity e1c = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(33), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(2000));
d1 = deviceManager.learnDeviceByEntity(e1c);
assertEquals("Sanity check failed. Should still be same device but " +
"deviceKeys differs", deviceKey, d1.getDeviceKey());
dsr1 = new DeviceSyncRepresentation(d1);
assertEquals("DefaultEntityClass::00:00:00:00:00:01::[0x2]::",
dsr1.getKey());
assertEquals(3, dsr1.getEntities().size());
// Entities are ordered by their lastSeen time
assertEquals(e1c, dsr1.getEntities().get(2).asEntity());
assertEquals(e1, dsr1.getEntities().get(1).asEntity());
assertEquals(e1b, dsr1.getEntities().get(0).asEntity());
//**************************************
// Test 1d: same device with a fourth entity that has a different
// attachment point and that is newer. Device should move and
// non-attachment point entities should be removed (e1b). Although
// e1 is non-attachment point it will remain because it has an IP
Entity e1d = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(33), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(6), new Date(3000));
d1 = deviceManager.learnDeviceByEntity(e1d);
assertEquals("Sanity check failed. Should still be same device but " +
"deviceKeys differs", deviceKey, d1.getDeviceKey());
dsr1 = new DeviceSyncRepresentation(d1);
assertEquals("DefaultEntityClass::00:00:00:00:00:01::[0x2]::",
dsr1.getKey());
assertEquals(3, dsr1.getEntities().size());
assertEquals(e1, dsr1.getEntities().get(0).asEntity());
assertEquals(e1c, dsr1.getEntities().get(1).asEntity());
assertEquals(e1d, dsr1.getEntities().get(2).asEntity());
d1 = null;
//**************************************
// Test 2: a second device with a different entity class. The
// mock entity classifier will return an entity class where all
// fields are keys if the DPID is > 10L
Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(23), IPv4Address.of(24), IPv6Address.NONE, DatapathId.of(11L), OFPort.of(1), new Date(1));
Device d2 = deviceManager.learnDeviceByEntity(e2);
DeviceSyncRepresentation dsr2 = new DeviceSyncRepresentation(d2);
assertEquals("Sanity check failed. Device doesn't have the expected " +
"entity class. Something with the test setup is strange",
"TestEntityClass", d2.getEntityClass().getName());
assertEquals("Sanity check failed. Device doesn't have the expected " +
"entity class. Something with the test setup is strange",
EnumSet.of(DeviceField.MAC, DeviceField.VLAN,
DeviceField.SWITCH, DeviceField.PORT),
d2.getEntityClass().getKeyFields());
SwitchPort swp = new SwitchPort(DatapathId.of(11L), OFPort.of(1), null); // the default of VlanVid.toString() returns a hexadecimal version of the int VlanVid, so 0x17 is expected
assertEquals("TestEntityClass::00:00:00:00:00:02::[0x17]::[" +
swp.toString() + "]::",
dsr2.getKey());
}
/* interate through all entries in the sync store and return them as
* list. We don't return the key from the store however, we assert
* that the key from the store matches the key in the representation.
* If we have a null value (tombstone) we simply add the null value to
* the list to return.
*/
private List<DeviceSyncRepresentation> getEntriesFromStore()
throws Exception {
List<DeviceSyncRepresentation> entries =
new ArrayList<DeviceSyncRepresentation>();
IClosableIterator<Entry<String, Versioned<DeviceSyncRepresentation>>> iter =
storeClient.entries();
try {
while(iter.hasNext()) {
Entry<String, Versioned<DeviceSyncRepresentation>> entry =
iter.next();
DeviceSyncRepresentation dsr = entry.getValue().getValue();
if (dsr != null)
assertEquals(entry.getKey(), dsr.getKey());
entries.add(dsr);
}
} finally {
if (iter != null)
iter.close();
}
return entries;
}
/*
* assert whether the given Entity expected is equals to the given
* SyncEntity actual. This method also compares the times (lastSeen,
* activeSince). Entity.equals will not do that!
*/
private static void assertEntityEquals(Entity expected, SyncEntity actual) {
assertNotNull(actual);
assertNotNull(expected);
Entity actualEntity = actual.asEntity();
assertEquals("entityFields", expected, actualEntity);
assertEquals("lastSeenTimestamp",
expected.getLastSeenTimestamp(),
actualEntity.getLastSeenTimestamp());
assertEquals("activeSince",
expected.getActiveSince(), actualEntity.getActiveSince());
}
/* This test tests the normal operation as master when we write to the sync
* store or delete from the store.
*/
@Test
public void testWriteToSyncStore() throws Exception {
int syncStoreIntervalMs = 50;
ITopologyService mockTopology = makeMockTopologyAllPortsAp();
replay(mockTopology);
deviceManager.topology = mockTopology;
deviceManager.setSyncStoreWriteInterval(syncStoreIntervalMs);
Entity e1a = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1000));
e1a.setActiveSince(new Date(1));
deviceManager.learnDeviceByEntity(e1a);
//storeClient.put("FooBar", new DeviceSyncRepresentation());
List<DeviceSyncRepresentation> entries = getEntriesFromStore();
assertEquals(1, entries.size());
DeviceSyncRepresentation dsr1 = entries.get(0);
assertEquals(1, dsr1.getEntities().size());
assertEntityEquals(e1a, dsr1.getEntities().get(0));
// Same entity but newer timestamp. Since the device hasn't changed,
// only the timestamp is updated and the write should be throttled.
Entity e1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(2000));
e1b.setActiveSince(new Date(1)); /* cannot use Date(0), since that's our 'no date' value now */
deviceManager.learnDeviceByEntity(e1a);
entries = getEntriesFromStore();
assertEquals(1, entries.size());
dsr1 = entries.get(0);
assertEquals(1, dsr1.getEntities().size());
assertEntityEquals(e1a, dsr1.getEntities().get(0)); //e1a not e1b !!!
// Wait for the write interval to expire then write again.
Thread.sleep(syncStoreIntervalMs+5);
Entity e1c = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(3000));
e1c.setActiveSince(new Date(1));
deviceManager.learnDeviceByEntity(e1c);
entries = getEntriesFromStore();
assertEquals(1, entries.size());
dsr1 = entries.get(0);
assertEquals(1, dsr1.getEntities().size());
assertEntityEquals(e1c, dsr1.getEntities().get(0)); // e1c !!
// Entity for same device but with different IP. should be added
// immediately
Entity e1d = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(33), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(4000));
e1d.setActiveSince(new Date(1));
deviceManager.learnDeviceByEntity(e1d);
entries = getEntriesFromStore();
assertEquals(1, entries.size());
dsr1 = entries.get(0);
assertEquals(2, dsr1.getEntities().size());
assertEntityEquals(e1c, dsr1.getEntities().get(0)); // e1c !!
assertEntityEquals(e1d, dsr1.getEntities().get(1)); // e1d !!
// Entity for same device with new switch port ==> moved ==> write
// update immediately without throttle.
// Note: the previous entities will still be there because they have
// IPs (even though they aren't for the current attachment point)
Entity e1e = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(33), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(6), new Date(5000));
e1e.setActiveSince(new Date(1));
deviceManager.learnDeviceByEntity(e1e);
entries = getEntriesFromStore();
assertEquals(1, entries.size());
dsr1 = entries.get(0);
assertEquals(3, dsr1.getEntities().size());
assertEntityEquals(e1c, dsr1.getEntities().get(0));
assertEntityEquals(e1d, dsr1.getEntities().get(1));
assertEntityEquals(e1e, dsr1.getEntities().get(2));
// Add a second device
Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(5L), OFPort.of(5), new Date());
deviceManager.learnDeviceByEntity(e2);
entries = getEntriesFromStore();
assertEquals(2, entries.size());
for (DeviceSyncRepresentation dsr: entries) {
// This is a kinda ugly way to ensure we have the two
// devices we need..... but it will work for now
if (dsr.getKey().contains("::00:00:00:00:00:01::")) {
assertEquals(3, dsr.getEntities().size());
assertEntityEquals(e1c, dsr.getEntities().get(0));
assertEntityEquals(e1d, dsr.getEntities().get(1));
assertEntityEquals(e1e, dsr.getEntities().get(2));
} else if (dsr.getKey().contains("::00:00:00:00:00:02::")) {
assertEquals(1, dsr.getEntities().size());
assertEntityEquals(e2, dsr.getEntities().get(0));
} else {
fail("Unknown entry in store: " + dsr);
}
}
// Run entity cleanup. Since we've used phony time stamps for
// device 1 its entities should be cleared and the device should be
// removed from the store. Device 2 should remain in the store.
deviceManager.cleanupEntities();
entries = getEntriesFromStore();
assertEquals(2, entries.size());
for (DeviceSyncRepresentation dsr: entries) {
if (dsr == null) {
// pass
} else if (dsr.getKey().contains("::00:00:00:00:00:02::")) {
assertEquals(1, dsr.getEntities().size());
assertEntityEquals(e2, dsr.getEntities().get(0));
} else {
fail("Unknown entry in store: " + dsr);
}
}
}
private void assertDeviceIps(IPv4Address[] expected, IDevice d) {
List<IPv4Address> expectedList = Arrays.asList(expected);
Collections.sort(expectedList);
List<IPv4Address> actualList = Arrays.asList(d.getIPv4Addresses());
Collections.sort(actualList);
assertEquals(expectedList, actualList);
}
private IDevice getSingleDeviceFromDeviceManager(long mac) {
Iterator<? extends IDevice> diter =
deviceManager.queryDevices(MacAddress.of(mac), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertTrue("Query didn't return a device", diter.hasNext());
IDevice d = diter.next();
assertFalse("Query returned more than one device", diter.hasNext());
return d;
}
@Test
public void testToMaster() throws Exception {
int syncStoreWriteIntervalMs = 0;
int initialSyncStoreConsolidateIntervalMs = 50;
ITopologyService mockTopology = makeMockTopologyAllPortsAp();
replay(mockTopology);
deviceManager.topology = mockTopology;
// We want an EntityClassifier that has switch/port as key fields
deviceManager.entityClassifier = new MockEntityClassifier();
deviceManager.setSyncStoreWriteInterval(syncStoreWriteIntervalMs);
deviceManager.setInitialSyncStoreConsolidateMs(initialSyncStoreConsolidateIntervalMs);
// Add Device1 with two entities with two different IPs
Entity e1a = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1000));
Entity e1b = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(33), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(2000));
Device d1 = deviceManager.allocateDevice(1L, e1a,
DefaultEntityClassifier.entityClass);
d1 = deviceManager.allocateDevice(d1, e1b, -1);
DeviceSyncRepresentation dsr = new DeviceSyncRepresentation(d1);
storeClient.put(dsr.getKey(), dsr);
// Add Device2 with different switch-ports. Only the most recent
// one should be the attachment point
Entity e2a = new Entity(MacAddress.of(2L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(4), new Date(1000));
Entity e2b = new Entity(MacAddress.of(2L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(2000));
Device d2 = deviceManager.allocateDevice(2L, e2a,
DefaultEntityClassifier.entityClass);
d2 = deviceManager.allocateDevice(d2, e2b, -1);
d2.updateAttachmentPoint(DatapathId.of(4L), OFPort.of(5),
e2b.getLastSeenTimestamp());
SwitchPort swp = new SwitchPort(DatapathId.of(4L), OFPort.of(5));
SwitchPort[] aps = d2.getAttachmentPoints();
// sanity check
assertArrayEquals("Sanity check: should only have AP(4L,5)",
new SwitchPort[] {swp}, aps);
dsr = new DeviceSyncRepresentation(d2);
storeClient.put(dsr.getKey(), dsr);
// Add a tombstone entry to the store to make sure we don't trip a
// NPE
dsr = null;
Versioned<DeviceSyncRepresentation> versionedDsr =
storeClient.get("FooBar");
storeClient.put("FooBar", versionedDsr);
deviceManager.getHAListener().transitionToActive();
// Query for the Device1. Make sure we have the two IPs we stored.
IDevice d = getSingleDeviceFromDeviceManager(1L);
assertDeviceIps(new IPv4Address[] {IPv4Address.of(3), IPv4Address.of(33)}, d);
assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d.getVlanId());
swp = new SwitchPort(DatapathId.of(4L), OFPort.of(5));
assertArrayEquals(new SwitchPort[] { swp }, d.getAttachmentPoints());
// Query for Device2. Make sure we only have the more recent AP
// Query for the Device1. Make sure we have the two IPs we stored.
d = getSingleDeviceFromDeviceManager(2L);
assertArrayEquals(new IPv4Address[0], d.getIPv4Addresses());
assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d.getVlanId());
swp = new SwitchPort(DatapathId.of(4L), OFPort.of(5));
assertArrayEquals(new SwitchPort[] { swp }, d.getAttachmentPoints());
//----------------------------
// add another entry device to the store. since device manager is
// already master we won't read this device and it should be
// removed from the store by the consolidate task
Entity e3 = new Entity(MacAddress.of(3L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), Entity.NO_DATE);
dsr = new DeviceSyncRepresentation();
dsr.setKey("Device3");
dsr.setEntities(Collections.singletonList(new SyncEntity(e3)));
storeClient.put(dsr.getKey(), dsr);
// make sure it's in the store
List<DeviceSyncRepresentation> entries = getEntriesFromStore();
boolean found = false;
for (DeviceSyncRepresentation entry: entries) {
if (entry!=null && entry.getKey().equals("Device3"))
found = true;
}
assertTrue("Device3 not in store. Entries in store: " + entries, found);
// make sure it's not in DevManager
Iterator<? extends IDevice> diter =
deviceManager.queryDevices(MacAddress.of(3L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertFalse("Device3 found in DeviceManager. Should be there",
diter.hasNext());
// Wait for consolidate
Thread.sleep(initialSyncStoreConsolidateIntervalMs + 5);
// make sure it's in NOT the store
entries = getEntriesFromStore();
found = false;
for (DeviceSyncRepresentation entry: entries) {
if (entry!=null && entry.getKey().equals("Device3"))
found = true;
}
assertFalse("Device3 not is still in the store. Entries in store: "
+ entries, found);
// make sure it's not in DevManager
diter = deviceManager.queryDevices(MacAddress.of(3L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO);
assertFalse("Device3 found in DeviceManager. Should be there",
diter.hasNext());
}
@Test
public void testConsolitateStore() throws Exception {
int syncStoreInternalMs = 0;
ITopologyService mockTopology = makeMockTopologyAllPortsAp();
replay(mockTopology);
deviceManager.topology = mockTopology;
// We want an EntityClassifier that has switch/port as key fields
deviceManager.entityClassifier = new MockEntityClassifier();
deviceManager.setSyncStoreWriteInterval(syncStoreInternalMs);
// Add Device1 with two entities to store and let device manager
// learn
Entity e1a = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(1000));
Entity e1b = new Entity(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.of(3), IPv6Address.NONE, DatapathId.of(4L), OFPort.of(5), new Date(2000));
Device d1 = deviceManager.learnDeviceByEntity(e1a);
deviceManager.learnDeviceByEntity(e1b);
String dev1Key = DeviceSyncRepresentation.computeKey(d1);
// Add a second device to the store but do NOT add to device manager
Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(5L), OFPort.of(5), new Date());
Device d2 = deviceManager.allocateDevice(42L, e2,
DefaultEntityClassifier.entityClass);
DeviceSyncRepresentation dsr = new DeviceSyncRepresentation(d2);
storeClient.put(dsr.getKey(), dsr);
String dev2Key = DeviceSyncRepresentation.computeKey(d2);
// Make sure we have two devices in the store
List<DeviceSyncRepresentation> entries = getEntriesFromStore();
assertEquals(2, entries.size());
deviceManager.scheduleConsolidateStoreNow();
Thread.sleep(25); // give the scheduler time to run the task
// We should still have two entries, however one of them will be a
// tombstone
entries = getEntriesFromStore();
assertEquals(2, entries.size());
// Device 1 should still be in store
Versioned<DeviceSyncRepresentation> versioned =
storeClient.get(dev1Key);
dsr = versioned.getValue();
assertNotNull(dsr);
assertEquals(2, dsr.getEntities().size());
assertEntityEquals(e1a, dsr.getEntities().get(0));
assertEntityEquals(e1b, dsr.getEntities().get(1));
// Device2 should be gone
versioned = storeClient.get(dev2Key);
assertNull(versioned.getValue());
// Run consolitate again. This time we check that tombstones in
// the store are handled correctly
deviceManager.scheduleConsolidateStoreNow();
Thread.sleep(25); // give the scheduler time to run the task
// Now write a device to the store that doesn't have any switch-port
// it should be removed
Entity e3 = new Entity(MacAddress.of(3L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, Entity.NO_DATE);
dsr.setKey("Device3");
dsr.setEntities(Collections.singletonList(new SyncEntity(e3)));
storeClient.put(dsr.getKey(), dsr);
// Run consolitate again. This time we check that tombstones in
// the store are handled correctly
deviceManager.scheduleConsolidateStoreNow();
Thread.sleep(25); // give the scheduler time to run the task
versioned = storeClient.get("Device3");
assertNull(versioned.getValue());
}
}