diff --git a/src/main/java/net/floodlightcontroller/accesscontrollist/ACL.java b/src/main/java/net/floodlightcontroller/accesscontrollist/ACL.java index b3c2a88f99bdb9836487cc53b6206fe8f100613a..edfc1015f656cde20bf9589091547fd582ed451e 100644 --- a/src/main/java/net/floodlightcontroller/accesscontrollist/ACL.java +++ b/src/main/java/net/floodlightcontroller/accesscontrollist/ACL.java @@ -413,6 +413,11 @@ public class ACL implements IACLService, IFloodlightModule, IDeviceListener { } + @Override + public void deviceIPV6AddrChanged(IDevice device) { + logger.debug("IPv6 not implemented in ACL. Device changed: {}", device.toString()); + } + @Override public void deviceIPV4AddrChanged(IDevice device) { diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/IPv6Serializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/IPv6Serializer.java new file mode 100644 index 0000000000000000000000000000000000000000..1394f53de55461ceed1836d30daf27f6f9c54332 --- /dev/null +++ b/src/main/java/net/floodlightcontroller/core/web/serializers/IPv6Serializer.java @@ -0,0 +1,39 @@ +/** +* Copyright 2011,2012 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.core.web.serializers; + +import java.io.IOException; + +import org.projectfloodlight.openflow.types.IPv6Address; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +/** + * Serialize an IPv6Address in dotted decimal format + */ +public class IPv6Serializer extends JsonSerializer<IPv6Address> { + + @Override + public void serialize(IPv6Address ipv6, JsonGenerator jGen, + SerializerProvider serializer) + throws IOException, JsonProcessingException { + jGen.writeString(ipv6.toString()); + } +} diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java index 67474cbab8a5801178a56b5598e980a1f1fc403a..3481e974505c4bcdfe50801a60a40848796c6ecd 100644 --- a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java +++ b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java @@ -689,31 +689,36 @@ public class StatsReplySerializer extends JsonSerializer<StatsReply> { jGen.writeEndArray(); } - - public static void serializePortReply(List<OFPortStatsReply> portReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ - OFPortStatsReply portReply = portReplies.get(0); // we will get only one PortReply and it will contains many OFPortStatsEntry ? - jGen.writeStringField("version", portReply.getVersion().toString()); //return the enum name - jGen.writeFieldName("port"); + public static void serializePortReply(List<OFPortStatsReply> portReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ + jGen.writeFieldName("port_reply"); jGen.writeStartArray(); - for(OFPortStatsEntry entry : portReply.getEntries()) { + for (OFPortStatsReply portReply : portReplies) { jGen.writeStartObject(); - jGen.writeStringField("portNumber",entry.getPortNo().toString()); - jGen.writeNumberField("receivePackets", entry.getRxPackets().getValue()); - jGen.writeNumberField("transmitPackets", entry.getTxPackets().getValue()); - jGen.writeNumberField("receiveBytes", entry.getRxBytes().getValue()); - jGen.writeNumberField("transmitBytes", entry.getTxBytes().getValue()); - jGen.writeNumberField("receiveDropped", entry.getRxDropped().getValue()); - jGen.writeNumberField("transmitDropped", entry.getTxDropped().getValue()); - jGen.writeNumberField("receiveErrors", entry.getRxErrors().getValue()); - jGen.writeNumberField("transmitErrors", entry.getTxErrors().getValue()); - jGen.writeNumberField("receiveFrameErrors", entry.getRxFrameErr().getValue()); - jGen.writeNumberField("receiveOverrunErrors", entry.getRxOverErr().getValue()); - jGen.writeNumberField("receiveCRCErrors", entry.getRxCrcErr().getValue()); - jGen.writeNumberField("collisions", entry.getCollisions().getValue()); - if (OFVersion.OF_13 == entry.getVersion()) { - jGen.writeNumberField("durationSec", entry.getDurationSec()); - jGen.writeNumberField("durationNsec", entry.getDurationNsec()); + jGen.writeStringField("version", portReply.getVersion().toString()); //return the enum name + jGen.writeFieldName("port"); + jGen.writeStartArray(); + for(OFPortStatsEntry entry : portReply.getEntries()) { + jGen.writeStartObject(); + jGen.writeStringField("portNumber",entry.getPortNo().toString()); + jGen.writeNumberField("receivePackets", entry.getRxPackets().getValue()); + jGen.writeNumberField("transmitPackets", entry.getTxPackets().getValue()); + jGen.writeNumberField("receiveBytes", entry.getRxBytes().getValue()); + jGen.writeNumberField("transmitBytes", entry.getTxBytes().getValue()); + jGen.writeNumberField("receiveDropped", entry.getRxDropped().getValue()); + jGen.writeNumberField("transmitDropped", entry.getTxDropped().getValue()); + jGen.writeNumberField("receiveErrors", entry.getRxErrors().getValue()); + jGen.writeNumberField("transmitErrors", entry.getTxErrors().getValue()); + jGen.writeNumberField("receiveFrameErrors", entry.getRxFrameErr().getValue()); + jGen.writeNumberField("receiveOverrunErrors", entry.getRxOverErr().getValue()); + jGen.writeNumberField("receiveCRCErrors", entry.getRxCrcErr().getValue()); + jGen.writeNumberField("collisions", entry.getCollisions().getValue()); + if (OFVersion.OF_13 == entry.getVersion()) { + jGen.writeNumberField("durationSec", entry.getDurationSec()); + jGen.writeNumberField("durationNsec", entry.getDurationNsec()); + } + jGen.writeEndObject(); } + jGen.writeEndArray(); jGen.writeEndObject(); } jGen.writeEndArray(); diff --git a/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java index c2a0fcdd95db1235614011b4d97713d31ba28162..9016edab905e493f4f5e64b0e041b3adcf56c53e 100644 --- a/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java +++ b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java @@ -32,7 +32,7 @@ public interface IDebugEventService extends IFloodlightService { * Describes the type of field obtained from reflection */ enum EventFieldType { - DPID, IPv4, MAC, STRING, OBJECT, PRIMITIVE, COLLECTION_IPV4, + DPID, IPv4, IPv6, MAC, STRING, OBJECT, PRIMITIVE, COLLECTION_IPV4, COLLECTION_ATTACHMENT_POINT, COLLECTION_OBJECT, SREF_COLLECTION_OBJECT, SREF_OBJECT } diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java index 4d5ba9be6d5d5ef7f31a4316cb92d2303a62502f..072808dfbf88cc4be941a883f02aec17e66611ab 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java @@ -20,6 +20,7 @@ package net.floodlightcontroller.devicemanager; import java.util.Date; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.VlanVid; @@ -62,12 +63,19 @@ public interface IDevice { */ public IPv4Address[] getIPv4Addresses(); + /** + * Get all unique IPv6 addresses associated with the device. + * @return an array containing the unique IPv6 addresses for the device. + */ + public IPv6Address[] getIPv6Addresses(); + /** * Get all unique attachment points associated with the device. This will * not include any blocked attachment points. * @return an array containing all unique attachment points for the device */ public SwitchPort[] getAttachmentPoints(); + /** * Get all old attachment points associated with the device. this is used in host movement scenario. * @return an array containing all unique old attachment points for the device diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java index 1221e66887666765574bc543cd57a049e839f616..19b7c85bbdd1287074101b0cb83bceeff06287e5 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java @@ -55,6 +55,13 @@ public interface IDeviceListener extends IListener<String> { */ public void deviceIPV4AddrChanged(IDevice device); + /** + * Called when a network address has been added or remove from a device + * + * @param device the device that changed + */ + public void deviceIPV6AddrChanged(IDevice device); + /** * Called when a VLAN tag for the device has been added or removed * @param device the device that changed diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java index 40d729f6894149d9a1e3142c618bc606c0753a4b..54d6963fd6440ef3a389ce746afe93acd1e4dc25 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java @@ -22,8 +22,11 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.Set; +import javax.annotation.Nonnull; + import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.VlanVid; import org.projectfloodlight.openflow.types.OFPort; @@ -43,7 +46,7 @@ public interface IDeviceService extends IFloodlightService { * @see IDeviceService#addIndex */ enum DeviceField { - MAC, IPV4, VLAN, SWITCH, PORT + MAC, IPv4, IPv6, VLAN, SWITCH, PORT } /** @@ -85,25 +88,26 @@ public interface IDeviceService extends IFloodlightService { * is the same lookup process that is used for packet_in processing and * device learning. Thus, findDevice() can be used to match flow entries * from switches to devices. + * * Only the key fields as defined by the {@link IEntityClassifierService} will - * be important in this search. All key fields MUST be supplied. + * be important in this search. All key fields MUST be supplied. * *{@link queryDevices()} might be more appropriate! * - * @param macAddress The MAC address - * @param vlan the VLAN. Null means no VLAN and is valid even if VLAN is a - * key field. - * @param ipv4Address the ipv4 address - * @param switchDPID the switch DPID - * @param switchPort the switch port + * @param macAddress the MAC address; use MacAddress.NONE for 'don't care' + * @param vlan the VLAN; use VlanVid.ZERO for 'untagged' + * @param ipv4Address the ipv4 address; use IPv4Address.NONE for 'don't care' + * @param ipv6Address the ipv6 address; use IPv6Address.NONE for 'don't care' + * @param switchDPID the switch DPID; use DatapathId.NONE for 'don't care' + * @param switchPort the switch port; use OFPort.ZERO for 'don't care' * @return an {@link IDevice} or null if no device is found. * @see IDeviceManager#setEntityClassifier(IEntityClassifierService) * @throws IllegalArgumentException if not all key fields of the * current {@link IEntityClassifierService} are specified. */ - public IDevice findDevice(MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, DatapathId switchDPID, - OFPort switchPort) + public IDevice findDevice(@Nonnull MacAddress macAddress, VlanVid vlan, + @Nonnull IPv4Address ipv4Address, @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, @Nonnull OFPort switchPort) throws IllegalArgumentException; /** @@ -118,18 +122,18 @@ public interface IDeviceService extends IFloodlightService { * be important in this search. All key fields MUST be supplied. * * @param entityClass The entity class in which to perform the lookup. - * @param macAddress The MAC address for the destination - * @param vlan the VLAN if available - * @param ipv4Address The IP address if available. + * @param macAddress the MAC address; use MacAddress.NONE for 'don't care' + * @param vlan the VLAN; use VlanVid.ZERO for 'untagged' + * @param ipv4Address the ipv4 address; use IPv4Address.NONE for 'don't care' + * @param ipv6Address the ipv6 address; use IPv6Address.NONE for 'don't care' * @return an {@link IDevice} or null if no device is found. - * @see IDeviceService#findDevice(long, Short, Integer, Long, - * Integer) + * @see IDeviceService#findDevice(MacAddress, VlanVid, IPv4Address, IPv6Address, DatapathId, OFPort) * @throws IllegalArgumentException if not all key fields of the * source's {@link IEntityClass} are specified. */ - public IDevice findClassDevice(IEntityClass entityClass, - MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address) + public IDevice findClassDevice(@Nonnull IEntityClass entityClass, + @Nonnull MacAddress macAddress, VlanVid vlan, + @Nonnull IPv4Address ipv4Address, @Nonnull IPv6Address ipv6Address) throws IllegalArgumentException; /** @@ -159,20 +163,22 @@ public interface IDeviceService extends IFloodlightService { * the query, then it will be performed efficiently using the index. * Otherwise, there will be a full scan of the device list. * - * @param macAddress The MAC address - * @param vlan the VLAN - * @param ipv4Address the ipv4 address - * @param switchDPID the switch DPID - * @param switchPort the switch port + * @param macAddress the MAC address; use MacAddress.NONE for 'don't care' + * @param vlan the VLAN; use null for 'don't care'; use VlanVid.ZERO for 'untagged' + * @param ipv4Address the ipv4 address; use IPv4Address.NONE for 'don't care' + * @param ipv6Address the ipv6 address; use IPv6Address.NONE for 'don't care' + * @param switchDPID the switch DPID; use DatapathId.NONE for 'don't care' + * @param switchPort the switch port; use OFPort.ZERO for 'don't care' * @return an iterator over a set of devices matching the query - * @see IDeviceService#queryClassDevices(IEntityClass, Long, - * Short, Integer, Long, Integer) + * @see IDeviceService#queryClassDevices(IEntityClass, MacAddress, + * VlanVid, IPv4Address, IPv6Address, DatapathId, OFPort) */ - public Iterator<? extends IDevice> queryDevices(MacAddress macAddress, + public Iterator<? extends IDevice> queryDevices(@Nonnull MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort); + @Nonnull IPv4Address ipv4Address, + @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, + @Nonnull OFPort switchPort); /** * Find devices that match the provided query. Only the index for @@ -183,19 +189,21 @@ public interface IDeviceService extends IFloodlightService { * of the device list. * * @param entityClass The entity class in which to perform the query - * @param macAddress The MAC address - * @param vlan the VLAN - * @param ipv4Address the ipv4 address - * @param switchDPID the switch DPID - * @param switchPort the switch port - * @return an iterator over a set of devices matching the query - * @see IDeviceService#queryClassDevices(Long, - * Short, Integer, Long, Integer) + * @param macAddress the MAC address; use MacAddress.NONE for 'don't care' + * @param vlan the VLAN; use null for 'don't care'; use VlanVid.ZERO for 'untagged' + * @param ipv4Address the ipv4 address; use IPv4Address.NONE for 'don't care' + * @param ipv6Address the ipv6 address; use IPv6Address.NONE for 'don't care' + * @param switchDPID the switch DPID; use DatapathId.NONE for 'don't care' + * @param switchPort the switch port; use OFPort.ZERO for 'don't care' + * @return an iterator over a set of devices matching the query + * @see IDeviceService#queryClassDevices(MacAddress, + * VlanVid, IPv4Address, IPv6Address, DatapathId, OFPort) */ public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass, MacAddress macAddress, VlanVid vlan, IPv4Address ipv4Address, + IPv6Address ipv6Address, DatapathId switchDPID, OFPort switchPort); diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java index 1845ffe8c47a7fbc65cfd50c247aee24e246b3e6..79777f8133e5d82cbf77f720da4037293fadf756 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java @@ -125,4 +125,4 @@ public class AttachmentPoint { + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen.toString() + "]"; } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java index ea55f8cac2bba0f33746375ff96b40a8ad6825f4..b8d83272254797d19d311985eaec5a80862fbf87 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java @@ -125,6 +125,5 @@ public class DefaultEntityClassifier implements @Override public void addListener(IEntityClassListener listener) { // no-op - } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java index d751e6fead99131dc9682b6c3fd7268f550bb664..9f028cf749b17434a422b5e2e6a9cc4f46800f6a 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java @@ -24,15 +24,18 @@ 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.Set; import java.util.TreeSet; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -49,690 +52,804 @@ import net.floodlightcontroller.topology.ITopologyService; /** * Concrete implementation of {@link IDevice} + * * @author readams */ -@JsonSerialize(using=DeviceSerializer.class) +@JsonSerialize(using = DeviceSerializer.class) public class Device implements IDevice { - protected static Logger log = LoggerFactory.getLogger(Device.class); - - private final Long deviceKey; - protected final DeviceManagerImpl deviceManager; - - protected final Entity[] entities; - private final IEntityClass entityClass; - - protected final String macAddressString; - // the vlan Ids from the entities of this device - protected final VlanVid[] vlanIds; - protected volatile String dhcpClientName; - - /** - * These are the old attachment points for the device that were - * valid no more than INACTIVITY_TIME ago. - */ - protected volatile List<AttachmentPoint> oldAPs; - /** - * The current attachment points for the device. - */ - protected volatile List<AttachmentPoint> attachmentPoints; - - // ************ - // Constructors - // ************ - - /** - * Create a device from an entities - * @param deviceManager the device manager for this device - * @param deviceKey the unique identifier for this device object - * @param entity the initial entity for the device - * @param entityClass the entity classes associated with the entity - */ - public Device(DeviceManagerImpl deviceManager, Long deviceKey, - Entity entity, IEntityClass entityClass) { - this.deviceManager = deviceManager; - this.deviceKey = deviceKey; - this.entities = new Entity[] {entity}; - this.macAddressString = entity.getMacAddress().toString(); - this.entityClass = entityClass; - Arrays.sort(this.entities); - - this.dhcpClientName = null; - this.oldAPs = null; - this.attachmentPoints = null; - - if (entity.getSwitchDPID() != null && entity.getSwitchPort() != null) { - DatapathId sw = entity.getSwitchDPID(); - OFPort port = entity.getSwitchPort(); - - if (deviceManager.isValidAttachmentPoint(sw, port)) { - AttachmentPoint ap; - ap = new AttachmentPoint(sw, port, entity.getLastSeenTimestamp()); - this.attachmentPoints = new ArrayList<AttachmentPoint>(); - this.attachmentPoints.add(ap); - } - } - vlanIds = computeVlandIds(); - } - - /** - * Create a device from a set of entities - * @param deviceManager the device manager for this device - * @param deviceKey the unique identifier for this device object - * @param entities the initial entities for the device - * @param entityClass the entity class associated with the entities - */ - public Device(DeviceManagerImpl deviceManager, - Long deviceKey, - String dhcpClientName, - Collection<AttachmentPoint> oldAPs, - Collection<AttachmentPoint> attachmentPoints, - Collection<Entity> entities, - IEntityClass entityClass) { - this.deviceManager = deviceManager; - this.deviceKey = deviceKey; - this.dhcpClientName = dhcpClientName; - this.entities = entities.toArray(new Entity[entities.size()]); - this.oldAPs = null; - this.attachmentPoints = null; - if (oldAPs != null) { - this.oldAPs = new ArrayList<AttachmentPoint>(oldAPs); - } - if (attachmentPoints != null) { - this.attachmentPoints = new ArrayList<AttachmentPoint>(attachmentPoints); - } - this.macAddressString = this.entities[0].getMacAddress().toString(); - this.entityClass = entityClass; - Arrays.sort(this.entities); - vlanIds = computeVlandIds(); - } - - /** - * Construct a new device consisting of the entities from the old device - * plus an additional entity. - * The caller needs to ensure that the additional entity is not already - * present in the array - * @param device the old device object - * @param newEntity the entity to add. newEntity must be have the same - * entity class as device - * @param if positive indicates the index in the entities array were the - * new entity should be inserted. If negative we will compute the - * correct insertion point - */ - public Device(Device device, Entity newEntity, int insertionpoint) { - this.deviceManager = device.deviceManager; - this.deviceKey = device.deviceKey; - this.dhcpClientName = device.dhcpClientName; - - this.entities = new Entity[device.entities.length + 1]; - if (insertionpoint < 0) { - insertionpoint = -(Arrays.binarySearch(device.entities, newEntity) + 1); - } - if (insertionpoint > 0) { - // insertion point is not the beginning: - // copy up to insertion point - System.arraycopy(device.entities, 0, this.entities, 0, insertionpoint); - } - if (insertionpoint < device.entities.length) { - // insertion point is not the end - // copy from insertion point - System.arraycopy(device.entities, insertionpoint, - this.entities, insertionpoint + 1, - device.entities.length - insertionpoint); - } - this.entities[insertionpoint] = newEntity; - /* - this.entities = Arrays.<Entity>copyOf(device.entities, - device.entities.length + 1); - this.entities[this.entities.length - 1] = newEntity; - Arrays.sort(this.entities); - */ - this.oldAPs = null; - if (device.oldAPs != null) { - this.oldAPs = new ArrayList<AttachmentPoint>(device.oldAPs); - } - this.attachmentPoints = null; - if (device.attachmentPoints != null) { - this.attachmentPoints = new ArrayList<AttachmentPoint>(device.attachmentPoints); - } - - this.macAddressString = this.entities[0].getMacAddress().toString(); - - this.entityClass = device.entityClass; - vlanIds = computeVlandIds(); - } - - private VlanVid[] computeVlandIds() { - if (entities.length == 1) { - if (entities[0].getVlan() != null) { - return new VlanVid[]{ entities[0].getVlan() }; - } else { - return new VlanVid[] { VlanVid.ofVlan(-1) }; - } - } - - TreeSet<VlanVid> vals = new TreeSet<VlanVid>(); - for (Entity e : entities) { - if (e.getVlan() == null) - vals.add(VlanVid.ofVlan(-1)); - else - vals.add(e.getVlan()); - } - return vals.toArray(new VlanVid[vals.size()]); - } - - /** - * Given a list of attachment points (apList), the procedure would return - * a map of attachment points for each L2 domain. L2 domain id is the key. - * @param apList - * @return - */ - private Map<DatapathId, AttachmentPoint> getAPMap(List<AttachmentPoint> apList) { - - if (apList == null) return null; - ITopologyService topology = deviceManager.topology; - - // Get the old attachment points and sort them. - List<AttachmentPoint>oldAP = new ArrayList<AttachmentPoint>(); - if (apList != null) oldAP.addAll(apList); - - // Remove invalid attachment points before sorting. - List<AttachmentPoint>tempAP = - new ArrayList<AttachmentPoint>(); - for(AttachmentPoint ap: oldAP) { - if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())) { - tempAP.add(ap); - } - } - oldAP = tempAP; - - Collections.sort(oldAP, deviceManager.apComparator); - - // Map of attachment point by L2 domain Id. - Map<DatapathId, AttachmentPoint> apMap = new HashMap<DatapathId, AttachmentPoint>(); - - for(int i=0; i<oldAP.size(); ++i) { - AttachmentPoint ap = oldAP.get(i); - // if this is not a valid attachment point, continue - if (!deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())) - continue; - - DatapathId id = topology.getL2DomainId(ap.getSw()); - apMap.put(id, ap); - } - - if (apMap.isEmpty()) return null; - return apMap; - } - - /** - * Remove all attachment points that are older than INACTIVITY_INTERVAL - * from the list. - * @param apList - * @return - */ - private boolean removeExpiredAttachmentPoints(List<AttachmentPoint>apList) { - - List<AttachmentPoint> expiredAPs = new ArrayList<AttachmentPoint>(); - - if (apList == null) return false; - - for(AttachmentPoint ap: apList) { - if (ap.getLastSeen().getTime() + AttachmentPoint.INACTIVITY_INTERVAL < System.currentTimeMillis()) { - expiredAPs.add(ap); - } - } - if (expiredAPs.size() > 0) { - apList.removeAll(expiredAPs); - return true; - } else return false; - } - - /** - * Get a list of duplicate attachment points, given a list of old attachment - * points and one attachment point per L2 domain. Given a true attachment - * point in the L2 domain, say trueAP, another attachment point in the - * same L2 domain, say ap, is duplicate if: - * 1. ap is inconsistent with trueAP, and - * 2. active time of ap is after that of trueAP; and - * 3. last seen time of ap is within the last INACTIVITY_INTERVAL - * @param oldAPList - * @param apMap - * @return - */ - List<AttachmentPoint> getDuplicateAttachmentPoints(List<AttachmentPoint>oldAPList, Map<DatapathId, AttachmentPoint>apMap) { - ITopologyService topology = deviceManager.topology; - List<AttachmentPoint> dupAPs = new ArrayList<AttachmentPoint>(); - long timeThreshold = System.currentTimeMillis() - AttachmentPoint.INACTIVITY_INTERVAL; - - if (oldAPList == null || apMap == null) - return dupAPs; - - for(AttachmentPoint ap : oldAPList) { - DatapathId id = topology.getL2DomainId(ap.getSw()); - AttachmentPoint trueAP = apMap.get(id); - - if (trueAP == null) continue; - boolean c = (topology.isConsistent(trueAP.getSw(), trueAP.getPort(), - ap.getSw(), ap.getPort())); - boolean active = (ap.getActiveSince().after(trueAP.getActiveSince())); - boolean last = ap.getLastSeen().getTime() > timeThreshold; - if (!c && active && last) { - dupAPs.add(ap); - } - } - - return dupAPs; - } - - /** - * Update the known attachment points. This method is called whenever - * topology changes. The method returns true if there's any change to - * the list of attachment points -- which indicates a possible device - * move. - * @return - */ - protected boolean updateAttachmentPoint() { - boolean moved = false; - this.oldAPs = attachmentPoints; - if (attachmentPoints == null || attachmentPoints.isEmpty()) - return false; - - List<AttachmentPoint> apList = new ArrayList<AttachmentPoint>(); - if (attachmentPoints != null) apList.addAll(attachmentPoints); - Map<DatapathId, AttachmentPoint> newMap = getAPMap(apList); - if (newMap == null || newMap.size() != apList.size()) { - moved = true; - } - - // Prepare the new attachment point list. - if (moved) { - log.info("updateAttachmentPoint: ap {} newmap {} ", attachmentPoints, newMap); - List<AttachmentPoint> newAPList = new ArrayList<AttachmentPoint>(); - if (newMap != null) newAPList.addAll(newMap.values()); - this.attachmentPoints = newAPList; - } - - // Set the oldAPs to null. - return moved; - } - - /** - * Update the list of attachment points given that a new packet-in - * was seen from (sw, port) at time (lastSeen). The return value is true - * if there was any change to the list of attachment points for the device - * -- which indicates a device move. - * @param sw - * @param port - * @param lastSeen - * @return - */ - protected boolean updateAttachmentPoint(DatapathId sw, OFPort port, Date lastSeen){ - ITopologyService topology = deviceManager.topology; - List<AttachmentPoint> oldAPList; - List<AttachmentPoint> apList; - boolean oldAPFlag = false; - - if (!deviceManager.isValidAttachmentPoint(sw, port)) return false; - AttachmentPoint newAP = new AttachmentPoint(sw, port, lastSeen); - //Copy the oldAP and ap list. - apList = new ArrayList<AttachmentPoint>(); - if (attachmentPoints != null) apList.addAll(attachmentPoints); - oldAPList = new ArrayList<AttachmentPoint>(); - if (oldAPs != null) oldAPList.addAll(oldAPs); - - // if the sw, port is in old AP, remove it from there - // and update the lastSeen in that object. - if (oldAPList.contains(newAP)) { - int index = oldAPList.indexOf(newAP); - newAP = oldAPList.remove(index); - newAP.setLastSeen(lastSeen); - this.oldAPs = oldAPList; - oldAPFlag = true; - } - - // newAP now contains the new attachment point. - - // Get the APMap is null or empty. - Map<DatapathId, AttachmentPoint> apMap = getAPMap(apList); - if (apMap == null || apMap.isEmpty()) { - apList.add(newAP); - attachmentPoints = apList; - // there are no old attachment points - since the device exists, this - // may be because the host really moved (so the old AP port went down); - // or it may be because the switch restarted (so old APs were nullified). - // For now we will treat both cases as host moved. - return true; - } - - DatapathId id = topology.getL2DomainId(sw); - AttachmentPoint oldAP = apMap.get(id); - - if (oldAP == null) { // No attachment on this L2 domain. - apList = new ArrayList<AttachmentPoint>(); - apList.addAll(apMap.values()); - apList.add(newAP); - this.attachmentPoints = apList; - return true; // new AP found on an L2 island. - } - - // There is already a known attachment point on the same L2 island. - // we need to compare oldAP and newAP. - if (oldAP.equals(newAP)) { - // nothing to do here. just the last seen has to be changed. - if (newAP.lastSeen.after(oldAP.lastSeen)) { - oldAP.setLastSeen(newAP.lastSeen); - } - this.attachmentPoints = - new ArrayList<AttachmentPoint>(apMap.values()); - return false; // nothing to do here. - } - - int x = deviceManager.apComparator.compare(oldAP, newAP); - if (x < 0) { - // newAP replaces oldAP. - apMap.put(id, newAP); - this.attachmentPoints = - new ArrayList<AttachmentPoint>(apMap.values()); - - oldAPList = new ArrayList<AttachmentPoint>(); - if (oldAPs != null) oldAPList.addAll(oldAPs); - oldAPList.add(oldAP); - this.oldAPs = oldAPList; - if (!topology.isInSameBroadcastDomain(oldAP.getSw(), oldAP.getPort(), - newAP.getSw(), newAP.getPort())) - return true; // attachment point changed. - } else if (oldAPFlag) { - // retain oldAP as is. Put the newAP in oldAPs for flagging - // possible duplicates. - oldAPList = new ArrayList<AttachmentPoint>(); - if (oldAPs != null) oldAPList.addAll(oldAPs); - // Add ot oldAPList only if it was picked up from the oldAPList - oldAPList.add(newAP); - this.oldAPs = oldAPList; - } - return false; - } - - /** - * Delete (sw,port) from the list of list of attachment points - * and oldAPs. - * @param sw - * @param port - * @return - */ - public boolean deleteAttachmentPoint(DatapathId sw, OFPort port) { - AttachmentPoint ap = new AttachmentPoint(sw, port, new Date(0)); - - if (this.oldAPs != null) { - ArrayList<AttachmentPoint> apList = new ArrayList<AttachmentPoint>(); - apList.addAll(this.oldAPs); - int index = apList.indexOf(ap); - if (index > 0) { - apList.remove(index); - this.oldAPs = apList; - } - } - - if (this.attachmentPoints != null) { - ArrayList<AttachmentPoint> apList = new ArrayList<AttachmentPoint>(); - apList.addAll(this.attachmentPoints); - int index = apList.indexOf(ap); - if (index > 0) { - apList.remove(index); - this.attachmentPoints = apList; - return true; - } - } - return false; - } - - public boolean deleteAttachmentPoint(DatapathId sw) { - boolean deletedFlag; - ArrayList<AttachmentPoint> apList; - ArrayList<AttachmentPoint> modifiedList; - - // Delete the APs on switch sw in oldAPs. - deletedFlag = false; - apList = new ArrayList<AttachmentPoint>(); - if (this.oldAPs != null) - apList.addAll(this.oldAPs); - modifiedList = new ArrayList<AttachmentPoint>(); - - for(AttachmentPoint ap: apList) { - if (ap.getSw().equals(sw)) { - deletedFlag = true; - } else { - modifiedList.add(ap); - } - } - - if (deletedFlag) { - this.oldAPs = modifiedList; - } - - // Delete the APs on switch sw in attachmentPoints. - deletedFlag = false; - apList = new ArrayList<AttachmentPoint>(); - if (this.attachmentPoints != null) - apList.addAll(this.attachmentPoints); - modifiedList = new ArrayList<AttachmentPoint>(); - - for(AttachmentPoint ap: apList) { - if (ap.getSw().equals(sw)) { - deletedFlag = true; - } else { - modifiedList.add(ap); - } - } - - if (deletedFlag) { - this.attachmentPoints = modifiedList; - return true; - } - - return false; - } - - // ******* - // IDevice - // ******* - - @Override - public SwitchPort[] getOldAP() { - List<SwitchPort> sp = new ArrayList<SwitchPort>(); - SwitchPort [] returnSwitchPorts = new SwitchPort[] {}; - if (oldAPs == null) return returnSwitchPorts; - if (oldAPs.isEmpty()) return returnSwitchPorts; - - // copy ap list. - List<AttachmentPoint> oldAPList; - oldAPList = new ArrayList<AttachmentPoint>(); - - if (oldAPs != null) oldAPList.addAll(oldAPs); - removeExpiredAttachmentPoints(oldAPList); - - if (oldAPList != null) { - for(AttachmentPoint ap: oldAPList) { - SwitchPort swport = new SwitchPort(ap.getSw(), - ap.getPort()); - sp.add(swport); - } - } - return sp.toArray(new SwitchPort[sp.size()]); - } - - @Override - public SwitchPort[] getAttachmentPoints() { - return getAttachmentPoints(false); - } - - @Override - public SwitchPort[] getAttachmentPoints(boolean includeError) { - List<SwitchPort> sp = new ArrayList<SwitchPort>(); - SwitchPort [] returnSwitchPorts = new SwitchPort[] {}; - if (attachmentPoints == null) return returnSwitchPorts; - if (attachmentPoints.isEmpty()) return returnSwitchPorts; - - // copy ap list. - List<AttachmentPoint> apList = attachmentPoints; - - if (apList != null) { - for(AttachmentPoint ap: apList) { - SwitchPort swport = new SwitchPort(ap.getSw(), - ap.getPort()); - sp.add(swport); - } - } - - if (!includeError) - return sp.toArray(new SwitchPort[sp.size()]); - - List<AttachmentPoint> oldAPList; - oldAPList = new ArrayList<AttachmentPoint>(); - - if (oldAPs != null) oldAPList.addAll(oldAPs); - - if (removeExpiredAttachmentPoints(oldAPList)) - this.oldAPs = oldAPList; - - List<AttachmentPoint> dupList; - // get AP map. - Map<DatapathId, AttachmentPoint> apMap = getAPMap(apList); - dupList = this.getDuplicateAttachmentPoints(oldAPList, apMap); - if (dupList != null) { - for(AttachmentPoint ap: dupList) { - SwitchPort swport = new SwitchPort(ap.getSw(), - ap.getPort(), - ErrorStatus.DUPLICATE_DEVICE); - sp.add(swport); - } - } - return sp.toArray(new SwitchPort[sp.size()]); - } - - @Override - public Long getDeviceKey() { - return deviceKey; - } - - @Override - public MacAddress getMACAddress() { - // we assume only one MAC per device for now. - return entities[0].getMacAddress(); - } - - @Override - public String getMACAddressString() { - return macAddressString; - } - - @Override - public VlanVid[] getVlanId() { - return Arrays.copyOf(vlanIds, vlanIds.length); - } - - static final EnumSet<DeviceField> ipv4Fields = EnumSet.of(DeviceField.IPV4); - - @Override - public IPv4Address[] getIPv4Addresses() { - // XXX - TODO we can cache this result. Let's find out if this - // is really a performance bottleneck first though. - - TreeSet<IPv4Address> vals = new TreeSet<IPv4Address>(); - for (Entity e : entities) { - if (e.getIpv4Address() == null) continue; - - // We have an IP address only if among the devices within the class - // we have the most recent entity with that IP. - boolean validIP = true; - Iterator<Device> devices = - deviceManager.queryClassByEntity(entityClass, ipv4Fields, e); - while (devices.hasNext()) { - Device d = devices.next(); - if (deviceKey.equals(d.getDeviceKey())) - continue; - for (Entity se : d.entities) { - if (se.getIpv4Address() != null && - se.getIpv4Address().equals(e.getIpv4Address()) && - se.getLastSeenTimestamp() != null && - 0 < se.getLastSeenTimestamp(). - compareTo(e.getLastSeenTimestamp())) { - validIP = false; - break; - } - } - if (!validIP) - break; - } - - if (validIP) - vals.add(e.getIpv4Address()); - } - - return vals.toArray(new IPv4Address[vals.size()]); - } - - @Override - public VlanVid[] getSwitchPortVlanIds(SwitchPort swp) { - TreeSet<VlanVid> vals = new TreeSet<VlanVid>(); - for (Entity e : entities) { - if (e.switchDPID.equals(swp.getSwitchDPID()) - && e.switchPort.equals(swp.getPort())) { - if (e.getVlan() == null) - vals.add(VlanVid.ofVlan(-1)); //TODO Update all -1 VLANs (untagged) to the new VlanVid.ZERO - else - vals.add(e.getVlan()); - } - } - return vals.toArray(new VlanVid[vals.size()]); - } - - @Override - public Date getLastSeen() { - Date d = null; - for (int i = 0; i < entities.length; i++) { - if (d == null || - entities[i].getLastSeenTimestamp().compareTo(d) > 0) - d = entities[i].getLastSeenTimestamp(); - } - return d; - } - - // *************** - // Getters/Setters - // *************** - - @Override - public IEntityClass getEntityClass() { - return entityClass; - } - - public Entity[] getEntities() { - return entities; - } - - public String getDHCPClientName() { - return dhcpClientName; - } - - // *************** - // Utility Methods - // *************** - - /** - * Check whether the device contains the specified entity - * @param entity the entity to search for - * @return the index of the entity, or <0 if not found - */ - protected int entityIndex(Entity entity) { - return Arrays.binarySearch(entities, entity); - } - - // ****** - // Object - // ****** - - @Override + protected static Logger log = LoggerFactory.getLogger(Device.class); + + private final Long deviceKey; + protected final DeviceManagerImpl deviceManager; + + protected final Entity[] entities; + private final IEntityClass entityClass; + + protected final String macAddressString; + // the vlan Ids from the entities of this device + protected final VlanVid[] vlanIds; + protected volatile String dhcpClientName; + + /** + * These are the old attachment points for the device that were valid no + * more than INACTIVITY_TIME ago. + */ + protected volatile List<AttachmentPoint> oldAPs; + /** + * The current attachment points for the device. + */ + protected volatile List<AttachmentPoint> attachmentPoints; + + // ************ + // Constructors + // ************ + + /** + * Create a device from an entities + * + * @param deviceManager + * the device manager for this device + * @param deviceKey + * the unique identifier for this device object + * @param entity + * the initial entity for the device + * @param entityClass + * the entity classes associated with the entity + */ + public Device(DeviceManagerImpl deviceManager, Long deviceKey, + Entity entity, IEntityClass entityClass) { + this.deviceManager = deviceManager; + this.deviceKey = deviceKey; + this.entities = new Entity[] { entity }; + this.macAddressString = entity.getMacAddress().toString(); + this.entityClass = entityClass; + Arrays.sort(this.entities); + + this.dhcpClientName = null; + this.oldAPs = null; + this.attachmentPoints = null; + + if (!entity.getSwitchDPID().equals(DatapathId.NONE) + && !entity.getSwitchPort().equals(OFPort.ZERO)) { + DatapathId sw = entity.getSwitchDPID(); + OFPort port = entity.getSwitchPort(); + + if (deviceManager.isValidAttachmentPoint(sw, port)) { + AttachmentPoint ap; + ap = new AttachmentPoint(sw, port, + entity.getLastSeenTimestamp()); + this.attachmentPoints = new ArrayList<AttachmentPoint>(); + this.attachmentPoints.add(ap); + } + } + vlanIds = computeVlandIds(); + } + + /** + * Create a device from a set of entities + * + * @param deviceManager + * the device manager for this device + * @param deviceKey + * the unique identifier for this device object + * @param entities + * the initial entities for the device + * @param entityClass + * the entity class associated with the entities + */ + public Device(DeviceManagerImpl deviceManager, Long deviceKey, + String dhcpClientName, Collection<AttachmentPoint> oldAPs, + Collection<AttachmentPoint> attachmentPoints, + Collection<Entity> entities, IEntityClass entityClass) { + this.deviceManager = deviceManager; + this.deviceKey = deviceKey; + this.dhcpClientName = dhcpClientName; + this.entities = entities.toArray(new Entity[entities.size()]); + this.oldAPs = null; + this.attachmentPoints = null; + if (oldAPs != null) { + this.oldAPs = new ArrayList<AttachmentPoint>(oldAPs); + } + if (attachmentPoints != null) { + this.attachmentPoints = new ArrayList<AttachmentPoint>( + attachmentPoints); + } + this.macAddressString = this.entities[0].getMacAddress().toString(); + this.entityClass = entityClass; + Arrays.sort(this.entities); + vlanIds = computeVlandIds(); + } + + /** + * Construct a new device consisting of the entities from the old device + * plus an additional entity. The caller needs to ensure that the additional + * entity is not already present in the array + * + * @param device + * the old device object + * @param newEntity + * the entity to add. newEntity must be have the same entity + * class as device + * @param if positive indicates the index in the entities array were the new + * entity should be inserted. If negative we will compute the correct + * insertion point + */ + public Device(Device device, Entity newEntity, int insertionpoint) { + this.deviceManager = device.deviceManager; + this.deviceKey = device.deviceKey; + this.dhcpClientName = device.dhcpClientName; + + if (insertionpoint < 0) { + insertionpoint = -(Arrays.binarySearch(device.entities, newEntity) + 1); + } + + /* + * If insertion point is still negative, then the entity exists already. + * Replace it with the new entity. + */ + if (insertionpoint < 0) { + log.warn("Performing a replacement upon new entity add in Device. Should the entity have been removed first?"); + this.entities = new Entity[device.entities.length]; + int replacementpoint = -insertionpoint - 1; /* get the original binarySearch return (the positive 0-relative position) */ + System.arraycopy(device.entities, 0, this.entities, 0, replacementpoint); /* 0 to replacementpoint-1 (or replacementpoint replacements) */ + this.entities[replacementpoint] = newEntity; + System.arraycopy(device.entities, replacementpoint + 1, this.entities, replacementpoint + 1, device.entities.length - (replacementpoint + 1)); + } else { + this.entities = new Entity[device.entities.length + 1]; + if (insertionpoint > 0) { + // insertion point is not the beginning: + // copy up to insertion point + System.arraycopy(device.entities, 0, this.entities, 0, + insertionpoint); + } + if (insertionpoint < device.entities.length) { + // insertion point is not the end + // copy from insertion point + System.arraycopy(device.entities, insertionpoint, this.entities, + insertionpoint + 1, device.entities.length - insertionpoint); + } + this.entities[insertionpoint] = newEntity; + } + /* + * this.entities = Arrays.<Entity>copyOf(device.entities, + * device.entities.length + 1); this.entities[this.entities.length - 1] + * = newEntity; Arrays.sort(this.entities); + */ + this.oldAPs = null; + if (device.oldAPs != null) { + this.oldAPs = new ArrayList<AttachmentPoint>(device.oldAPs); + } + this.attachmentPoints = null; + if (device.attachmentPoints != null) { + this.attachmentPoints = new ArrayList<AttachmentPoint>( + device.attachmentPoints); + } + + this.macAddressString = this.entities[0].getMacAddress().toString(); + + this.entityClass = device.entityClass; + vlanIds = computeVlandIds(); + } + + private VlanVid[] computeVlandIds() { + if (entities.length == 1) { + return new VlanVid[] { entities[0].getVlan() }; + } + + TreeSet<VlanVid> vals = new TreeSet<VlanVid>(); + for (Entity e : entities) { + vals.add(e.getVlan()); + } + return vals.toArray(new VlanVid[vals.size()]); + } + + /** + * Given a list of attachment points (apList), the procedure would return a + * map of attachment points for each L2 domain. L2 domain id is the key. + * + * @param apList + * @return + */ + private Map<DatapathId, AttachmentPoint> getAPMap( + List<AttachmentPoint> apList) { + + if (apList == null) + return null; + + // Get the old attachment points and sort them. + List<AttachmentPoint> oldAP = new ArrayList<AttachmentPoint>(); + if (apList != null) { + oldAP.addAll(apList); + } + + // Remove invalid attachment points before sorting. + List<AttachmentPoint> tempAP = new ArrayList<AttachmentPoint>(); + for (AttachmentPoint ap : oldAP) { + if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())) { + tempAP.add(ap); + } + } + oldAP = tempAP; + + Collections.sort(oldAP, deviceManager.apComparator); + + // Map of attachment point by L2 domain Id. + Map<DatapathId, AttachmentPoint> apMap = new HashMap<DatapathId, AttachmentPoint>(); + + for (int i = 0; i < oldAP.size(); ++i) { + AttachmentPoint ap = oldAP.get(i); + // if this is not a valid attachment point, continue + if (!deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())) + continue; + + DatapathId id = deviceManager.topology.getL2DomainId(ap.getSw()); + apMap.put(id, ap); + } + + if (apMap.isEmpty()) + return null; + return apMap; + } + + /** + * Remove all attachment points that are older than INACTIVITY_INTERVAL from + * the list. + * + * @param apList + * @return + */ + private boolean removeExpiredAttachmentPoints(List<AttachmentPoint> apList) { + + List<AttachmentPoint> expiredAPs = new ArrayList<AttachmentPoint>(); + + if (apList == null) + return false; + + for (AttachmentPoint ap : apList) { + if (ap.getLastSeen().getTime() + + AttachmentPoint.INACTIVITY_INTERVAL < System + .currentTimeMillis()) { + expiredAPs.add(ap); + } + } + if (expiredAPs.size() > 0) { + apList.removeAll(expiredAPs); + return true; + } else + return false; + } + + /** + * Get a list of duplicate attachment points, given a list of old attachment + * points and one attachment point per L2 domain. Given a true attachment + * point in the L2 domain, say trueAP, another attachment point in the same + * L2 domain, say ap, is duplicate if: 1. ap is inconsistent with trueAP, + * and 2. active time of ap is after that of trueAP; and 3. last seen time + * of ap is within the last INACTIVITY_INTERVAL + * + * @param oldAPList + * @param apMap + * @return + */ + List<AttachmentPoint> getDuplicateAttachmentPoints( + List<AttachmentPoint> oldAPList, + Map<DatapathId, AttachmentPoint> apMap) { + ITopologyService topology = deviceManager.topology; + List<AttachmentPoint> dupAPs = new ArrayList<AttachmentPoint>(); + long timeThreshold = System.currentTimeMillis() - AttachmentPoint.INACTIVITY_INTERVAL; + + if (oldAPList == null || apMap == null) { + return dupAPs; + } + + Set<DatapathId> visitedIslands = new HashSet<DatapathId>(); + + for (AttachmentPoint ap : oldAPList) { + DatapathId id = topology.getL2DomainId(ap.getSw()); + AttachmentPoint trueAP = apMap.get(id); + + if (trueAP == null) { + continue; + } + boolean c = (topology.isConsistent(trueAP.getSw(), + trueAP.getPort(), ap.getSw(), ap.getPort())); + boolean active = trueAP.getActiveSince().after(ap.getActiveSince()) + && ap.getLastSeen().after(trueAP.getLastSeen()); + boolean last = ap.getLastSeen().getTime() > timeThreshold; + if (!c && active && last) { + visitedIslands.add(id); + } + } + + /* + * Now that we've found the islands with a duplicate, + * go back and for every AP on those islands that + * has not expired, add them as duplicates to the list. + */ + for (AttachmentPoint ap : oldAPList) { + DatapathId id = topology.getL2DomainId(ap.getSw()); + if (visitedIslands.contains(id)) { + if (ap.getLastSeen().getTime() > timeThreshold) { + dupAPs.add(ap); + } + } + } + + return dupAPs; + } + + /** + * Update the known attachment points. This method is called whenever + * topology changes. The method returns true if there's any change to the + * list of attachment points -- which indicates a possible device move. + * + * @return + */ + protected boolean updateAttachmentPoint() { + boolean moved = false; + this.oldAPs = attachmentPoints; + if (attachmentPoints == null || attachmentPoints.isEmpty()) { + return false; + } + + List<AttachmentPoint> apList = new ArrayList<AttachmentPoint>(); + if (attachmentPoints != null) { + apList.addAll(attachmentPoints); + } + Map<DatapathId, AttachmentPoint> newMap = getAPMap(apList); + if (newMap == null || newMap.size() != apList.size()) { + moved = true; + } + + // Prepare the new attachment point list + if (moved) { + log.info("updateAttachmentPoint: ap {} newmap {} ", + attachmentPoints, newMap); + List<AttachmentPoint> newAPList = new ArrayList<AttachmentPoint>(); + if (newMap != null) { + newAPList.addAll(newMap.values()); + } + this.attachmentPoints = newAPList; + } + + // Set the oldAPs to null. + return moved; + } + + /** + * Update the list of attachment points given that a new packet-in was seen + * from (sw, port) at time (lastSeen). The return value is true if there was + * any change to the list of attachment points for the device -- which + * indicates a device move. + * + * @param sw + * @param port + * @param lastSeen + * @return + */ + protected boolean updateAttachmentPoint(DatapathId sw, OFPort port, + Date lastSeen) { + ITopologyService topology = deviceManager.topology; + List<AttachmentPoint> oldAPList; + List<AttachmentPoint> apList; + boolean oldAPFlag = false; + + if (!deviceManager.isValidAttachmentPoint(sw, port)) + return false; + AttachmentPoint newAP = new AttachmentPoint(sw, port, lastSeen); + // Copy the oldAP and ap list. + apList = new ArrayList<AttachmentPoint>(); + if (attachmentPoints != null) + apList.addAll(attachmentPoints); + oldAPList = new ArrayList<AttachmentPoint>(); + if (oldAPs != null) + oldAPList.addAll(oldAPs); + + // if the sw, port is in old AP, remove it from there + // and update the lastSeen in that object. + if (oldAPList.contains(newAP)) { + int index = oldAPList.indexOf(newAP); + newAP = oldAPList.remove(index); + newAP.setLastSeen(lastSeen); + this.oldAPs = oldAPList; + oldAPFlag = true; + } + + // newAP now contains the new attachment point. + + // Get the APMap is null or empty. + Map<DatapathId, AttachmentPoint> apMap = getAPMap(apList); + if (apMap == null || apMap.isEmpty()) { + apList.add(newAP); + attachmentPoints = apList; + // there are no old attachment points - since the device exists, + // this + // may be because the host really moved (so the old AP port went + // down); + // or it may be because the switch restarted (so old APs were + // nullified). + // For now we will treat both cases as host moved. + return true; + } + + DatapathId id = topology.getL2DomainId(sw); + AttachmentPoint oldAP = apMap.get(id); + + if (oldAP == null) { // No attachment on this L2 domain. + apList = new ArrayList<AttachmentPoint>(); + apList.addAll(apMap.values()); + apList.add(newAP); + this.attachmentPoints = apList; + return true; // new AP found on an L2 island. + } + + // There is already a known attachment point on the same L2 island. + // we need to compare oldAP and newAP. + if (oldAP.equals(newAP)) { + // nothing to do here. just the last seen has to be changed. + if (newAP.lastSeen.after(oldAP.lastSeen)) { + oldAP.setLastSeen(newAP.lastSeen); + } + this.attachmentPoints = new ArrayList<AttachmentPoint>( + apMap.values()); + return false; // nothing to do here. + } + + int x = deviceManager.apComparator.compare(oldAP, newAP); + if (x < 0) { + // newAP replaces oldAP. + apMap.put(id, newAP); + this.attachmentPoints = new ArrayList<AttachmentPoint>( + apMap.values()); + + oldAPList = new ArrayList<AttachmentPoint>(); + if (oldAPs != null) + oldAPList.addAll(oldAPs); + oldAPList.add(oldAP); + this.oldAPs = oldAPList; + if (!topology.isInSameBroadcastDomain(oldAP.getSw(), + oldAP.getPort(), newAP.getSw(), newAP.getPort())) + return true; // attachment point changed. + } else if (oldAPFlag) { + // retain oldAP as is. Put the newAP in oldAPs for flagging + // possible duplicates. + oldAPList = new ArrayList<AttachmentPoint>(); + if (oldAPs != null) + oldAPList.addAll(oldAPs); + // Add to oldAPList only if it was picked up from the oldAPList + oldAPList.add(newAP); + this.oldAPs = oldAPList; + } + return false; + } + + /** + * Delete (sw,port) from the list of list of attachment points and oldAPs. + * + * @param sw + * @param port + * @return + */ + public boolean deleteAttachmentPoint(DatapathId sw, OFPort port) { + AttachmentPoint ap = new AttachmentPoint(sw, port, new Date(0)); + + if (this.oldAPs != null) { + ArrayList<AttachmentPoint> apList = new ArrayList<AttachmentPoint>(); + apList.addAll(this.oldAPs); + int index = apList.indexOf(ap); + if (index > 0) { + apList.remove(index); + this.oldAPs = apList; + } + } + + if (this.attachmentPoints != null) { + ArrayList<AttachmentPoint> apList = new ArrayList<AttachmentPoint>(); + apList.addAll(this.attachmentPoints); + int index = apList.indexOf(ap); + if (index > 0) { + apList.remove(index); + this.attachmentPoints = apList; + return true; + } + } + return false; + } + + public boolean deleteAttachmentPoint(DatapathId sw) { + boolean deletedFlag; + ArrayList<AttachmentPoint> apList; + ArrayList<AttachmentPoint> modifiedList; + + // Delete the APs on switch sw in oldAPs. + deletedFlag = false; + apList = new ArrayList<AttachmentPoint>(); + if (this.oldAPs != null) + apList.addAll(this.oldAPs); + modifiedList = new ArrayList<AttachmentPoint>(); + + for (AttachmentPoint ap : apList) { + if (ap.getSw().equals(sw)) { + deletedFlag = true; + } else { + modifiedList.add(ap); + } + } + + if (deletedFlag) { + this.oldAPs = modifiedList; + } + + // Delete the APs on switch sw in attachmentPoints. + deletedFlag = false; + apList = new ArrayList<AttachmentPoint>(); + if (this.attachmentPoints != null) + apList.addAll(this.attachmentPoints); + modifiedList = new ArrayList<AttachmentPoint>(); + + for (AttachmentPoint ap : apList) { + if (ap.getSw().equals(sw)) { + deletedFlag = true; + } else { + modifiedList.add(ap); + } + } + + if (deletedFlag) { + this.attachmentPoints = modifiedList; + return true; + } + + return false; + } + + // ******* + // IDevice + // ******* + + @Override + public SwitchPort[] getOldAP() { + List<SwitchPort> sp = new ArrayList<SwitchPort>(); + SwitchPort[] returnSwitchPorts = new SwitchPort[] {}; + if (oldAPs == null) + return returnSwitchPorts; + if (oldAPs.isEmpty()) + return returnSwitchPorts; + + // copy ap list. + List<AttachmentPoint> oldAPList; + oldAPList = new ArrayList<AttachmentPoint>(); + + if (oldAPs != null) + oldAPList.addAll(oldAPs); + removeExpiredAttachmentPoints(oldAPList); + + if (oldAPList != null) { + for (AttachmentPoint ap : oldAPList) { + SwitchPort swport = new SwitchPort(ap.getSw(), ap.getPort()); + sp.add(swport); + } + } + return sp.toArray(new SwitchPort[sp.size()]); + } + + @Override + public SwitchPort[] getAttachmentPoints() { + return getAttachmentPoints(false); + } + + @Override + public SwitchPort[] getAttachmentPoints(boolean includeError) { + List<SwitchPort> sp = new ArrayList<SwitchPort>(); + SwitchPort[] returnSwitchPorts = new SwitchPort[] {}; + if (attachmentPoints == null) + return returnSwitchPorts; + if (attachmentPoints.isEmpty()) + return returnSwitchPorts; + + // copy ap list. + List<AttachmentPoint> apList = new ArrayList<AttachmentPoint>( + attachmentPoints); + + if (apList != null) { + for (AttachmentPoint ap : apList) { + SwitchPort swport = new SwitchPort(ap.getSw(), ap.getPort()); + sp.add(swport); + } + } + + if (!includeError) + return sp.toArray(new SwitchPort[sp.size()]); + + List<AttachmentPoint> oldAPList; + oldAPList = new ArrayList<AttachmentPoint>(); + + if (oldAPs != null) + oldAPList.addAll(oldAPs); + + if (removeExpiredAttachmentPoints(oldAPList)) + this.oldAPs = oldAPList; + + List<AttachmentPoint> dupList; + // get AP map. + Map<DatapathId, AttachmentPoint> apMap = getAPMap(apList); + dupList = this.getDuplicateAttachmentPoints(oldAPList, apMap); + if (dupList != null) { + for (AttachmentPoint ap : dupList) { + SwitchPort swport = new SwitchPort(ap.getSw(), ap.getPort(), + ErrorStatus.DUPLICATE_DEVICE); + sp.add(swport); + } + } + return sp.toArray(new SwitchPort[sp.size()]); + } + + @Override + public Long getDeviceKey() { + return deviceKey; + } + + @Override + public MacAddress getMACAddress() { + // we assume only one MAC per device for now. + return entities[0].getMacAddress(); + } + + @Override + public String getMACAddressString() { + return macAddressString; + } + + @Override + public VlanVid[] getVlanId() { + return Arrays.copyOf(vlanIds, vlanIds.length); + } + + static final EnumSet<DeviceField> ipv4Fields = EnumSet.of(DeviceField.IPv4); + static final EnumSet<DeviceField> ipv6Fields = EnumSet.of(DeviceField.IPv6); + + @Override + public IPv4Address[] getIPv4Addresses() { + // XXX - TODO we can cache this result. Let's find out if this + // is really a performance bottleneck first though. + + TreeSet<IPv4Address> vals = new TreeSet<IPv4Address>(); + for (Entity e : entities) { + if (e.getIpv4Address().equals(IPv4Address.NONE)) + continue; + + // We have an IP address only if among the devices within the class + // we have the most recent entity with that IP. + boolean validIP = true; + Iterator<Device> devices = deviceManager.queryClassByEntity( + entityClass, ipv4Fields, e); + while (devices.hasNext()) { + Device d = devices.next(); + if (deviceKey.equals(d.getDeviceKey())) + continue; + for (Entity se : d.entities) { + if (se.getIpv4Address() != null + && se.getIpv4Address().equals(e.getIpv4Address()) + && !se.getLastSeenTimestamp() + .equals(Entity.NO_DATE) + && 0 < se.getLastSeenTimestamp().compareTo( + e.getLastSeenTimestamp())) { + validIP = false; + break; + } + } + if (!validIP) + break; + } + + if (validIP) + vals.add(e.getIpv4Address()); + } + + return vals.toArray(new IPv4Address[vals.size()]); + } + + @Override + public IPv6Address[] getIPv6Addresses() { + TreeSet<IPv6Address> vals = new TreeSet<IPv6Address>(); + for (Entity e : entities) { + if (e.getIpv6Address().equals(IPv6Address.NONE)) + continue; + + // We have an IP address only if among the devices within the class + // we have the most recent entity with that IP. + boolean validIP = true; + Iterator<Device> devices = deviceManager.queryClassByEntity( + entityClass, ipv6Fields, e); + while (devices.hasNext()) { + Device d = devices.next(); + if (deviceKey.equals(d.getDeviceKey())) + continue; + for (Entity se : d.entities) { + if (se.getIpv6Address() != null + && se.getIpv6Address().equals(e.getIpv6Address()) + && !se.getLastSeenTimestamp() + .equals(Entity.NO_DATE) + && 0 < se.getLastSeenTimestamp().compareTo( + e.getLastSeenTimestamp())) { + validIP = false; + break; + } + } + if (!validIP) + break; + } + + if (validIP) + vals.add(e.getIpv6Address()); + } + + return vals.toArray(new IPv6Address[vals.size()]); + } + + @Override + public VlanVid[] getSwitchPortVlanIds(SwitchPort swp) { + TreeSet<VlanVid> vals = new TreeSet<VlanVid>(); + for (Entity e : entities) { + if (e.switchDPID.equals(swp.getSwitchDPID()) + && e.switchPort.equals(swp.getPort())) { + if (e.getVlan() == null) + vals.add(VlanVid.ZERO); + else + vals.add(e.getVlan()); + } + } + return vals.toArray(new VlanVid[vals.size()]); + } + + @Override + public Date getLastSeen() { + Date d = null; + for (int i = 0; i < entities.length; i++) { + if (d == null + || entities[i].getLastSeenTimestamp().compareTo(d) > 0) + d = entities[i].getLastSeenTimestamp(); + } + return d; + } + + // *************** + // Getters/Setters + // *************** + + @Override + public IEntityClass getEntityClass() { + return entityClass; + } + + public Entity[] getEntities() { + return entities; + } + + public String getDHCPClientName() { + return dhcpClientName; + } + + // *************** + // Utility Methods + // *************** + + /** + * Check whether the device contains the specified entity + * + * @param entity + * the entity to search for + * @return the index of the entity, or <0 if not found + */ + protected int entityIndex(Entity entity) { + return Arrays.binarySearch(entities, entity); + } + + // ****** + // Object + // ****** + + @Override public int hashCode() { final int prime = 31; int result = 1; @@ -742,7 +859,7 @@ public class Device implements IDevice { return result; } - @Override + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -761,26 +878,34 @@ public class Device implements IDevice { return true; } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Device [deviceKey="); - builder.append(deviceKey); - builder.append(", entityClass="); - builder.append(entityClass.getName()); - builder.append(", MAC="); - builder.append(macAddressString); - builder.append(", IPs=["); - boolean isFirst = true; - for (IPv4Address ip: getIPv4Addresses()) { - if (!isFirst) - builder.append(", "); - isFirst = false; - builder.append(ip.toString()); - } - builder.append("], APs="); - builder.append(Arrays.toString(getAttachmentPoints(true))); - builder.append("]"); - return builder.toString(); - } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Device [deviceKey="); + builder.append(deviceKey); + builder.append(", entityClass="); + builder.append(entityClass.getName()); + builder.append(", MAC="); + builder.append(macAddressString); + builder.append(", IPv4s=["); + boolean isFirst = true; + for (IPv4Address ip : getIPv4Addresses()) { + if (!isFirst) + builder.append(", "); + isFirst = false; + builder.append(ip.toString()); + } + builder.append("], IPv6s=["); + isFirst = true; + for (IPv6Address ip : getIPv6Addresses()) { + if (!isFirst) + builder.append(", "); + isFirst = false; + builder.append(ip.toString()); + } + builder.append("], APs="); + builder.append(Arrays.toString(getAttachmentPoints(true))); + builder.append("]"); + return builder.toString(); + } } diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java index 0c5100498a87c1c94736a90e793d1968c282283e..dd3702cc9ebbef8fe603e39209ee3d8a6ea27a3b 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java @@ -114,4 +114,4 @@ public abstract class DeviceIndex { } } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java index 2015bbe60d648d86c33a582d2c9bae9b5274e5c8..6404ba662173b70dc7ac291bd8a5dc368a1dc320 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java @@ -55,5 +55,4 @@ public class DeviceIndexInterator implements Iterator<Device> { public void remove() { subIterator.remove(); } - -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java index 4c7c4a4b15b676b3aeef0308ceb35a44e964f139..199271d14506f25b173648e2741a97f20a1f491b 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java @@ -23,6 +23,7 @@ import java.util.List; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -40,6 +41,7 @@ public class DeviceIterator extends FilterIterator<Device> { private MacAddress macAddress; private VlanVid vlan; private IPv4Address ipv4Address; + private IPv6Address ipv6Address; private DatapathId switchDPID; private OFPort switchPort; @@ -50,6 +52,7 @@ public class DeviceIterator extends FilterIterator<Device> { * @param macAddress The MAC address * @param vlan the VLAN * @param ipv4Address the ipv4 address + * @param ipv6Address the ipv6 address * @param switchDPID the switch DPID * @param switchPort the switch port */ @@ -58,6 +61,7 @@ public class DeviceIterator extends FilterIterator<Device> { MacAddress macAddress, VlanVid vlan, IPv4Address ipv4Address, + IPv6Address ipv6Address, DatapathId switchDPID, OFPort switchPort) { super(subIterator); @@ -66,6 +70,7 @@ public class DeviceIterator extends FilterIterator<Device> { this.macAddress = macAddress; this.vlan = vlan; this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; this.switchDPID = switchDPID; this.switchPort = switchPort; } @@ -86,35 +91,42 @@ public class DeviceIterator extends FilterIterator<Device> { } if (!match) return false; } - if (macAddress != null) { + if (!macAddress.equals(MacAddress.NONE)) { if (!macAddress.equals(value.getMACAddress())) return false; } - if (vlan != null) { + if (vlan != null) { /* VLAN is null, since VlanVid.ZERO is untagged */ VlanVid[] vlans = value.getVlanId(); List<VlanVid> searchableVlanList = Arrays.asList(vlans); if (!searchableVlanList.contains(vlan)) { return false; } } - if (ipv4Address != null) { + if (!ipv4Address.equals(IPv4Address.NONE)) { IPv4Address[] ipv4Addresses = value.getIPv4Addresses(); List<IPv4Address> searchableIPv4AddrList = Arrays.asList(ipv4Addresses); if (!searchableIPv4AddrList.contains(ipv4Address)) { return false; } } - if (switchDPID != null || switchPort != null) { + if (!ipv6Address.equals(IPv6Address.NONE)) { + IPv6Address[] ipv6Addresses = value.getIPv6Addresses(); + List<IPv6Address> searchableIPv6AddrList = Arrays.asList(ipv6Addresses); + if (!searchableIPv6AddrList.contains(ipv6Address)) { + return false; + } + } + if (!switchDPID.equals(DatapathId.NONE) || !switchPort.equals(OFPort.ZERO)) { SwitchPort[] sps = value.getAttachmentPoints(); if (sps == null) return false; match = false; for (SwitchPort sp : sps) { - if (switchDPID != null) { + if (!switchDPID.equals(DatapathId.NONE)) { if (!switchDPID.equals(sp.getSwitchDPID())) return false; } - if (switchPort != null) { + if (!switchPort.equals(OFPort.ZERO)) { if (!switchPort.equals(sp.getPort())) return false; } @@ -125,4 +137,4 @@ public class DeviceIterator extends FilterIterator<Device> { } return true; } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java index dbc20c0bdec4e98bc97b1390df62e5c82093a1bc..cb5c0fcb25c22be4fbd76d03ac26a1a922cd3d5a 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java @@ -39,6 +39,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnull; + import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.HAListenerTypeMarker; import net.floodlightcontroller.core.IFloodlightProviderService; @@ -76,6 +78,7 @@ import net.floodlightcontroller.packet.DHCP; import net.floodlightcontroller.packet.DHCPOption; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; +import net.floodlightcontroller.packet.IPv6; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.packet.DHCP.DHCPOptionCode; import net.floodlightcontroller.restserver.IRestApiService; @@ -92,6 +95,7 @@ import org.projectfloodlight.openflow.protocol.OFPacketIn; import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -240,7 +244,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT * The entity classifier currently in use */ protected IEntityClassifierService entityClassifier; - + /** * Used to cache state about specific entity classes */ @@ -360,7 +364,6 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT if (oldDomain.getLong() < newDomain.getLong()) return -1; else if (oldDomain.getLong() > newDomain.getLong()) return 1; - // Give preference to LOCAL always if (oldPort != OFPort.LOCAL && newPort == OFPort.LOCAL) { @@ -373,7 +376,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT // We expect that the last seen of the new AP is higher than // old AP, if it is not, just reverse and send the negative // of the result. - if (oldAP.getActiveSince().after(newAP.getActiveSince())) + if (oldAP.getLastSeen().after(newAP.getLastSeen())) //TODO should this be lastSeen? @Ryan did change this from activeSince return -compare(newAP, oldAP); long activeOffset = 0; @@ -440,16 +443,37 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } @Override - public IDevice findDevice(MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, DatapathId switchDPID, - OFPort switchPort) + public IDevice findDevice(@Nonnull MacAddress macAddress, VlanVid vlan, + @Nonnull IPv4Address ipv4Address, @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, @Nonnull OFPort switchPort) throws IllegalArgumentException { - if (vlan != null && vlan.getVlan() <= 0) - vlan = null; - if (ipv4Address != null && ipv4Address.getInt() == 0) - ipv4Address = null; - Entity e = new Entity(macAddress, vlan, ipv4Address, switchDPID, - switchPort, null); + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null. Try MacAddress.NONE if intention is 'no MAC'"); + } + if (ipv4Address == null) { + throw new IllegalArgumentException("IPv4 address cannot be null. Try IPv4Address.NONE if intention is 'no IPv4'"); + } + if (ipv6Address == null) { + throw new IllegalArgumentException("IPv6 address cannot be null. Try IPv6Address.NONE if intention is 'no IPv6'"); + } + if (vlan == null) { + throw new IllegalArgumentException("VLAN cannot be null. Try VlanVid.ZERO if intention is 'no VLAN / untagged'"); + } + if (switchDPID == null) { + throw new IllegalArgumentException("Switch DPID cannot be null. Try DatapathId.NONE if intention is 'no DPID'"); + } + if (switchPort == null) { + throw new IllegalArgumentException("Switch port cannot be null. Try OFPort.ZERO if intention is 'no port'"); + } + + Entity e = new Entity(macAddress, vlan, + ipv4Address, ipv6Address, + switchDPID, switchPort, Entity.NO_DATE); + + /* + * allKeyFieldsPresent() will check if the entity key fields (e.g. MAC and VLAN) + * have non-"zero" values i.e. are not set to e.g. MacAddress.NONE and VlanVid.ZERO + */ if (!allKeyFieldsPresent(e, entityClassifier.getKeyFields())) { throw new IllegalArgumentException("Not all key fields specified." + " Required fields: " + entityClassifier.getKeyFields()); @@ -458,17 +482,27 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } @Override - public IDevice findClassDevice(IEntityClass entityClass, MacAddress macAddress, - VlanVid vlan, IPv4Address ipv4Address) + public IDevice findClassDevice(@Nonnull IEntityClass entityClass, @Nonnull MacAddress macAddress, + @Nonnull VlanVid vlan, @Nonnull IPv4Address ipv4Address, @Nonnull IPv6Address ipv6Address) throws IllegalArgumentException { - if (vlan != null && vlan.getVlan() <= 0) - vlan = null; - if (ipv4Address != null && ipv4Address.getInt() == 0) - ipv4Address = null; - Entity e = new Entity(macAddress, vlan, ipv4Address, - null, null, null); - if (entityClass == null || - !allKeyFieldsPresent(e, entityClass.getKeyFields())) { + if (entityClass == null) { + throw new IllegalArgumentException("Entity class cannot be null."); + } + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null. Try MacAddress.NONE if intention is 'no MAC'"); + } + if (ipv4Address == null) { + throw new IllegalArgumentException("IPv4 address cannot be null. Try IPv4Address.NONE if intention is 'no IPv4'"); + } + if (ipv6Address == null) { + throw new IllegalArgumentException("IPv6 address cannot be null. Try IPv6Address.NONE if intention is 'no IPv6'"); + } + if (vlan == null) { + throw new IllegalArgumentException("VLAN cannot be null. Try VlanVid.ZERO if intention is 'no VLAN / untagged'"); + } + + Entity e = new Entity(macAddress, vlan, ipv4Address, ipv6Address, DatapathId.NONE, OFPort.ZERO, Entity.NO_DATE); + if (!allKeyFieldsPresent(e, entityClass.getKeyFields())) { throw new IllegalArgumentException("Not all key fields and/or " + " no source device specified. Required fields: " + entityClassifier.getKeyFields()); @@ -493,15 +527,33 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } @Override - public Iterator<? extends IDevice> queryDevices(MacAddress macAddress, + public Iterator<? extends IDevice> queryDevices(@Nonnull MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { + @Nonnull IPv4Address ipv4Address, + @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, + @Nonnull OFPort switchPort) { + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null. Try MacAddress.NONE if intention is 'no MAC'"); + } + if (ipv4Address == null) { + throw new IllegalArgumentException("IPv4 address cannot be null. Try IPv4Address.NONE if intention is 'no IPv4'"); + } + if (ipv6Address == null) { + throw new IllegalArgumentException("IPv6 address cannot be null. Try IPv6Address.NONE if intention is 'no IPv6'"); + } + /* VLAN can be null in this case, which means 'don't care' */ + if (switchDPID == null) { + throw new IllegalArgumentException("Switch DPID cannot be null. Try DatapathId.NONE if intention is 'no DPID'"); + } + if (switchPort == null) { + throw new IllegalArgumentException("Switch port cannot be null. Try OFPort.ZERO if intention is 'no port'"); + } + DeviceIndex index = null; if (secondaryIndexMap.size() > 0) { EnumSet<DeviceField> keys = - getEntityKeys(macAddress, vlan, ipv4Address, + getEntityKeys(macAddress, vlan, ipv4Address, ipv6Address, switchDPID, switchPort); index = secondaryIndexMap.get(keys); } @@ -515,9 +567,10 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT Entity entity = new Entity(macAddress, vlan, ipv4Address, + ipv6Address, switchDPID, switchPort, - null); + Entity.NO_DATE); deviceIterator = new DeviceIndexInterator(this, index.queryByEntity(entity)); } @@ -528,18 +581,37 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT macAddress, vlan, ipv4Address, + ipv6Address, switchDPID, switchPort); return di; } @Override - public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass, - MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { + public Iterator<? extends IDevice> queryClassDevices(@Nonnull IEntityClass entityClass, + @Nonnull MacAddress macAddress, + @Nonnull VlanVid vlan, + @Nonnull IPv4Address ipv4Address, + @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, + @Nonnull OFPort switchPort) { + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null. Try MacAddress.NONE if intention is 'no MAC'"); + } + if (ipv4Address == null) { + throw new IllegalArgumentException("IPv4 address cannot be null. Try IPv4Address.NONE if intention is 'no IPv4'"); + } + if (ipv6Address == null) { + throw new IllegalArgumentException("IPv6 address cannot be null. Try IPv6Address.NONE if intention is 'no IPv6'"); + } + /* VLAN can be null, which means 'don't care' */ + if (switchDPID == null) { + throw new IllegalArgumentException("Switch DPID cannot be null. Try DatapathId.NONE if intention is 'no DPID'"); + } + if (switchPort == null) { + throw new IllegalArgumentException("Switch port cannot be null. Try OFPort.ZERO if intention is 'no port'"); + } + ArrayList<Iterator<Device>> iterators = new ArrayList<Iterator<Device>>(); ClassState classState = getClassState(entityClass); @@ -548,7 +620,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT if (classState.secondaryIndexMap.size() > 0) { EnumSet<DeviceField> keys = getEntityKeys(macAddress, vlan, ipv4Address, - switchDPID, switchPort); + ipv6Address, switchDPID, switchPort); index = classState.secondaryIndexMap.get(keys); } @@ -560,7 +632,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT return new DeviceIterator(deviceMap.values().iterator(), new IEntityClass[] { entityClass }, macAddress, vlan, ipv4Address, - switchDPID, switchPort); + ipv6Address, switchDPID, switchPort); } else { // scan the entire class iter = new DeviceIndexInterator(this, index.getAll()); @@ -571,9 +643,10 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT new Entity(macAddress, vlan, ipv4Address, + ipv6Address, switchDPID, switchPort, - null); + Entity.NO_DATE); iter = new DeviceIndexInterator(this, index.queryByEntity(entity)); } @@ -582,16 +655,34 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT return new MultiIterator<Device>(iterators.iterator()); } - protected Iterator<Device> getDeviceIteratorForQuery(MacAddress macAddress, + protected Iterator<Device> getDeviceIteratorForQuery(@Nonnull MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { + @Nonnull IPv4Address ipv4Address, + @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, + @Nonnull OFPort switchPort) { + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null. Try MacAddress.NONE if intention is 'no MAC'"); + } + if (ipv4Address == null) { + throw new IllegalArgumentException("IPv4 address cannot be null. Try IPv4Address.NONE if intention is 'no IPv4'"); + } + if (ipv6Address == null) { + throw new IllegalArgumentException("IPv6 address cannot be null. Try IPv6Address.NONE if intention is 'no IPv6'"); + } + /* VLAN can be null, which means 'don't care' */ + if (switchDPID == null) { + throw new IllegalArgumentException("Switch DPID cannot be null. Try DatapathId.NONE if intention is 'no DPID'"); + } + if (switchPort == null) { + throw new IllegalArgumentException("Switch port cannot be null. Try OFPort.ZERO if intention is 'no port'"); + } + DeviceIndex index = null; if (secondaryIndexMap.size() > 0) { EnumSet<DeviceField> keys = getEntityKeys(macAddress, vlan, ipv4Address, - switchDPID, switchPort); + ipv6Address, switchDPID, switchPort); index = secondaryIndexMap.get(keys); } @@ -604,9 +695,10 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT Entity entity = new Entity(macAddress, vlan, ipv4Address, + ipv6Address, switchDPID, switchPort, - null); + Entity.NO_DATE); deviceIterator = new DeviceIndexInterator(this, index.queryByEntity(entity)); } @@ -617,6 +709,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT macAddress, vlan, ipv4Address, + ipv6Address, switchDPID, switchPort); return di; @@ -694,6 +787,11 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT public void deviceIPV4AddrChanged(IDevice device) { generateDeviceEvent(device, "host-ipv4-addr-changed"); } + + @Override + public void deviceIPV6AddrChanged(IDevice device) { + generateDeviceEvent(device, "host-ipv6-addr-changed"); + } @Override public void deviceVlanChanged(IDevice device) { @@ -703,6 +801,8 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT private void generateDeviceEvent(IDevice device, String reason) { List<IPv4Address> ipv4Addresses = new ArrayList<IPv4Address>(Arrays.asList(device.getIPv4Addresses())); + List<IPv6Address> ipv6Addresses = + new ArrayList<IPv6Address>(Arrays.asList(device.getIPv6Addresses())); List<SwitchPort> oldAps = new ArrayList<SwitchPort>(Arrays.asList(device.getOldAP())); List<SwitchPort> currentAps = @@ -712,6 +812,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT debugEventCategory.newEventNoFlush(new DeviceEvent(device.getMACAddress(), ipv4Addresses, + ipv6Addresses, oldAps, currentAps, vlanIds, reason)); @@ -807,7 +908,8 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT public void init(FloodlightModuleContext fmc) throws FloodlightModuleException { this.perClassIndices = new HashSet<EnumSet<DeviceField>>(); - addIndex(true, EnumSet.of(DeviceField.IPV4)); + addIndex(true, EnumSet.of(DeviceField.IPv4)); + addIndex(true, EnumSet.of(DeviceField.IPv6)); this.deviceListeners = new ListenerDispatcher<String, IDeviceListener>(); this.suppressAPs = Collections.newSetFromMap( @@ -1055,7 +1157,6 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT @Override public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type, String name) { - // TODO Auto-generated method stub return false; } @@ -1173,14 +1274,14 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } /** - * Get sender IP address from packet if the packet is an ARP + * Get sender IPv4 address from packet if the packet is an ARP * packet and if the source MAC address matches the ARP packets * sender MAC address. * @param eth * @param dlAddr * @return */ - private IPv4Address getSrcNwAddr(Ethernet eth, MacAddress dlAddr) { + private IPv4Address getSrcIPv4AddrFromARP(Ethernet eth, MacAddress dlAddr) { if (eth.getPayload() instanceof ARP) { ARP arp = (ARP) eth.getPayload(); if ((arp.getProtocolType() == ARP.PROTO_TYPE_IP) && (arp.getSenderHardwareAddress().equals(dlAddr))) { @@ -1189,6 +1290,21 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } return IPv4Address.NONE; } + + /** + * Get sender IPv6 address from packet if the packet is ND + * + * @param eth + * @param dlAddr + * @return + */ + private IPv6Address getSrcIPv6Addr(Ethernet eth) { + if (eth.getPayload() instanceof IPv6) { + IPv6 ipv6 = (IPv6) eth.getPayload(); + return ipv6.getSourceAddress(); + } + return IPv6Address.NONE; + } /** * Parse an entity from an {@link Ethernet} packet. @@ -1208,10 +1324,12 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT return null; VlanVid vlan = VlanVid.ofVlan(eth.getVlanID()); - IPv4Address nwSrc = getSrcNwAddr(eth, dlAddr); + IPv4Address ipv4Src = getSrcIPv4AddrFromARP(eth, dlAddr); + IPv6Address ipv6Src = ipv4Src.equals(IPv4Address.NONE) ? getSrcIPv6Addr(eth) : IPv6Address.NONE; return new Entity(dlAddr, vlan, - nwSrc, + ipv4Src, + ipv6Src, swdpid, port, new Date()); @@ -1239,15 +1357,16 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT if (senderAddr.isBroadcast() || senderAddr.isMulticast()) return; // Ignore zero sender mac - if (senderAddr.getLong() == 0) + if (senderAddr.equals(MacAddress.of(0))) return; VlanVid vlan = VlanVid.ofVlan(eth.getVlanID()); IPv4Address nwSrc = arp.getSenderProtocolAddress(); Entity e = new Entity(senderAddr, - ((vlan.getVlan() >= 0) ? vlan : null), - ((nwSrc.getInt() != 0) ? nwSrc : null), + vlan, /* will either be a valid tag or VlanVid.ZERO if untagged */ + nwSrc, + IPv6Address.NONE, /* must be none for ARP */ swdpid, port, new Date()); @@ -1263,26 +1382,31 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT protected Entity getDestEntityFromPacket(Ethernet eth) { MacAddress dlAddr = eth.getDestinationMACAddress(); VlanVid vlan = VlanVid.ofVlan(eth.getVlanID()); - IPv4Address nwDst = IPv4Address.NONE; + IPv4Address ipv4Dst = IPv4Address.NONE; + IPv6Address ipv6Dst = IPv6Address.NONE; // Ignore broadcast/multicast destination if (dlAddr.isBroadcast() || dlAddr.isMulticast()) return null; // Ignore zero dest mac - if (dlAddr.getLong() == 0) + if (dlAddr.equals(MacAddress.of(0))) return null; if (eth.getPayload() instanceof IPv4) { IPv4 ipv4 = (IPv4) eth.getPayload(); - nwDst = ipv4.getDestinationAddress(); + ipv4Dst = ipv4.getDestinationAddress(); + } else if (eth.getPayload() instanceof IPv6) { + IPv6 ipv6 = (IPv6) eth.getPayload(); + ipv6Dst = ipv6.getDestinationAddress(); } return new Entity(dlAddr, vlan, - nwDst, - null, - null, - null); + ipv4Dst, + ipv6Dst, + DatapathId.NONE, + OFPort.ZERO, + Entity.NO_DATE); } /** @@ -1497,12 +1621,13 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT cntPacketOnInternalPortForKnownDevice.increment(); break; } + int entityindex = -1; if ((entityindex = device.entityIndex(entity)) >= 0) { // Entity already exists // update timestamp on the found entity Date lastSeen = entity.getLastSeenTimestamp(); - if (lastSeen == null) { + if (lastSeen.equals(Entity.NO_DATE)) { lastSeen = new Date(); entity.setLastSeenTimestamp(lastSeen); } @@ -1553,11 +1678,9 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT boolean moved = device.updateAttachmentPoint(entity.getSwitchDPID(), entity.getSwitchPort(), entity.getLastSeenTimestamp()); - // TODO: use update mechanism instead of sending the - // notification directly if (moved) { // we count device moved events in sendDeviceMovedNotification() - sendDeviceMovedNotification(device); + // TODO remove this. It's now done in the event handler as a result of the update above... sendDeviceMovedNotification(device); if (logger.isTraceEnabled()) { logger.trace("Device moved: attachment points {}," + "entities {}", device.attachmentPoints, @@ -1591,45 +1714,51 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT return true; } - - - - protected EnumSet<DeviceField> findChangedFields(Device device, Entity newEntity) { EnumSet<DeviceField> changedFields = - EnumSet.of(DeviceField.IPV4, + EnumSet.of(DeviceField.IPv4, + DeviceField.IPv6, DeviceField.VLAN, DeviceField.SWITCH); - if (newEntity.getIpv4Address() == null) - changedFields.remove(DeviceField.IPV4); - if (newEntity.getVlan() == null) + /* + * Do we really need this here? + * + if (newEntity.getIpv4Address().equals(IPv4Address.NONE)) + changedFields.remove(DeviceField.IPv4); + if (newEntity.getIpv6Address().equals(IPv6Address.NONE)) + changedFields.remove(DeviceField.IPv6); + /*if (newEntity.getVlan().equals(VlanVid.ZERO)) TODO VLAN is ZERO here, since the actual Device and Entity must have some sort of VLAN, either untagged (ZERO) or some value changedFields.remove(DeviceField.VLAN); - if (newEntity.getSwitchDPID() == null || - newEntity.getSwitchPort() == null) - changedFields.remove(DeviceField.SWITCH); + if (newEntity.getSwitchDPID().equals(DatapathId.NONE) || + newEntity.getSwitchPort().equals(OFPort.ZERO)) + changedFields.remove(DeviceField.SWITCH); - if (changedFields.size() == 0) return changedFields; + if (changedFields.size() == 0) return changedFields; */ for (Entity entity : device.getEntities()) { - if (newEntity.getIpv4Address() == null || - (entity.getIpv4Address() != null && - entity.getIpv4Address().equals(newEntity.getIpv4Address()))) - changedFields.remove(DeviceField.IPV4); - if (newEntity.getVlan() == null || - (entity.getVlan() != null && - entity.getVlan().equals(newEntity.getVlan()))) + if (newEntity.getIpv4Address().equals(IPv4Address.NONE) || /* NONE means 'not in this packet' */ + entity.getIpv4Address().equals(newEntity.getIpv4Address())) /* these (below) might be defined and if they are and changed, then the device has changed */ + changedFields.remove(DeviceField.IPv4); + if (newEntity.getIpv6Address().equals(IPv6Address.NONE) || /* NONE means 'not in this packet' */ + entity.getIpv6Address().equals(newEntity.getIpv6Address())) + changedFields.remove(DeviceField.IPv6); + if (entity.getVlan().equals(newEntity.getVlan())) /* these (below) must be defined in each and every packet-in, and if different signal a device field change */ changedFields.remove(DeviceField.VLAN); - if (newEntity.getSwitchDPID() == null || - newEntity.getSwitchPort() == null || - (entity.getSwitchDPID() != null && - entity.getSwitchPort() != null && - entity.getSwitchDPID().equals(newEntity.getSwitchDPID()) && + if (newEntity.getSwitchDPID().equals(DatapathId.NONE) || + newEntity.getSwitchPort().equals(OFPort.ZERO) || + (entity.getSwitchDPID().equals(newEntity.getSwitchDPID()) && entity.getSwitchPort().equals(newEntity.getSwitchPort()))) changedFields.remove(DeviceField.SWITCH); } + if (changedFields.contains(DeviceField.SWITCH)) { + if (!isValidAttachmentPoint(newEntity.getSwitchDPID(), newEntity.getSwitchPort())) { + changedFields.remove(DeviceField.SWITCH); + } + } + return changedFields; } @@ -1669,12 +1798,15 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT case CHANGE: for (DeviceField field : update.fieldsChanged) { switch (field) { - case IPV4: + case IPv4: listener.deviceIPV4AddrChanged(update.device); break; + case IPv6: + listener.deviceIPV6AddrChanged(update.device); + break; case SWITCH: case PORT: - //listener.deviceMoved(update.device); + listener.deviceMoved(update.device); // TODO why was this commented out? break; case VLAN: listener.deviceVlanChanged(update.device); @@ -1702,19 +1834,26 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT case MAC: // MAC address is always present break; - case IPV4: - if (e.ipv4Address == null) return false; + case IPv4: + case IPv6: + if (e.ipv4Address.equals(IPv4Address.NONE) && e.ipv6Address.equals(IPv6Address.NONE)) { + return false; // mutually exclusive + } break; case SWITCH: - if (e.switchDPID == null) return false; + if (e.switchDPID.equals(DatapathId.NONE)) { + return false; + } break; case PORT: - if (e.switchPort == null) return false; + if (e.switchPort.equals(OFPort.ZERO)) { + return false; + } break; case VLAN: - // FIXME: vlan==null is ambiguous: it can mean: not present - // or untagged - //if (e.vlan == null) return false; + if (e.vlan == null) { /* VLAN is null for 'don't care' or 'unspecified'. It's VlanVid.ZERO for untagged. */ + return false; /* For key field of VLAN, the VLAN **MUST** be set to either ZERO or some value. */ + } break; default: // we should never get here. unless somebody extended @@ -1819,7 +1958,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT toRemove.clear(); toKeep.clear(); for (Entity e : d.getEntities()) { - if (e.getLastSeenTimestamp() != null && + if (!e.getLastSeenTimestamp().equals(Entity.NO_DATE) && 0 > e.getLastSeenTimestamp().compareTo(cutoff)) { // individual entity needs to be removed toRemove.add(e); @@ -1937,20 +2076,19 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } } - private EnumSet<DeviceField> getEntityKeys(MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { - // FIXME: vlan==null is a valid search. Need to handle this - // case correctly. Note that the code will still work correctly. - // But we might do a full device search instead of using an index. + private EnumSet<DeviceField> getEntityKeys(@Nonnull MacAddress macAddress, + VlanVid vlan, /* A null VLAN means 'don't care'; VlanVid.ZERO means 'untagged' */ + @Nonnull IPv4Address ipv4Address, + @Nonnull IPv6Address ipv6Address, + @Nonnull DatapathId switchDPID, + @Nonnull OFPort switchPort) { EnumSet<DeviceField> keys = EnumSet.noneOf(DeviceField.class); - if (macAddress != null) keys.add(DeviceField.MAC); - if (vlan != null) keys.add(DeviceField.VLAN); - if (ipv4Address != null) keys.add(DeviceField.IPV4); - if (switchDPID != null) keys.add(DeviceField.SWITCH); - if (switchPort != null) keys.add(DeviceField.PORT); + if (!macAddress.equals(MacAddress.NONE)) keys.add(DeviceField.MAC); + if (vlan != null) keys.add(DeviceField.VLAN); /* TODO verify fix. null means 'don't care' and will conduct full search; VlanVid.ZERO means 'untagged' and only uses untagged index */ + if (!ipv4Address.equals(IPv4Address.NONE)) keys.add(DeviceField.IPv4); + if (!ipv6Address.equals(IPv6Address.NONE)) keys.add(DeviceField.IPv6); + if (!switchDPID.equals(DatapathId.NONE)) keys.add(DeviceField.SWITCH); + if (!switchPort.equals(OFPort.ZERO)) keys.add(DeviceField.PORT); return keys; } @@ -1969,7 +2107,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT return new Device(this, deviceKey, entity, entityClass); } - // TODO: FIX THIS. + // TODO: FIX THIS. What's 'this' that needs fixing? protected Device allocateDevice(Long deviceKey, String dhcpClientName, List<AttachmentPoint> aps, @@ -1986,7 +2124,8 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT return new Device(device, entity, insertionpoint); } - //not used + //not used + /* TODO then let's get rid of it? protected Device allocateDevice(Device device, Set <Entity> entities) { List <AttachmentPoint> newPossibleAPs = new ArrayList<AttachmentPoint>(); @@ -2014,7 +2153,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT entities, device.getEntityClass()); d.updateAttachmentPoint(); return d; - } + } */ // ********************* // ITopologyListener @@ -2033,7 +2172,6 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT } } } - while (diter.hasNext()) { Device d = diter.next(); if (d.updateAttachmentPoint()) { @@ -2353,6 +2491,7 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT // Do we have a device for this entity?? IDevice d = findDevice(MacAddress.of(se.macAddress), VlanVid.ofVlan(se.vlan), IPv4Address.of(se.ipv4Address), + IPv6Address.NONE, DatapathId.of(se.switchDPID), OFPort.of(se.switchPort)); if (d != null) { @@ -2408,8 +2547,10 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT private class DeviceEvent { @EventColumn(name = "MAC", description = EventFieldType.MAC) private final MacAddress macAddress; - @EventColumn(name = "IPs", description = EventFieldType.IPv4) + @EventColumn(name = "IPv4s", description = EventFieldType.IPv4) private final List<IPv4Address> ipv4Addresses; + @EventColumn(name = "IPv6s", description = EventFieldType.IPv6) + private final List<IPv6Address> ipv6Addresses; @EventColumn(name = "Old Attachment Points", description = EventFieldType.COLLECTION_ATTACHMENT_POINT) private final List<SwitchPort> oldAttachmentPoints; @@ -2422,16 +2563,18 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT private final String reason; public DeviceEvent(MacAddress macAddress, List<IPv4Address> ipv4Addresses, + List<IPv6Address> ipv6Addresses, List<SwitchPort> oldAttachmentPoints, List<SwitchPort> currentAttachmentPoints, List<VlanVid> vlanIds, String reason) { super(); this.macAddress = macAddress; this.ipv4Addresses = ipv4Addresses; + this.ipv6Addresses = ipv6Addresses; this.oldAttachmentPoints = oldAttachmentPoints; this.currentAttachmentPoints = currentAttachmentPoints; this.vlanIds = vlanIds; this.reason = reason; } } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java index df47d32b2558df200cf8f02154cbde6444411ff4..a603696054c8339b906fed8256411dc818c5d5aa 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java @@ -78,7 +78,7 @@ public class DeviceMultiIndex extends DeviceIndex { Collection<Long> devices = null; IndexedEntity ie = new IndexedEntity(keyFields, entity); - if (!ie.hasNonNullKeys()) return false; + if (!ie.hasNonZeroOrNonNullKeys()) return false; devices = index.get(ie); if (devices == null) { @@ -106,4 +106,4 @@ public class DeviceMultiIndex extends DeviceIndex { if (devices != null) devices.remove(deviceKey); } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java index 82fb832e5d7049fc0342b7f7a10caabcb0891567..d0846c2a25abf2be1cb3323888fe64714e0c4f3d 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java @@ -9,6 +9,7 @@ import java.util.List; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -19,152 +20,160 @@ import net.floodlightcontroller.devicemanager.SwitchPort; import com.fasterxml.jackson.annotation.JsonProperty; public class DeviceSyncRepresentation { - public static class SyncEntity implements Comparable<SyncEntity> { - @JsonProperty - public long macAddress; - @JsonProperty - public int ipv4Address; - @JsonProperty - public short vlan; - @JsonProperty - public long switchDPID; - @JsonProperty - public int switchPort; - @JsonProperty - public Date lastSeenTimestamp; - @JsonProperty - public Date activeSince; - - public SyncEntity() { - // do nothing; - } - - public SyncEntity(Entity e) { - this.macAddress = (e.getMacAddress() != null ? e.getMacAddress().getLong() : 0); - this.ipv4Address = (e.getIpv4Address() != null ? e.getIpv4Address().getInt() : 0); - this.vlan = (e.getVlan() != null ? e.getVlan().getVlan() : -1); - this.switchDPID = (e.getSwitchDPID() != null ? e.getSwitchDPID().getLong() : 0); - this.switchPort = (e.getSwitchPort() != null ? e.getSwitchPort().getPortNumber() : 0); - if (e.getLastSeenTimestamp() == null) - this.lastSeenTimestamp = null; - else - this.lastSeenTimestamp = new Date(e.getLastSeenTimestamp().getTime()); - if (e.getActiveSince() == null) - this.activeSince = null; - else - this.activeSince = new Date(e.getActiveSince().getTime()); - } - - public Entity asEntity() { - Entity e = new Entity(macAddress == 0 ? null : MacAddress.of(macAddress), - vlan == -1 ? null : VlanVid.ofVlan(vlan), - ipv4Address == 0 ? null : IPv4Address.of(ipv4Address), - switchDPID == 0 ? null : DatapathId.of(switchDPID), - switchPort == 0 ? null : OFPort.of(switchPort), - lastSeenTimestamp); - e.setActiveSince(activeSince); - return e; - } - - @Override - public int compareTo(SyncEntity other) { - return lastSeenTimestamp.compareTo(other.lastSeenTimestamp); - } - - @Override - public String toString() { - return asEntity().toString(); - } - } - - private String key; - private List<SyncEntity> entities; - - public DeviceSyncRepresentation() { - // do nothing - } - - public DeviceSyncRepresentation(Device device) { - this.key = computeKey(device); - this.entities = new ArrayList<SyncEntity>(); - // FIXME: do we need the APs with errors as well?? - // FIXME - SwitchPort[] aps = device.getAttachmentPoints(); - for(Entity e: device.getEntities()) { - // Add the entities from the device only if they either don't - // have a switch/port or if they are an attachment point or - // if they have an IP address. - if (!e.hasSwitchPort()) { - this.entities.add(new SyncEntity(e)); - } else if (isAttachmentPointEntity(aps, e)) { - this.entities.add(new SyncEntity(e)); - } else if (e.getIpv4Address() != null) { - this.entities.add(new SyncEntity(e)); - } - } - Collections.sort(this.entities); - } - - private static boolean isAttachmentPointEntity(SwitchPort[] aps, Entity e) { - if (!e.hasSwitchPort()) - return false; - for (SwitchPort p: aps) { - if (e.getSwitchDPID().equals(p.getSwitchDPID()) && - e.getSwitchPort().equals(p.getPort())) { - return true; - } - } - return false; - } - - static String computeKey(Device d) { - StringBuilder bld = new StringBuilder(d.getEntityClass().getName()); - bld.append("::"); - EnumSet<DeviceField> keyFields = d.getEntityClass().getKeyFields(); - if (keyFields.contains(DeviceField.MAC)) { - bld.append(d.getMACAddressString()); - bld.append("::"); - } - if (keyFields.contains(DeviceField.VLAN)) { - if (d.getVlanId() != null) - bld.append(Arrays.toString(d.getVlanId())); - bld.append("::"); - } - if (keyFields.contains(DeviceField.SWITCH) || - keyFields.contains(DeviceField.PORT) ) { - if (d.getAttachmentPoints(true) != null) - bld.append(Arrays.toString(d.getAttachmentPoints(true))); - bld.append("::"); - } - if (keyFields.contains(DeviceField.IPV4)) { - if (d.getIPv4Addresses() != null) - bld.append(Arrays.toString(d.getIPv4Addresses())); - bld.append("::"); - } - return bld.toString(); - } - - public String getKey() { - return key; - } - public void setKey(String key) { - this.key = key; - } - public List<SyncEntity> getEntities() { - return entities; - } - public void setEntities(List<SyncEntity> entities) { - if (entities == null) { - this.entities = null; - } else { - List<SyncEntity> tmp = new ArrayList<SyncEntity>(entities); - Collections.sort(tmp); - this.entities = tmp; - } - } - - @Override - public String toString() { - return key; - } + public static class SyncEntity implements Comparable<SyncEntity> { + @JsonProperty + public long macAddress; + @JsonProperty + public int ipv4Address; // TODO Sync IPv6 address + @JsonProperty + public short vlan; + @JsonProperty + public long switchDPID; + @JsonProperty + public int switchPort; + @JsonProperty + public Date lastSeenTimestamp; + @JsonProperty + public Date activeSince; + + public SyncEntity() { + // do nothing; + } + + public SyncEntity(Entity e) { + this.macAddress = (e.getMacAddress() != null ? e.getMacAddress().getLong() : 0); + this.ipv4Address = (e.getIpv4Address() != null ? e.getIpv4Address().getInt() : 0); + this.vlan = (e.getVlan() != null ? e.getVlan().getVlan() : -1); + this.switchDPID = (e.getSwitchDPID() != null ? e.getSwitchDPID().getLong() : 0); + this.switchPort = (e.getSwitchPort() != null ? e.getSwitchPort().getPortNumber() : 0); + if (e.getLastSeenTimestamp() == null) + this.lastSeenTimestamp = null; + else + this.lastSeenTimestamp = new Date(e.getLastSeenTimestamp().getTime()); + if (e.getActiveSince() == null) + this.activeSince = null; + else + this.activeSince = new Date(e.getActiveSince().getTime()); + } + + public Entity asEntity() { + Entity e = new Entity(MacAddress.of(macAddress), + VlanVid.ofVlan(vlan), + IPv4Address.of(ipv4Address), + IPv6Address.NONE, + DatapathId.of(switchDPID), + OFPort.of(switchPort), + lastSeenTimestamp); + e.setActiveSince(activeSince); + return e; + } + + @Override + public int compareTo(SyncEntity other) { + return lastSeenTimestamp.compareTo(other.lastSeenTimestamp); + } + + @Override + public String toString() { + return asEntity().toString(); + } + } + + private String key; + private List<SyncEntity> entities; + + public DeviceSyncRepresentation() { + // do nothing + } + + public DeviceSyncRepresentation(Device device) { + this.key = computeKey(device); + this.entities = new ArrayList<SyncEntity>(); + // FIXME: do we need the APs with errors as well?? + // FIXME + SwitchPort[] aps = device.getAttachmentPoints(); + for (Entity e : device.getEntities()) { + // Add the entities from the device only if they either don't + // have a switch/port or if they are an attachment point or + // if they have an IP address. + if (!e.hasSwitchPort()) { + this.entities.add(new SyncEntity(e)); + } else if (isAttachmentPointEntity(aps, e)) { + this.entities.add(new SyncEntity(e)); + } else if (!e.getIpv4Address().equals(IPv4Address.NONE)) { + this.entities.add(new SyncEntity(e)); + } + } + Collections.sort(this.entities); + } + + private static boolean isAttachmentPointEntity(SwitchPort[] aps, Entity e) { + if (!e.hasSwitchPort()) + return false; + for (SwitchPort p : aps) { + if (e.getSwitchDPID().equals(p.getSwitchDPID()) && + e.getSwitchPort().equals(p.getPort()) + && (!e.getSwitchDPID().equals(DatapathId.NONE) || + !e.getSwitchPort().equals(OFPort.ZERO))) { + return true; + } + } + return false; + } + + static String computeKey(Device d) { + StringBuilder bld = new StringBuilder(d.getEntityClass().getName()); + bld.append("::"); + EnumSet<DeviceField> keyFields = d.getEntityClass().getKeyFields(); + if (keyFields.contains(DeviceField.MAC)) { + bld.append(d.getMACAddressString()); + bld.append("::"); + } + if (keyFields.contains(DeviceField.VLAN)) { + if (d.getVlanId() != null) + bld.append(Arrays.toString(d.getVlanId())); + bld.append("::"); + } + if (keyFields.contains(DeviceField.SWITCH) || + keyFields.contains(DeviceField.PORT) ) { + if (d.getAttachmentPoints(true) != null) + bld.append(Arrays.toString(d.getAttachmentPoints(true))); + bld.append("::"); + } + if (keyFields.contains(DeviceField.IPv4)) { + if (d.getIPv4Addresses() != null) + bld.append(Arrays.toString(d.getIPv4Addresses())); + bld.append("::"); + } + if (keyFields.contains(DeviceField.IPv6)) { + if (d.getIPv6Addresses() != null) + bld.append(Arrays.toString(d.getIPv6Addresses())); + bld.append("::"); + } + return bld.toString(); + } + + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + public List<SyncEntity> getEntities() { + return entities; + } + public void setEntities(List<SyncEntity> entities) { + if (entities == null) { + this.entities = null; + } else { + List<SyncEntity> tmp = new ArrayList<SyncEntity>(entities); + Collections.sort(tmp); + this.entities = tmp; + } + } + + @Override + public String toString() { + return key; + } } diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java index e373018bff2bc02a02a41384ae58daadaf45cb0b..3917f493b0788f409babae395de503cba71f0e6a 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java @@ -64,7 +64,7 @@ public class DeviceUniqueIndex extends DeviceIndex { public boolean updateIndex(Device device, Long deviceKey) { for (Entity e : device.entities) { IndexedEntity ie = new IndexedEntity(keyFields, e); - if (!ie.hasNonNullKeys()) continue; + if (!ie.hasNonZeroOrNonNullKeys()) continue; Long ret = index.putIfAbsent(ie, deviceKey); if (ret != null && !ret.equals(deviceKey)) { @@ -80,7 +80,7 @@ public class DeviceUniqueIndex extends DeviceIndex { @Override public boolean updateIndex(Entity entity, Long deviceKey) { IndexedEntity ie = new IndexedEntity(keyFields, entity); - if (!ie.hasNonNullKeys()) return false; + if (!ie.hasNonZeroOrNonNullKeys()) return false; index.put(ie, deviceKey); return true; } @@ -113,5 +113,4 @@ public class DeviceUniqueIndex extends DeviceIndex { return null; return deviceKey; } - -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java index 79c0199feae753336072b497e609ae891e13f81b..d1d24be6f19cfd8386a414827ab5bf878b6e1c2b 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java @@ -19,7 +19,10 @@ package net.floodlightcontroller.devicemanager.internal; import java.util.Date; +import javax.annotation.Nonnull; + import net.floodlightcontroller.core.web.serializers.IPv4Serializer; +import net.floodlightcontroller.core.web.serializers.IPv6Serializer; import net.floodlightcontroller.core.web.serializers.DPIDSerializer; import net.floodlightcontroller.core.web.serializers.OFPortSerializer; import net.floodlightcontroller.core.web.serializers.VlanVidSerializer; @@ -30,6 +33,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -55,17 +59,25 @@ public class Entity implements Comparable<Entity> { */ protected static int ACTIVITY_TIMEOUT = 30000; + protected static final Date NO_DATE = new Date(0); /* Jan 1st 1970 00:00:00 */ + /** * The MAC address associated with this entity */ protected MacAddress macAddress; /** - * The IP address associated with this entity, or null if no IP learned + * The IPv4 address associated with this entity, or null if no IP learned * from the network observation associated with this entity */ protected IPv4Address ipv4Address; + /** + * The IPv6 address associated with this entity, or null if no IP learned + * from the network observation associated with this entity + */ + protected IPv6Address ipv6Address; + /** * The VLAN tag on this entity, or null if untagged */ @@ -108,15 +120,37 @@ public class Entity implements Comparable<Entity> { * @param macAddress * @param vlan * @param ipv4Address + * @param ipv6Address * @param switchDPID * @param switchPort * @param lastSeenTimestamp */ - public Entity(MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, DatapathId switchDPID, OFPort switchPort, - Date lastSeenTimestamp) { + public Entity(@Nonnull MacAddress macAddress, VlanVid vlan, @Nonnull IPv4Address ipv4Address, + @Nonnull IPv6Address ipv6Address, @Nonnull DatapathId switchDPID, @Nonnull OFPort switchPort, + @Nonnull Date lastSeenTimestamp) { + if (macAddress == null) { + throw new IllegalArgumentException("MAC address cannot be null. Try MacAddress.NONE if intention is 'no MAC'"); + } + if (ipv4Address == null) { + throw new IllegalArgumentException("IPv4 address cannot be null. Try IPv4Address.NONE if intention is 'no IPv4'"); + } + if (ipv6Address == null) { + throw new IllegalArgumentException("IPv6 address cannot be null. Try IPv6Address.NONE if intention is 'no IPv6'"); + } + /* VLAN can be null for 'don't care' in query searches */ + if (switchDPID == null) { + throw new IllegalArgumentException("Switch DPID cannot be null. Try DatapathId.NONE if intention is 'no DPID'"); + } + if (switchPort == null) { + throw new IllegalArgumentException("Switch port cannot be null. Try OFPort.ZERO if intention is 'no port'"); + } + if (lastSeenTimestamp == null) { + throw new IllegalArgumentException("Last seen time stamp cannot be null. Try Entity.NO_DATE if intention is 'no time'"); + } + this.macAddress = macAddress; this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; this.vlan = vlan; this.switchDPID = switchDPID; this.switchPort = switchPort; @@ -138,6 +172,11 @@ public class Entity implements Comparable<Entity> { return ipv4Address; } + @JsonSerialize(using=IPv6Serializer.class) + public IPv6Address getIpv6Address() { + return ipv6Address; + } + @JsonSerialize(using=VlanVidSerializer.class) public VlanVid getVlan() { return vlan; @@ -169,7 +208,8 @@ public class Entity implements Comparable<Entity> { * @see {@link Entity#activeSince} */ public void setLastSeenTimestamp(Date lastSeenTimestamp) { - if (activeSince == null || (activeSince.getTime() + ACTIVITY_TIMEOUT) < lastSeenTimestamp.getTime()) + if (activeSince.equals(Entity.NO_DATE) || + (activeSince.getTime() + ACTIVITY_TIMEOUT) < lastSeenTimestamp.getTime()) this.activeSince = lastSeenTimestamp; this.lastSeenTimestamp = lastSeenTimestamp; } @@ -188,6 +228,8 @@ public class Entity implements Comparable<Entity> { int result = 1; result = prime * result + ((ipv4Address == null) ? 0 : ipv4Address.hashCode()); + result = prime * result + + ((ipv6Address == null) ? 0 : ipv6Address.hashCode()); result = prime * result + ((macAddress == null) ? 0 : macAddress.hashCode()); result = prime * result @@ -207,11 +249,18 @@ public class Entity implements Comparable<Entity> { if (getClass() != obj.getClass()) return false; Entity other = (Entity) obj; + if (hashCode() != obj.hashCode()) + return false; if (ipv4Address == null) { if (other.ipv4Address != null) return false; } else if (!ipv4Address.equals(other.ipv4Address)) return false; + if (ipv6Address == null) { + if (other.ipv6Address != null) + return false; + } else if (!ipv6Address.equals(other.ipv6Address)) + return false; if (macAddress == null) { if (other.macAddress != null) return false; @@ -235,8 +284,6 @@ public class Entity implements Comparable<Entity> { return true; } - - @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -252,6 +299,12 @@ public class Entity implements Comparable<Entity> { } else { builder.append("null"); } + builder.append(", ipv6Address="); + if (ipv4Address != null) { + builder.append(ipv6Address.toString()); + } else { + builder.append("null"); + } builder.append(", vlan="); if (vlan != null) { builder.append(vlan.getVlan()); @@ -272,13 +325,14 @@ public class Entity implements Comparable<Entity> { } builder.append(", lastSeenTimestamp="); if (lastSeenTimestamp != null) { - builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.getTime()); + builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.toString()); + } else { builder.append("null"); } builder.append(", activeSince="); if (activeSince != null) { - builder.append(activeSince == null? "null" : activeSince.getTime()); + builder.append(activeSince == null? "null" : activeSince.toString()); } else { builder.append("null"); } @@ -315,6 +369,14 @@ public class Entity implements Comparable<Entity> { else r = ipv4Address.compareTo(o.ipv4Address); if (r != 0) return r; + + if (ipv6Address == null) + r = o.ipv6Address == null ? 0 : -1; + else if (o.ipv6Address == null) + r = 1; + else + r = ipv6Address.compareTo(o.ipv6Address); + if (r != 0) return r; if (vlan == null) r = o.vlan == null ? 0 : -1; @@ -326,5 +388,4 @@ public class Entity implements Comparable<Entity> { return 0; } - -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java index 6fb1dda1305e4e35e86cf95131a2edf17f843895..503b268529c4bfecdb2ce0b6833ed46c3a7dc9cd 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java @@ -18,6 +18,10 @@ package net.floodlightcontroller.devicemanager.internal; import java.util.EnumSet; +import org.projectfloodlight.openflow.types.DatapathId; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; +import org.projectfloodlight.openflow.types.OFPort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,24 +55,27 @@ public class IndexedEntity { } /** - * Check whether this entity has non-null values in any of its key fields + * Check whether this entity has non-'zero' values in any of its key fields * @return true if any key fields have a non-null value */ - public boolean hasNonNullKeys() { + public boolean hasNonZeroOrNonNullKeys() { for (DeviceField f : keyFields) { switch (f) { - case MAC: + case MAC: /* We assume operation over Ethernet, thus all devices must have a MAC */ return true; - case IPV4: - if (entity.ipv4Address != null) return true; + case IPv4: + if (!entity.ipv4Address.equals(IPv4Address.NONE)) return true; + break; + case IPv6: + if (!entity.ipv6Address.equals(IPv6Address.NONE)) return true; break; case SWITCH: - if (entity.switchDPID != null) return true; + if (!entity.switchDPID.equals(DatapathId.NONE)) return true; break; case PORT: - if (entity.switchPort != null) return true; + if (!entity.switchPort.equals(OFPort.ZERO)) return true; break; - case VLAN: + case VLAN: /* VLAN can still be null, meaning 'don't care'. VlanVid.ZERO means 'untagged' */ if (entity.vlan != null) return true; break; } @@ -92,12 +99,18 @@ public class IndexedEntity { + (int) (entity.macAddress.getLong() ^ (entity.macAddress.getLong() >>> 32)); break; - case IPV4: + case IPv4: hashCode = prime * hashCode + ((entity.ipv4Address == null) ? 0 : entity.ipv4Address.hashCode()); break; + case IPv6: + hashCode = prime * hashCode + + ((entity.ipv6Address == null) + ? 0 + : entity.ipv6Address.hashCode()); + break; case SWITCH: hashCode = prime * hashCode + ((entity.switchDPID == null) @@ -137,11 +150,16 @@ public class IndexedEntity { if (!entity.macAddress.equals(other.entity.macAddress)) return false; break; - case IPV4: + case IPv4: if (entity.ipv4Address == null) { if (other.entity.ipv4Address != null) return false; } else if (!entity.ipv4Address.equals(other.entity.ipv4Address)) return false; break; + case IPv6: + if (entity.ipv6Address == null) { + if (other.entity.ipv6Address != null) return false; + } else if (!entity.ipv6Address.equals(other.entity.ipv6Address)) return false; + break; case SWITCH: if (entity.switchDPID == null) { if (other.entity.switchDPID != null) return false; @@ -158,10 +176,7 @@ public class IndexedEntity { } else if (!entity.vlan.equals(other.entity.vlan)) return false; break; } - } - + } return true; } - - -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java b/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java index 512e4912babe760a3dbf44049465fd4424f0e96e..595650f45ad385c76c4f5cf49148102a877c9d25 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java @@ -27,6 +27,7 @@ import net.floodlightcontroller.util.FilterIterator; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -46,6 +47,8 @@ public abstract class AbstractDeviceResource extends ServerResource { public static final String IPV4_ERROR = "Invalid IPv4 address: must be in dotted decimal format, " + "234.0.59.1"; + public static final String IPV6_ERROR = + "Invalid IPv6 address: must be a valid IPv6 format."; public static final String DPID_ERROR = "Invalid Switch DPID: must be a 64-bit quantity, expressed in " + "hex as AA:BB:CC:DD:EE:FF:00:11"; @@ -57,16 +60,18 @@ public abstract class AbstractDeviceResource extends ServerResource { (IDeviceService)getContext().getAttributes(). get(IDeviceService.class.getCanonicalName()); - MacAddress macAddress = null; - VlanVid vlan = null; - IPv4Address ipv4Address = null; - DatapathId switchDPID = null; - OFPort switchPort = null; + MacAddress macAddress = MacAddress.NONE; + VlanVid vlan = null; /* must be null for don't care */ + IPv4Address ipv4Address = IPv4Address.NONE; + IPv6Address ipv6Address = IPv6Address.NONE; + DatapathId switchDPID = DatapathId.NONE; + OFPort switchPort = OFPort.ZERO; Form form = getQuery(); String macAddrStr = form.getFirstValue("mac", true); String vlanStr = form.getFirstValue("vlan", true); String ipv4Str = form.getFirstValue("ipv4", true); + String ipv6Str = form.getFirstValue("ipv6", true); String dpid = form.getFirstValue("dpid", true); String port = form.getFirstValue("port", true); @@ -98,6 +103,14 @@ public abstract class AbstractDeviceResource extends ServerResource { return null; } } + if (ipv6Str != null) { + try { + ipv6Address = IPv6Address.of(ipv6Str); + } catch (Exception e) { + setStatus(Status.CLIENT_ERROR_BAD_REQUEST, IPV6_ERROR); + return null; + } + } if (dpid != null) { try { switchDPID = DatapathId.of(dpid); @@ -124,6 +137,7 @@ public abstract class AbstractDeviceResource extends ServerResource { deviceManager.queryDevices(macAddress, vlan, ipv4Address, + ipv6Address, switchDPID, switchPort); @@ -133,6 +147,8 @@ public abstract class AbstractDeviceResource extends ServerResource { form.getFirstValue("vlan__startswith", true); final String ipv4StartsWith = form.getFirstValue("ipv4__startswith", true); + final String ipv6StartsWith = + form.getFirstValue("ipv6__startswith", true); final String dpidStartsWith = form.getFirstValue("dpid__startswith", true); final String portStartsWith = @@ -169,6 +185,19 @@ public abstract class AbstractDeviceResource extends ServerResource { } if (!match) return false; } + if (ipv6StartsWith != null) { + boolean match = false; + for (IPv6Address v : value.getIPv6Addresses()) { + String str; + if (v != null && + (str = v.toString()) != null && + str.startsWith(ipv6StartsWith)) { + match = true; + break; + } + } + if (!match) return false; + } if (dpidStartsWith != null) { boolean match = false; for (SwitchPort v : value.getAttachmentPoints(true)) { diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java index e45e438056ea2b6c55e982fbaff106fb57efa9b8..7dca0ea07de36694298ab99abf8a7bdc28e9d5f2 100644 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java @@ -20,6 +20,7 @@ package net.floodlightcontroller.devicemanager.web; import java.io.IOException; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.VlanVid; import net.floodlightcontroller.devicemanager.SwitchPort; @@ -51,6 +52,11 @@ public class DeviceSerializer extends JsonSerializer<Device> { for (IPv4Address ip : device.getIPv4Addresses()) jGen.writeString(ip.toString()); jGen.writeEndArray(); + + jGen.writeArrayFieldStart("ipv6"); + for (IPv6Address ip : device.getIPv6Addresses()) + jGen.writeString(ip.toString()); + jGen.writeEndArray(); jGen.writeArrayFieldStart("vlan"); for (VlanVid vlan : device.getVlanId()) diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java index d331fe2af4f4b6f1843470fd9b051fbc02465455..7f07b1a595a9bc7bc6098be628133b81b2adb0f8 100644 --- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java +++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java @@ -358,7 +358,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { * since it's a prerequisite for transport ports. */ if (!FLOWMOD_DEFAULT_MATCH_IP_ADDR) { - mb.setExact(MatchField.ETH_TYPE, EthType.IPv4); + mb.setExact(MatchField.ETH_TYPE, EthType.IPv6); } if (ip.getNextHeader().equals(IpProtocol.TCP)) { diff --git a/src/main/java/net/floodlightcontroller/packet/Ethernet.java b/src/main/java/net/floodlightcontroller/packet/Ethernet.java index d9feae28aa1b21cc1ae35ff4585b13e010eadc8e..b3ef406e69298fc785e975cb488fb3833de5d36b 100644 --- a/src/main/java/net/floodlightcontroller/packet/Ethernet.java +++ b/src/main/java/net/floodlightcontroller/packet/Ethernet.java @@ -476,6 +476,17 @@ public class Ethernet extends BasePacket { sb.append("\nnw_proto: "); sb.append(p.getProtocol()); } + else if (pkt instanceof IPv6) { + IPv6 p = (IPv6) pkt; + sb.append("\nnw_src: "); + sb.append(p.getSourceAddress().toString()); + sb.append("\nnw_dst: "); + sb.append(p.getDestinationAddress().toString()); + sb.append("\nnw_tclass: "); + sb.append(p.getTrafficClass()); + sb.append("\nnw_proto: "); + sb.append(p.getNextHeader().toString()); + } else if (pkt instanceof DHCP) { sb.append("\ndhcp packet"); } @@ -488,9 +499,8 @@ public class Ethernet extends BasePacket { else if (pkt instanceof BPDU) { sb.append("\nbpdu packet"); } - else sb.append("\nunknwon packet"); + else sb.append("\nunknown packet"); return sb.toString(); } - -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/packet/IPv6.java b/src/main/java/net/floodlightcontroller/packet/IPv6.java index d8af941018bd2ad2f8ae0b37f02d0cee7522d29c..e15b45e024fd9a4ecdf6aa9f9e1915a457ab8e5a 100644 --- a/src/main/java/net/floodlightcontroller/packet/IPv6.java +++ b/src/main/java/net/floodlightcontroller/packet/IPv6.java @@ -1,255 +1,304 @@ +/** + * Copyright 2015, 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.packet; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import java.util.Set; import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.IpProtocol; /** * @author Jacob Chappell (jacob.chappell@uky.edu) + * @edited Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu */ public class IPv6 extends BasePacket { - public static Map<IpProtocol, Class<? extends IPacket>> nextHeaderClassMap; - - static { - nextHeaderClassMap = new HashMap<IpProtocol, Class<? extends IPacket>>(); - // TODO: Add ICMPv6, IPv6 Options, etc.. - nextHeaderClassMap.put(IpProtocol.TCP, TCP.class); - nextHeaderClassMap.put(IpProtocol.UDP, UDP.class); - } - - public static final int HEADER_LENGTH = 40; - - protected byte version; - protected byte trafficClass; - protected int flowLabel; - protected short payloadLength; - protected IpProtocol nextHeader; - protected byte hopLimit; - protected IPv6Address sourceAddress; - protected IPv6Address destinationAddress; - - public IPv6() { - super(); - this.version = 6; - nextHeader = IpProtocol.NONE; - sourceAddress = IPv6Address.NONE; - destinationAddress = IPv6Address.NONE; - } - - public byte getVersion() { - return version; - } - - public IPv6 setVersion(byte version) { - this.version = version; - return this; - } - - public byte getTrafficClass() { - return trafficClass; - } - - public IPv6 setTrafficClass(byte trafficClass) { - this.trafficClass = trafficClass; - return this; - } - - public int getFlowLabel() { - return flowLabel; - } - - public IPv6 setFlowLabel(int flowLabel) { - this.flowLabel = flowLabel; - return this; - } - - public short getPayloadLength() { - return payloadLength; - } - - public IPv6 setPayloadLength(short payloadLength) { - this.payloadLength = payloadLength; - return this; - } - - public IpProtocol getNextHeader() { - return nextHeader; - } - - public IPv6 setNextHeader(IpProtocol nextHeader) { - this.nextHeader = nextHeader; - return this; - } - - public byte getHopLimit() { - return hopLimit; - } - - public IPv6 setHopLimit(byte hopLimit) { - this.hopLimit = hopLimit; - return this; - } - - public IPv6Address getSourceAddress() { - return sourceAddress; - } - - public IPv6 setSourceAddress(IPv6Address sourceAddress) { - this.sourceAddress = sourceAddress; - return this; - } - - public IPv6Address getDestinationAddress() { - return destinationAddress; - } - - public IPv6 setDestinationAddress(IPv6Address destinationAddress) { - this.destinationAddress = destinationAddress; - return this; - } - - @Override - public byte[] serialize() { - // Get the raw bytes of the payload we encapsulate. - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - // Update our internal payload length. - this.payloadLength = (short) ((payloadData != null) ? payloadData.length : 0); - // Create a byte buffer to hold the IPv6 packet structure. - byte[] data = new byte[HEADER_LENGTH + this.payloadLength]; - ByteBuffer bb = ByteBuffer.wrap(data); - // Add header fields to the byte buffer in the correct order. - // Fear not the bit magic that must occur. - bb.put((byte) (((this.version & 0xF) << 4) | - ((this.trafficClass & 0xF0) >>> 4))); - bb.put((byte) (((this.trafficClass & 0xF) << 4) | - ((this.flowLabel & 0xF0000) >>> 16))); - bb.putShort((short) (this.flowLabel & 0xFFFF)); - bb.putShort(this.payloadLength); - bb.put((byte) this.nextHeader.getIpProtocolNumber()); - bb.put(this.hopLimit); - bb.put(this.sourceAddress.getBytes()); - bb.put(this.destinationAddress.getBytes()); - // Add the payload to the byte buffer, if necessary. - if (payloadData != null) - bb.put(payloadData); - // We're done! Return the data. - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) - throws PacketParsingException { - // Wrap the data in a byte buffer for easier retrieval. - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - // Retrieve values from IPv6 header. - byte firstByte = bb.get(); - byte secondByte = bb.get(); - this.version = (byte) ((firstByte & 0xF0) >>> 4); - if (this.version != 6) { - throw new PacketParsingException( - "Invalid version for IPv6 packet: " + - this.version); - } - this.trafficClass = (byte) (((firstByte & 0xF) << 4) | - ((secondByte & 0xF0) >>> 4)); - this.flowLabel = ((secondByte & 0xF) << 16) | - (bb.getShort() & 0xFFFF); - this.payloadLength = bb.getShort(); - this.nextHeader = IpProtocol.of(bb.get()); // TODO: U8.f()? - this.hopLimit = bb.get(); - byte[] sourceAddress = new byte[16]; - bb.get(sourceAddress, 0, 16); - byte[] destinationAddress = new byte[16]; - bb.get(destinationAddress, 0, 16); - this.sourceAddress = IPv6Address.of(sourceAddress); - this.destinationAddress = IPv6Address.of(destinationAddress); - // Retrieve the payload, if possible. - IPacket payload; - if (IPv6.nextHeaderClassMap.containsKey(this.nextHeader)) { - Class<? extends IPacket> clazz = IPv6.nextHeaderClassMap.get(this.nextHeader); - try { - payload = clazz.newInstance(); - } catch (Exception e) { - throw new RuntimeException("Error parsing payload for IPv6 packet", e); - } - } else { - payload = new Data(); - } - // Deserialize as much of the payload as we can (hopefully all of it). - this.payload = payload.deserialize(data, bb.position(), - Math.min(this.payloadLength, bb.limit() - bb.position())); - this.payload.setParent(this); - // We're done! - return this; - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime - * result - + ((destinationAddress == null) ? 0 : destinationAddress - .hashCode()); - result = prime * result + flowLabel; - result = prime * result + hopLimit; - result = prime * result - + ((nextHeader == null) ? 0 : nextHeader.hashCode()); - result = prime * result + payloadLength; - result = prime * result - + ((sourceAddress == null) ? 0 : sourceAddress.hashCode()); - result = prime * result + trafficClass; - result = prime * result + version; - return result; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (!(obj instanceof IPv6)) - return false; - IPv6 other = (IPv6) obj; - if (destinationAddress == null) { - if (other.destinationAddress != null) - return false; - } else if (!destinationAddress.equals(other.destinationAddress)) - return false; - if (flowLabel != other.flowLabel) - return false; - if (hopLimit != other.hopLimit) - return false; - if (nextHeader == null) { - if (other.nextHeader != null) - return false; - } else if (!nextHeader.equals(other.nextHeader)) - return false; - if (payloadLength != other.payloadLength) - return false; - if (sourceAddress == null) { - if (other.sourceAddress != null) - return false; - } else if (!sourceAddress.equals(other.sourceAddress)) - return false; - if (trafficClass != other.trafficClass) - return false; - if (version != other.version) - return false; - return true; - } + public static Map<IpProtocol, Class<? extends IPacket>> nextHeaderClassMap; + + static { + nextHeaderClassMap = new HashMap<IpProtocol, Class<? extends IPacket>>(); + // TODO: Add ICMPv6, IPv6 Options, etc.. + nextHeaderClassMap.put(IpProtocol.TCP, TCP.class); + nextHeaderClassMap.put(IpProtocol.UDP, UDP.class); + } + + public static final int HEADER_LENGTH = 40; + + protected byte version; + protected byte trafficClass; + protected int flowLabel; + protected short payloadLength; + protected IpProtocol nextHeader; + protected byte hopLimit; + protected IPv6Address sourceAddress; + protected IPv6Address destinationAddress; + + public IPv6() { + super(); + this.version = 6; + nextHeader = IpProtocol.NONE; + sourceAddress = IPv6Address.NONE; + destinationAddress = IPv6Address.NONE; + } + + public byte getVersion() { + return version; + } + + public IPv6 setVersion(byte version) { + this.version = version; + return this; + } + + public byte getTrafficClass() { + return trafficClass; + } + + public IPv6 setTrafficClass(byte trafficClass) { + this.trafficClass = trafficClass; + return this; + } + + public int getFlowLabel() { + return flowLabel; + } + + public IPv6 setFlowLabel(int flowLabel) { + this.flowLabel = flowLabel; + return this; + } + + public short getPayloadLength() { + return payloadLength; + } + + public IPv6 setPayloadLength(short payloadLength) { + this.payloadLength = payloadLength; + return this; + } + + public IpProtocol getNextHeader() { + return nextHeader; + } + + public IPv6 setNextHeader(IpProtocol nextHeader) { + this.nextHeader = nextHeader; + return this; + } + + public byte getHopLimit() { + return hopLimit; + } + + public IPv6 setHopLimit(byte hopLimit) { + this.hopLimit = hopLimit; + return this; + } + + public IPv6Address getSourceAddress() { + return sourceAddress; + } + + public IPv6 setSourceAddress(IPv6Address sourceAddress) { + this.sourceAddress = sourceAddress; + return this; + } + + public IPv6Address getDestinationAddress() { + return destinationAddress; + } + + public IPv6 setDestinationAddress(IPv6Address destinationAddress) { + this.destinationAddress = destinationAddress; + return this; + } + + @Override + public byte[] serialize() { + // Get the raw bytes of the payload we encapsulate. + byte[] payloadData = null; + if (this.payload != null) { + this.payload.setParent(this); + payloadData = this.payload.serialize(); + /* + * If we forgot to include the IpProtocol before serializing, + * try to ascertain what it is from the payload. If it's not + * a payload type we know about, we'll throw an exception. + */ + if ((this.nextHeader == null || this.nextHeader.equals(IpProtocol.NONE))) { + if (IPv6.nextHeaderClassMap.containsValue(this.payload.getClass())) { + Set<Map.Entry<IpProtocol, Class<? extends IPacket>>> entries = IPv6.nextHeaderClassMap.entrySet(); + for (Map.Entry<IpProtocol, Class<? extends IPacket>> m : entries) { + if (m.getValue().equals(this.payload.getClass())) { + this.setNextHeader(m.getKey()); + log.warn("Setting previously unset IPv6 'next header' to {} as detected by payload {}", m.getKey(), this.getPayload().getClass().toString()); + break; + } + } + } else if (this.payload instanceof Data) { + /* we're good -- there shouldn't be an IpProtocol set it it's just data */ + } else { + throw new IllegalArgumentException("IpProtocol is unset in IPv6 packet " + this.toString() + ". Unable to determine payload type to set for payload " + this.getPayload().getClass().toString()); + } + } + } + // Update our internal payload length. + this.payloadLength = (short) ((payloadData != null) ? payloadData.length : 0); + // Create a byte buffer to hold the IPv6 packet structure. + byte[] data = new byte[HEADER_LENGTH + this.payloadLength]; + ByteBuffer bb = ByteBuffer.wrap(data); + // Add header fields to the byte buffer in the correct order. + // Fear not the bit magic that must occur. + bb.put((byte) (((this.version & 0xF) << 4) | + ((this.trafficClass & 0xF0) >>> 4))); + bb.put((byte) (((this.trafficClass & 0xF) << 4) | + ((this.flowLabel & 0xF0000) >>> 16))); + bb.putShort((short) (this.flowLabel & 0xFFFF)); + bb.putShort(this.payloadLength); + bb.put((byte) this.nextHeader.getIpProtocolNumber()); + bb.put(this.hopLimit); + bb.put(this.sourceAddress.getBytes()); + bb.put(this.destinationAddress.getBytes()); + // Add the payload to the byte buffer, if necessary. + if (payloadData != null) + bb.put(payloadData); + // We're done! Return the data. + return data; + } + + @Override + public String toString() { + return "IPv6 [version=" + version + ", trafficClass=" + trafficClass + + ", flowLabel=" + flowLabel + ", payloadLength=" + + payloadLength + ", nextHeader=" + nextHeader + ", hopLimit=" + + hopLimit + ", sourceAddress=" + sourceAddress + + ", destinationAddress=" + destinationAddress + ", parent=" + + parent + ", payload=" + payload + "]"; + } + + @Override + public IPacket deserialize(byte[] data, int offset, int length) + throws PacketParsingException { + // Wrap the data in a byte buffer for easier retrieval. + ByteBuffer bb = ByteBuffer.wrap(data, offset, length); + // Retrieve values from IPv6 header. + byte firstByte = bb.get(); + byte secondByte = bb.get(); + this.version = (byte) ((firstByte & 0xF0) >>> 4); + if (this.version != 6) { + throw new PacketParsingException( + "Invalid version for IPv6 packet: " + + this.version); + } + this.trafficClass = (byte) (((firstByte & 0xF) << 4) | + ((secondByte & 0xF0) >>> 4)); + this.flowLabel = ((secondByte & 0xF) << 16) | + (bb.getShort() & 0xFFFF); + this.payloadLength = bb.getShort(); + this.nextHeader = IpProtocol.of(bb.get()); + this.hopLimit = bb.get(); + byte[] sourceAddress = new byte[16]; + bb.get(sourceAddress, 0, 16); + byte[] destinationAddress = new byte[16]; + bb.get(destinationAddress, 0, 16); + this.sourceAddress = IPv6Address.of(sourceAddress); + this.destinationAddress = IPv6Address.of(destinationAddress); + // Retrieve the payload, if possible. + IPacket payload; + if (IPv6.nextHeaderClassMap.containsKey(this.nextHeader)) { + Class<? extends IPacket> clazz = IPv6.nextHeaderClassMap.get(this.nextHeader); + try { + payload = clazz.newInstance(); + } catch (Exception e) { + throw new RuntimeException("Error parsing payload for IPv6 packet", e); + } + } else { + payload = new Data(); + } + // Deserialize as much of the payload as we can (hopefully all of it). + this.payload = payload.deserialize(data, bb.position(), + Math.min(this.payloadLength, bb.limit() - bb.position())); + this.payload.setParent(this); + // We're done! + return this; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime + * result + + ((destinationAddress == null) ? 0 : destinationAddress + .hashCode()); + result = prime * result + flowLabel; + result = prime * result + hopLimit; + result = prime * result + + ((nextHeader == null) ? 0 : nextHeader.hashCode()); + result = prime * result + payloadLength; + result = prime * result + + ((sourceAddress == null) ? 0 : sourceAddress.hashCode()); + result = prime * result + trafficClass; + result = prime * result + version; + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (!(obj instanceof IPv6)) + return false; + IPv6 other = (IPv6) obj; + if (destinationAddress == null) { + if (other.destinationAddress != null) + return false; + } else if (!destinationAddress.equals(other.destinationAddress)) + return false; + if (flowLabel != other.flowLabel) + return false; + if (hopLimit != other.hopLimit) + return false; + if (nextHeader == null) { + if (other.nextHeader != null) + return false; + } else if (!nextHeader.equals(other.nextHeader)) + return false; + if (payloadLength != other.payloadLength) + return false; + if (sourceAddress == null) { + if (other.sourceAddress != null) + return false; + } else if (!sourceAddress.equals(other.sourceAddress)) + return false; + if (trafficClass != other.trafficClass) + return false; + if (version != other.version) + return false; + return true; + } } diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java index cf2183a2e8d1f016a68496a4e9cffc38e5dec064..7568dad7d11139915ac8b480eca1cb837d677005 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java @@ -91,7 +91,7 @@ public class TopologyInstance { @Override public Route load(RouteId rid) { - return ti.buildroute(rid); + return ti.buildroute(rid); } } @@ -638,7 +638,7 @@ public class TopologyInstance { if (log.isTraceEnabled()) { log.trace("buildroute: {}", result); } - return result; + return result; } protected int getCost(DatapathId srcId, DatapathId dstId) { diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java index f5ea145c4af628df9331907d7ca7ca5942969f34..cab875e333bdc047514e2ed8568fb182f1aec605 100644 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java +++ b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java @@ -520,6 +520,12 @@ implements IFloodlightModule, IVirtualNetworkService, IOFMessageListener { // add or remove entry as gateway deviceAdded(device); } + + @Override + public void deviceIPV6AddrChanged(IDevice device) { + //TODO + log.debug("IPv6 address change not handled in VirtualNetworkFilter. Device: {}", device.toString()); + } @Override public void deviceMoved(IDevice device) { diff --git a/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java b/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java index 230f1e93436e498cfafd4789eb0811c80fce1abc..f9c4d0487f11a7eca2dfeeca41f005757c15b7b4 100644 --- a/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java +++ b/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java @@ -51,8 +51,6 @@ import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClassifierService; import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; import net.floodlightcontroller.devicemanager.test.MockDeviceManager; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; @@ -69,7 +67,11 @@ import org.junit.Test; import org.projectfloodlight.openflow.protocol.OFFactories; import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.types.DatapathId; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; +import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.VlanVid; public class ACLTest extends FloodlightTestCase { @@ -177,14 +179,12 @@ public class ACLTest extends FloodlightTestCase { Map<String, Object> row; // a new AP[dpid:00:00:00:00:00:00:00:01 port:1 ip:10.0.0.1] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:01")), - null, IPv4.toIPv4Address("10.0.0.1"), 1L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:01"), + VlanVid.ZERO, IPv4Address.of("10.0.0.1"), IPv6Address.NONE, DatapathId.of(1), OFPort.of(1)); // a new AP[dpid:00:00:00:00:00:00:00:02 port:1 ip:10.0.0.3] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:03")), - null, IPv4.toIPv4Address("10.0.0.3"), 2L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:03"), + VlanVid.ZERO, IPv4Address.of("10.0.0.3"), IPv6Address.NONE, DatapathId.of(2), OFPort.of(1)); // rule1 indicates host(10.0.0.0/28) can not access TCP port 80 in host(10.0.0.254/32) rule1 = new ACLRule(); @@ -344,9 +344,8 @@ public class ACLTest extends FloodlightTestCase { assertEquals(acl.getRules().size(), 1); // a new AP[dpid:00:00:00:00:00:00:00:01 port:1 ip:10.0.0.1] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:01")), - null, IPv4.toIPv4Address("10.0.0.1"), 1L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:01"), + VlanVid.ZERO, IPv4Address.of("10.0.0.1"), IPv6Address.NONE, DatapathId.of(1), OFPort.of(1)); resultSet = storageService.getRow( StaticFlowEntryPusher.TABLE_NAME, "ACLRule_1_00:00:00:00:00:00:00:01"); @@ -364,9 +363,8 @@ public class ACLTest extends FloodlightTestCase { } // a new AP[dpid:00:00:00:00:00:00:00:01 port:2 ip:10.0.0.2] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:02")), - null, IPv4.toIPv4Address("10.0.0.2"), 1L, 2); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:02"), + VlanVid.ZERO, IPv4Address.of("10.0.0.2"), IPv6Address.NONE, DatapathId.of(1), OFPort.of(2)); resultSet = storageService.getRow( StaticFlowEntryPusher.TABLE_NAME, "ACLRule_1_00:00:00:00:00:00:00:01"); @@ -392,9 +390,8 @@ public class ACLTest extends FloodlightTestCase { assertEquals(acl.getRules().size(), 2); // a new AP[dpid:00:00:00:00:00:00:00:02 port:1 ip:10.0.0.3] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:03")), - null, IPv4.toIPv4Address("10.0.0.3"), 2L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:03"), + VlanVid.ZERO, IPv4Address.of("10.0.0.3"), IPv6Address.NONE, DatapathId.of(2), OFPort.of(1)); resultSet = storageService.getRow( StaticFlowEntryPusher.TABLE_NAME, "ACLRule_2_00:00:00:00:00:00:00:02"); @@ -428,9 +425,8 @@ public class ACLTest extends FloodlightTestCase { Map<String, Object> row; // a new AP[dpid:00:00:00:00:00:00:00:01 port:1] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:01")), - null, null, 1L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:01"), + VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(1), OFPort.of(1)); // rule1 indicates host(10.0.0.0/28) can not access TCP port 80 in host(10.0.0.254/32) rule1 = new ACLRule(); @@ -455,9 +451,8 @@ public class ACLTest extends FloodlightTestCase { assertEquals(it.hasNext(), false); // a new AP[dpid:00:00:00:00:00:00:00:01 port:1 ip:10.0.0.1] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:01")), - null, IPv4.toIPv4Address("10.0.0.1"), 1L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:01"), + VlanVid.ZERO, IPv4Address.of("10.0.0.1"), IPv6Address.NONE, DatapathId.of(1), OFPort.of(1)); resultSet = storageService.getRow( StaticFlowEntryPusher.TABLE_NAME, "ACLRule_1_00:00:00:00:00:00:00:01"); @@ -491,14 +486,12 @@ public class ACLTest extends FloodlightTestCase { Map<String, Object> row; // a new AP[dpid:00:00:00:00:00:00:00:01 port:1 ip:10.0.0.1] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:01")), - null, IPv4.toIPv4Address("10.0.0.1"), 1L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:01"), + VlanVid.ZERO, IPv4Address.of("10.0.0.1"), IPv6Address.NONE, DatapathId.of(1), OFPort.of(1)); // a new AP[dpid:00:00:00:00:00:00:00:02 port:1 ip:10.0.0.3] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:03")), - null, IPv4.toIPv4Address("10.0.0.3"), 2L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:03"), + VlanVid.ZERO, IPv4Address.of("10.0.0.3"), IPv6Address.NONE, DatapathId.of(2), OFPort.of(1)); // rule1 indicates host(10.0.0.0/28) can not access TCP port 80 in host(10.0.0.254/32) rule1 = new ACLRule(); @@ -579,14 +572,12 @@ public class ACLTest extends FloodlightTestCase { Map<String, Object> row; // a new AP[dpid:00:00:00:00:00:00:00:01 port:1 ip:10.0.0.1] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:01")), - null, IPv4.toIPv4Address("10.0.0.1"), 1L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:01"), + VlanVid.ZERO, IPv4Address.of("10.0.0.1"), IPv6Address.NONE, DatapathId.of(1), OFPort.of(1)); // a new AP[dpid:00:00:00:00:00:00:00:02 port:1 ip:10.0.0.3] appears - deviceManager.learnEntity( - Ethernet.toLong(Ethernet.toMACAddress("00:00:00:00:00:03")), - null, IPv4.toIPv4Address("10.0.0.3"), 2L, 1); + deviceManager.learnEntity(MacAddress.of("00:00:00:00:00:03"), + VlanVid.ZERO, IPv4Address.of("10.0.0.3"), IPv6Address.NONE, DatapathId.of(2), OFPort.of(1)); // rule1 indicates host(10.0.0.0/28) can not access TCP port 80 in host(10.0.0.254/32) rule1 = new ACLRule(); diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java index 116e8bb179633d8afdc9a42be590d317ac58a887..0bb86f00d0031948b33f5ef21382f50d09694aa3 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java @@ -79,6 +79,7 @@ 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; @@ -99,6 +100,7 @@ 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; @@ -118,8 +120,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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; @@ -286,6 +292,38 @@ public class DeviceManagerImplTest extends FloodlightTestCase { .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) @@ -301,6 +339,20 @@ public class DeviceManagerImplTest extends FloodlightTestCase { .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(); } /** @@ -322,9 +374,9 @@ public class DeviceManagerImplTest extends FloodlightTestCase { public void testLastSeen() throws Exception { Calendar c = Calendar.getInstance(); Date d1 = c.getTime(); - Entity entity1 = new Entity(MacAddress.of(1L), null, null, null, null, d1); + 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), null, IPv4Address.of(1), null, null, c.getTime()); + 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()); @@ -377,13 +429,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; - Entity entity1 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(10L), OFPort.of(1), new Date()); - Entity entity3 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(10L), OFPort.of(1), new Date()); - Entity entity4 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity5 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.of(1), DatapathId.of(5L), OFPort.of(2), new Date()); - Entity entity6 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.of(1), DatapathId.of(50L), OFPort.of(3), new Date()); - Entity entity7 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(4), IPv4Address.of(2), DatapathId.of(50L), OFPort.of(3), new Date()); + 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); @@ -393,7 +445,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertSame(d1, deviceManager.findDeviceByEntity(entity1)); assertEquals(DefaultEntityClassifier.entityClass , d1.getEntityClass()); - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(-1) }, d1.getVlanId()); + assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d1.getVlanId()); assertArrayEquals(new IPv4Address[] { }, d1.getIPv4Addresses()); assertEquals(1, deviceManager.getAllDevices().size()); @@ -408,8 +460,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertNotSame(d1, d2); assertNotSame(d1.getDeviceKey(), d2.getDeviceKey()); assertEquals(MockEntityClassifier.testEC, d2.getEntityClass()); - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(-1) }, d2.getVlanId()); - assertArrayEquals(new Integer[] { }, d2.getIPv4Addresses()); + assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d2.getVlanId()); + assertArrayEquals(new IPv4Address[] { }, d2.getIPv4Addresses()); assertEquals(2, deviceManager.getAllDevices().size()); verify(mockListener); @@ -428,7 +480,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { d3.getAttachmentPoints()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) }, d3.getAttachmentPoints(true)); - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(-1) }, + assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d3.getVlanId()); assertEquals(2, deviceManager.getAllDevices().size()); @@ -446,7 +498,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { d4.getIPv4Addresses()); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, d4.getAttachmentPoints()); - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(-1) }, + assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d4.getVlanId()); assertEquals(2, deviceManager.getAllDevices().size()); @@ -504,15 +556,184 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.entityClassifier = new MockEntityClassifierMac(); deviceManager.startUp(null); - Entity entityNoClass = new Entity(MacAddress.of(5L), VlanVid.ofVlan(1), IPv4Address.of(5), DatapathId.of(-1L), OFPort.of(1), new Date()); + 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.getL2DomainId(DatapathId.of(anyLong()))). + andReturn(DatapathId.of(1L)).anyTimes(); + expect(mockTopology.isBroadcastDomainPort(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), null, null, null, null, null); + 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); @@ -528,7 +749,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { }; for (Long mac: macs) { - e = new Entity(MacAddress.of(mac), null, null, null, null, null); + 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); @@ -600,14 +821,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); - Entity entity0 = new Entity(MacAddress.of(1L), null, null, null, null, c.getTime()); + 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), null, null, DatapathId.of(5L), 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()); c.add(Calendar.SECOND, 1); - Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(10L), 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()); c.add(Calendar.SECOND, 1); - Entity entity4 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(50L), OFPort.of(1), c.getTime()); + 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; @@ -664,106 +885,6 @@ public class DeviceManagerImplTest extends FloodlightTestCase { verify(mockListener); } - /** - * In this test, a device is moved from attachment point (1,1) to (5,1) - * and then moved back to (1,1) within 30 seconds. Both the moves should - * generate device moved notification. - * @throws Exception - */ - @Test - public void testAttachmentPointMovingBack() 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.getL2DomainId(DatapathId.of(1L))). - andReturn(DatapathId.of(1L)).anyTimes(); - expect(mockTopology.getL2DomainId(DatapathId.of(5L))). - andReturn(DatapathId.of(1L)).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))). - andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()), - DatapathId.of(anyLong()), OFPort.of(anyShort()))) - .andReturn(false).anyTimes(); - - expect(mockTopology.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(); - - 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), null, null, DatapathId.of(1L), OFPort.of(1), c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(1), c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(1), c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity4 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(1), c.getTime()); - - IDevice d; - SwitchPort[] aps; - - mockListener.deviceAdded(isA(IDevice.class)); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)) }, aps); - 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); - verify(mockListener); - - reset(mockListener); - mockListener.deviceMoved((isA(IDevice.class))); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity3); - assertEquals(1, deviceManager.getAllDevices().size()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), - new SwitchPort(DatapathId.of(5L), OFPort.of(1), ErrorStatus.DUPLICATE_DEVICE)}, - d.getAttachmentPoints(true)); - verify(mockListener); - - // Generate a packet-in again from 5,1 and ensure that it doesn't - // create a device moved event. - reset(mockListener); - replay(mockListener); - d = deviceManager.learnDeviceByEntity(entity4); - assertEquals(1, deviceManager.getAllDevices().size()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), - new SwitchPort(DatapathId.of(5L), OFPort.of(1), ErrorStatus.DUPLICATE_DEVICE)}, - d.getAttachmentPoints(true)); - verify(mockListener); - } - private void verifyEntityArray(Entity[] expected, Device d) { Arrays.sort(expected); assertArrayEquals(expected, d.entities); @@ -818,13 +939,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); + 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), null, IPv4Address.of(2), DatapathId.of(2L), OFPort.of(1), c.getTime()); + 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), null, IPv4Address.of(3), DatapathId.of(3L), OFPort.of(1), c.getTime()); + 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), null, IPv4Address.of(4), DatapathId.of(4L), OFPort.of(1), c.getTime()); + 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; @@ -910,7 +1031,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { reset(mockListener); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getL2DomainId(DatapathId.of(1L))). + expect(mockTopology.getL2DomainId(DatapathId.of(1L))). /* two different OpenFlow islands, 1 and 10 */ andReturn(DatapathId.of(1L)).anyTimes(); expect(mockTopology.getL2DomainId(DatapathId.of(5L))). andReturn(DatapathId.of(1L)).anyTimes(); @@ -941,42 +1062,41 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.addSuppressAPs(DatapathId.of(10L), OFPort.of(1)); Calendar c = Calendar.getInstance(); - Entity entity0 = new Entity(MacAddress.of(1L), null, null, null, null, c.getTime()); - // No attachment point should be learnt on 1L, 1 - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); + /* 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), null, IPv4Address.of(1), DatapathId.of(5L), OFPort.of(1), c.getTime()); + 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); - Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(10L), OFPort.of(1), c.getTime()); + /* 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), null, null, DatapathId.of(50L), OFPort.of(1), c.getTime()); + 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); - // TODO: we currently do learn entities on suppressed APs - // // cannot learn device on suppressed AP - // d = deviceManager.learnDeviceByEntity(entity1); - // assertNull(d); - + /* 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); + 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))); - //mockListener.deviceIPV4AddrChanged((isA(IDevice.class))); replay(mockListener); d = deviceManager.learnDeviceByEntity(entity2); assertEquals(1, deviceManager.getAllDevices().size()); @@ -990,7 +1110,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { reset(mockListener); replay(mockListener); - d = deviceManager.learnDeviceByEntity(entity3); + d = deviceManager.learnDeviceByEntity(entity3); assertEquals(1, deviceManager.getAllDevices().size()); aps = d.getAttachmentPoints(); assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(5L), OFPort.of(1)) }, aps); @@ -1039,13 +1159,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); + 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), null, null, DatapathId.of(1L), OFPort.of(2), c.getTime()); + 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), null, null, DatapathId.of(1L), OFPort.of(2), c.getTime()); + 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; @@ -1105,13 +1225,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); + 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), null, null, DatapathId.of(1L), OFPort.LOCAL, c.getTime()); + 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), null, null, DatapathId.of(1L), OFPort.of(2), c.getTime()); + 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; @@ -1178,23 +1298,25 @@ public class DeviceManagerImplTest extends FloodlightTestCase { * Vlan and ip are optional all other fields must be specified. * @return */ - private static void verifyDevice(IDevice d, long mac, Short vlan, Integer ip, - long swId, int port) { + private static void verifyDevice(IDevice d, MacAddress mac, VlanVid vlan, IPv4Address ipv4, + IPv6Address ipv6, DatapathId swId, OFPort port) { assertNotNull(d); - assertEquals(MacAddress.of(mac), d.getMACAddress()); - if (vlan == null) - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(-1) }, d.getVlanId()); - else - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(vlan) }, d.getVlanId()); - - if (ip == null) - assertArrayEquals(new IPv4Address[] { IPv4Address.of(0) }, d.getIPv4Addresses()); - else - assertArrayEquals(new IPv4Address[] { IPv4Address.of(ip) }, d.getIPv4Addresses()); - - SwitchPort expectedAp = new SwitchPort(DatapathId.of(swId), OFPort.of(port)); - assertArrayEquals(new SwitchPort[] { expectedAp }, - d.getAttachmentPoints()); + 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()); + } } @@ -1203,7 +1325,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { MacAddress deviceMac = ((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress(); OFPacketIn packetIn = testARPReplyPacketIn_1; - Integer ipaddr = IPv4.toIPv4Address("192.168.1.1"); + IPv4Address ipaddr = IPv4Address.of("192.168.1.1"); // Mock up our expected behavior ITopologyService mockTopology = createMock(ITopologyService.class); @@ -1218,9 +1340,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Verify the device Device rdevice = (Device) deviceManager.findDevice(deviceMac, - VlanVid.ofVlan(5), null, null, null); - verifyDevice(rdevice, deviceMac.getLong(), - (short) 5, ipaddr, 1L, 1); + 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); @@ -1230,8 +1351,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Device result = null; Iterator<? extends IDevice> dstiter = - deviceManager.queryDevices(null, null, IPv4Address.of(ipaddr), - null, null); + deviceManager.queryDevices(MacAddress.NONE, null /* any VLAN here */, ipaddr, + IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); if (dstiter.hasNext()) { result = (Device)dstiter.next(); } @@ -1257,9 +1378,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Verify the device rdevice = (Device) deviceManager.findDevice(deviceMac, - VlanVid.ofVlan(5), null, null, null); - verifyDevice(rdevice, deviceMac.getLong(), - (short)5, ipaddr, 5L, 2); + 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)); cntxSrcDev = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); assertEquals(rdevice, cntxSrcDev); @@ -1285,13 +1405,115 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(Command.CONTINUE, cmd); IDevice srcDev = - deviceManager.findDevice(srcMac, VlanVid.ofVlan(5), null, null, null); - verifyDevice(srcDev, srcMac.getLong(), (short)5, null, - 1L, testUDPPacketIn.getMatch().get(MatchField.IN_PORT).getShortPortNumber()); + 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), null, null, null); - verifyDevice(dstDev, dstMac.getLong(), (short)5, ipaddr, 5L, 2); + 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 + 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)); + 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); @@ -1319,7 +1541,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { MacAddress sourceMac = ((Ethernet)this.testARPReplyPacket_2) .getSourceMACAddress(); - Integer ipaddr = IPv4.toIPv4Address("192.168.1.1"); + IPv4Address ipaddr = IPv4Address.of("192.168.1.1"); OFPacketIn packetIn = testARPReplyPacketIn_2; // Mock up our expected behavior @@ -1334,14 +1556,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase { verify(mockTopology); assertEquals(Command.CONTINUE, cmd); // Verify the device for the sender HW address - Device senderDev = (Device) - deviceManager.findDevice(senderMac, VlanVid.ofVlan(5), null, null, null); - verifyDevice(senderDev, senderMac.getLong(), (short)5, ipaddr, 1L, 1); + 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)); - Device result = null; + IDevice result = null; Iterator<? extends IDevice> dstiter = - deviceManager.queryDevices(null, null, IPv4Address.of(ipaddr), - null, null); + deviceManager.queryDevices(MacAddress.NONE, null /* any VLAN here */, ipaddr, + IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); if (dstiter.hasNext()) { result = (Device)dstiter.next(); } @@ -1351,10 +1573,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Verify the device for the source MAC - Device srcDev = (Device) - deviceManager.findDevice(sourceMac, VlanVid.ofVlan(5), null, null, null); + 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.getLong(), (short)5, null, 1L, 1); + 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 @@ -1416,8 +1638,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(Command.CONTINUE, cmd); cntxSrcDev = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); - verifyDevice(cntxSrcDev, 1L, (short)5, null, - 1L, testUDPPacketIn.getMatch().get(MatchField.IN_PORT).getShortPortNumber()); + 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); @@ -1443,8 +1664,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(Command.CONTINUE, cmd); IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); - verifyDevice(cntxSrcDev, srcMac.getLong(), (short)5, null, - 1L, testUDPPacketIn.getMatch().get(MatchField.IN_PORT).getShortPortNumber()); + 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); @@ -1460,9 +1680,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { IDeviceService.CONTEXT_SRC_DEVICE); // yes: we check that cntxSrcDev matched dstMAC because we are // just adding the dest device - int ip = IPv4Address.of("192.168.1.1").getInt(); - verifyDevice(cntxSrcDev, dstMac.getLong(), (short)5, ip, - 1L, testARPReplyPacketIn_1.getMatch().get(MatchField.IN_PORT).getShortPortNumber()); + 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; @@ -1513,7 +1732,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.of(1))).andReturn(false).anyTimes(); expect(mockTopology.isBroadcastDomainPort(DatapathId.of(5L), OFPort.of(1))).andReturn(false).anyTimes(); - expect(mockTopology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(mockTopology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); /* different islands */ expect(mockTopology.getL2DomainId(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(); @@ -1526,23 +1745,23 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(2), DatapathId.of(1L), OFPort.of(1), c.getTime()); - c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); - Entity entity2 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(5L), OFPort.of(1), c.getTime()); + 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); + 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(), - null, null, IPv4Address.of(1), null, null); + 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(), - null, null, IPv4Address.of(2), null, null); + MacAddress.NONE, VlanVid.ZERO /* untagged here */, IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); assertTrue(diter.hasNext()); assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); @@ -1550,7 +1769,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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); @@ -1563,14 +1782,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase { new SwitchPort(DatapathId.of(5L), OFPort.of(1)) }, d.getAttachmentPoints()); diter = deviceManager.queryClassDevices(d.getEntityClass(), - null, null, IPv4Address.of(2), null, null); + 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(), - null, null, IPv4Address.of(1), null, null); + MacAddress.NONE, VlanVid.ZERO /* untagged here */, IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); assertFalse(diter.hasNext()); - d = deviceManager.findDevice(MacAddress.of(1L), null, null, null, null); + 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. @@ -1592,8 +1811,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Calendar c = Calendar.getInstance(); c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); - Entity entity1 = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); - Entity entity2 = new Entity(MacAddress.of(1L), null, IPv4Address.of(2), DatapathId.of(5L), OFPort.of(1), c.getTime()); + 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; @@ -1631,10 +1850,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertNull(r); Iterator<? extends IDevice> diter = deviceManager.queryClassDevices(d.getEntityClass(), - null, null, IPv4Address.of(1), null, null); + MacAddress.NONE, VlanVid.ZERO, IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); assertFalse(diter.hasNext()); - r = deviceManager.findDevice(MacAddress.of(1L), null, null, null, null); + r = deviceManager.findDevice(MacAddress.of(1L), VlanVid.ZERO, IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); assertNull(r); verify(mockListener); @@ -1680,13 +1899,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Entity newEntity = new Entity (e.macAddress, e.vlan, e.ipv4Address, + e.ipv6Address, e.switchDPID, e.switchPort, e.lastSeenTimestamp); - if (e.vlan == null) + if (newEntity.vlan.equals(VlanVid.ZERO)) { newEntity.vlan = VlanVid.ofVlan(1); - else - newEntity.vlan = VlanVid.ofVlan(((e.vlan.getVlan() + 1 % 4095)+1)); + } else { + newEntity.vlan = VlanVid.ofVlan((e.vlan.getVlan() + 1 % 4095) + 1); + } newDevice = new Device(newDevice, newEntity, -1); } assertEquals(false, newDevice.equals(d)); @@ -1772,19 +1993,18 @@ public class DeviceManagerImplTest extends FloodlightTestCase { replay(mockTopology); deviceManager.topology = mockTopology; - Entity entity1 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(1), c.getTime()); - Entity entity1a = new Entity(MacAddress.of(1L), null, IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), c.getTime()); - Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(1), c.getTime()); - Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(10L), OFPort.of(1), c.getTime()); - entity1.setLastSeenTimestamp(c.getTime()); + /* 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()); + entity1a.setLastSeenTimestamp(c.getTime()); /* halfway timed out for entity1 */ c.add(Calendar.MILLISECOND, 1); - entity2.setLastSeenTimestamp(c.getTime()); + entity2.setLastSeenTimestamp(c.getTime()); /* small increment; still below entity1 timeout */ c.add(Calendar.MILLISECOND, 1); - entity3.setLastSeenTimestamp(c.getTime()); - - + entity3.setLastSeenTimestamp(c.getTime()); /* small increment; still below entity1 timeout */ IDevice d; d = deviceManager.learnDeviceByEntity(entity1); @@ -1800,21 +2020,21 @@ public class DeviceManagerImplTest extends FloodlightTestCase { d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4); - entity1.setLastSeenTimestamp(c.getTime()); - d = deviceManager.learnDeviceByEntity(entity1); + 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(1L), OFPort.of(1)) }, + assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(10L), OFPort.of(1)) }, d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), + 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(10L), OFPort.of(1), + 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()); + 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()); @@ -1864,10 +2084,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase { replay(mockTopology); deviceManager.topology = mockTopology; - Entity entity1 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(1), c.getTime()); - Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(1L), OFPort.of(2), c.getTime()); - Entity entity3 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(1), c.getTime()); - Entity entity4 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(5L), OFPort.of(2), c.getTime()); + 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); @@ -1895,12 +2115,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase { d = deviceManager.learnDeviceByEntity(entity1); // all entities are active, so entities 2,4 should win - assertArrayEquals(new SwitchPort[] { new SwitchPort(DatapathId.of(1L), OFPort.of(1)), + 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(1)), + 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(2), ErrorStatus.DUPLICATE_DEVICE)}, + new SwitchPort(DatapathId.of(1L), OFPort.of(1), ErrorStatus.DUPLICATE_DEVICE)}, d.getAttachmentPoints(true)); c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+1); @@ -1929,11 +2149,11 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } protected void doTestDeviceQuery() throws Exception { - Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(1L), OFPort.of(2), new Date()); - Entity entity3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), DatapathId.of(5L), OFPort.of(1), new Date()); - Entity entity4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(3), DatapathId.of(5L), OFPort.of(2), new Date()); - Entity entity5 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(4), IPv4Address.of(3), DatapathId.of(5L), OFPort.of(2), new Date()); + 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); @@ -1943,7 +2163,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { IDevice d; Iterator<? extends IDevice> iter = - deviceManager.queryDevices(null, VlanVid.ofVlan(1), IPv4Address.of(1), null, null); + deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); int count = 0; while (iter.hasNext()) { count += 1; @@ -1952,7 +2172,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } assertEquals(1, count); - iter = deviceManager.queryDevices(null, VlanVid.ofVlan(3), IPv4Address.of(3), null, null); + iter = deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(3), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); count = 0; while (iter.hasNext()) { count += 1; @@ -1961,7 +2181,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } assertEquals(1, count); - iter = deviceManager.queryDevices(null, VlanVid.ofVlan(1), IPv4Address.of(3), null, null); + iter = deviceManager.queryDevices(MacAddress.NONE, VlanVid.ofVlan(1), IPv4Address.of(3), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); count = 0; while (iter.hasNext()) { count += 1; @@ -1970,7 +2190,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(0, count); Device d5 = deviceManager.learnDeviceByEntity(entity5); - iter = deviceManager.queryDevices(null, VlanVid.ofVlan(4), IPv4Address.of(3), null, null); + 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()) { @@ -1985,7 +2205,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(2, count); - iter = deviceManager.queryDevices(MacAddress.of(1L), null, null, null, null); + 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()) { @@ -2004,7 +2225,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { public void testDeviceIndex() throws Exception { EnumSet<IDeviceService.DeviceField> indexFields = EnumSet.noneOf(IDeviceService.DeviceField.class); - indexFields.add(IDeviceService.DeviceField.IPV4); + indexFields.add(IDeviceService.DeviceField.IPv4); indexFields.add(IDeviceService.DeviceField.VLAN); deviceManager.addIndex(false, indexFields); @@ -2035,11 +2256,11 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } protected void doTestDeviceClassQuery() throws Exception { - Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(1L), OFPort.of(2), new Date()); - Entity entity3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), DatapathId.of(5L), OFPort.of(1), new Date()); - Entity entity4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(3), DatapathId.of(5L), OFPort.of(2), new Date()); - Entity entity5 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(4), IPv4Address.of(3), DatapathId.of(5L), OFPort.of(2), new Date()); + 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); @@ -2052,8 +2273,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { IDevice d; Iterator<? extends IDevice> iter = - deviceManager.queryClassDevices(d1.getEntityClass(), null, - VlanVid.ofVlan(1), IPv4Address.of(1), null, null); + 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; @@ -2062,8 +2283,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } assertEquals(1, count); - iter = deviceManager.queryClassDevices(d1.getEntityClass(), null, - VlanVid.ofVlan(3), IPv4Address.of(3), null, null); + 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; @@ -2073,8 +2294,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { } assertEquals(1, count); - iter = deviceManager.queryClassDevices(d1.getEntityClass(), null, - VlanVid.ofVlan(1), IPv4Address.of(3), null, null); + 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; @@ -2084,8 +2305,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { IDevice d5 = deviceManager.learnDeviceByEntity(entity5); assertEquals(d1.getEntityClass(), d5.getEntityClass()); - iter = deviceManager.queryClassDevices(d1.getEntityClass(), null, - VlanVid.ofVlan(4), IPv4Address.of(3), null, null); + 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()) { @@ -2104,7 +2325,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { public void testDeviceClassIndex() throws Exception { EnumSet<IDeviceService.DeviceField> indexFields = EnumSet.noneOf(IDeviceService.DeviceField.class); - indexFields.add(IDeviceService.DeviceField.IPV4); + indexFields.add(IDeviceService.DeviceField.IPv4); indexFields.add(IDeviceService.DeviceField.VLAN); deviceManager.addIndex(true, indexFields); @@ -2145,14 +2366,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.getL2DomainId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes(); replay(mockTopology); - Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(1L), OFPort.of(2), new Date()); - Entity entity2b = new Entity(MacAddress.of(22L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(1L), OFPort.of(2), new Date()); + 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), DatapathId.of(2L), OFPort.of(1), new Date()); - Entity entity4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(2), IPv4Address.of(4), DatapathId.of(2L), 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), DatapathId.of(3L), OFPort.of(1), 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); @@ -2174,23 +2395,27 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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(), - null, + VlanVid.ZERO, entity1.getIpv4Address(), + entity1.getIpv6Address(), entity1.getSwitchDPID(), entity1.getSwitchPort())); assertEquals(d2, deviceManager.findDeviceByEntity(entity2)); @@ -2198,6 +2423,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(d3, deviceManager.findDevice(entity3.getMacAddress(), entity3.getVlan(), entity3.getIpv4Address(), + entity3.getIpv6Address(), entity3.getSwitchDPID(), entity3.getSwitchPort())); // switch and port not set. throws exception @@ -2206,8 +2432,9 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(), entity3.getVlan(), entity3.getIpv4Address(), - null, - null)); + entity3.getIpv6Address(), + DatapathId.NONE, + OFPort.ZERO)); } catch (IllegalArgumentException e) { exceptionCaught = true; @@ -2218,6 +2445,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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 @@ -2227,8 +2455,9 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), entity5.getVlan(), entity5.getIpv4Address(), - null, - null)); + entity5.getIpv6Address(), + DatapathId.NONE, + OFPort.ZERO)); } catch (IllegalArgumentException e) { exceptionCaught = true; @@ -2237,7 +2466,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { fail("findDevice() did not throw IllegalArgumentException"); - Entity entityNoClass = new Entity(MacAddress.of(5L), VlanVid.ofVlan(1), IPv4Address.of(5), DatapathId.of(-1L), OFPort.of(1), new Date()); + 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)); @@ -2245,19 +2474,20 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), entity1.getMacAddress(), entity1.getVlan(), - entity1.getIpv4Address())); + entity1.getIpv4Address(), + entity1.getIpv6Address())); assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), entity1.getMacAddress(), entity1.getVlan(), - null)); + IPv4Address.NONE, + entity1.getIpv6Address())); assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(), entity1.getMacAddress(), - VlanVid.ofVlan(-1), - IPv4Address.of(0))); + VlanVid.ZERO, + IPv4Address.NONE, + entity1.getIpv6Address())); } - - @Test public void testGetIPv4Addresses() { // Looks like Date is only 1s granularity @@ -2285,44 +2515,44 @@ public class DeviceManagerImplTest extends FloodlightTestCase { andReturn(false).anyTimes(); replay(mockTopology); - Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), null, null, null, new Date(2000)); + 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 Integer[0], d1.getIPv4Addresses()); + assertArrayEquals(new IPv4Address[0], d1.getIPv4Addresses()); - Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), null, null, new Date(2000)); + 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), null, DatapathId.of(2L), OFPort.of(2), new Date(3000)); + 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), DatapathId.of(2L), OFPort.of(3), new Date(3000)); + 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), null, null, new Date(4000)); - Entity e3b = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.of(3), DatapathId.of(3L), OFPort.of(3), new Date(4400)); + 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), DatapathId.of(3L), OFPort.of(3), new Date(4400)); + 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), null, null, new Date(1000)); - Entity e4b = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), null, DatapathId.of(4L), OFPort.of(4), new Date(1000)); + 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()); @@ -2331,53 +2561,160 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertArrayEquals(new IPv4Address[0], d4.getIPv4Addresses()); // Make e4 and e4a newer - Entity e4c = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.of(2), null, null, new Date(5000)); - Entity e4d = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), null, DatapathId.of(4L), OFPort.of(5), new Date(5000)); + 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()); - // FIXME: d4 should not return IP4 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), DatapathId.of(4L), OFPort.of(6), new Date(6000)); + 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), DatapathId.of(2L), OFPort.of(4), new Date(7000)); + 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), DatapathId.of(4L), OFPort.of(7), new Date(7000)); + 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), DatapathId.of(2L), OFPort.of(5), new Date(8000)); + 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), DatapathId.of(4L), OFPort.of(8), new Date(9000)); + 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.getL2DomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()), + OFPort.of(EasyMock.anyShort()), + DatapathId.of(EasyMock.anyLong()), + OFPort.of(EasyMock.anyShort()))) + .andReturn(false) + .anyTimes(); + expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()), + OFPort.of(EasyMock.anyShort()))) + .andReturn(false) + .anyTimes(); + expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(EasyMock.anyLong()), + OFPort.of(EasyMock.anyShort()), + DatapathId.of(EasyMock.anyLong()), + OFPort.of(EasyMock.anyShort()))). + andReturn(false).anyTimes(); + replay(mockTopology); + + Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), 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); + } - // TODO: this test should really go into a separate class that collects - // unit tests for Device @Test public void testGetSwitchPortVlanId() { - Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), null, DatapathId.of(10L), OFPort.of(1), new Date()); - Entity entity2 = new Entity(MacAddress.of(1L), null, null, DatapathId.of(10L), OFPort.of(1), new Date()); - Entity entity3 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(3), null, DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity4 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(42), null, DatapathId.of(1L), OFPort.of(1), new Date()); + 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 }; @@ -2387,7 +2724,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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.ofVlan(-1), VlanVid.ofVlan(1)}, + assertArrayEquals(new VlanVid[] { VlanVid.ZERO, VlanVid.ofVlan(1)}, d.getSwitchPortVlanIds(swp10x1)); assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(3), VlanVid.ofVlan(42)}, d.getSwitchPortVlanIds(swp1x1)); @@ -2424,10 +2761,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase { //flexClassifier.createTestEntityClass("Class1"); - Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - Entity entity2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(1), IPv4Address.of(2), DatapathId.of(2L), OFPort.of(2), new Date()); - Entity entity2b = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(2L), OFPort.of(2), new Date()); + 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); @@ -2436,20 +2773,20 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Device d2b = deviceManager.learnDeviceByEntity(entity2b); d1 = deviceManager.getDeviceIteratorForQuery(entity1.getMacAddress(), - entity1.getVlan(), entity1.getIpv4Address(), + entity1.getVlan(), entity1.getIpv4Address(), entity1.getIpv6Address(), entity1.getSwitchDPID(), entity1.getSwitchPort()) .next(); d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(), - entity1b.getVlan(), entity1b.getIpv4Address(), + entity1b.getVlan(), entity1b.getIpv4Address(), entity1b.getIpv6Address(), entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next(); assertEquals(d1, d1b); d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(), - entity2.getVlan(), entity2.getIpv4Address(), + entity2.getVlan(), entity2.getIpv4Address(), entity2.getIpv6Address(), entity2.getSwitchDPID(), entity2.getSwitchPort()).next(); d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(), - entity2b.getVlan(), entity2b.getIpv4Address(), + entity2b.getVlan(), entity2b.getIpv4Address(), entity2b.getIpv6Address(), entity2b.getSwitchDPID(), entity2b.getSwitchPort()).next(); assertEquals(d2, d2b); @@ -2520,8 +2857,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { @Test public void testSyncEntity() { Date d1 = new Date(); - Date d2 = new Date(0); - Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), DatapathId.of(4L), OFPort.of(5), d1); + 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); @@ -2535,7 +2872,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertNotSame(d1, se1.lastSeenTimestamp); assertNotSame(d2, se1.activeSince); - Entity e2 = new Entity(MacAddress.of(42L), null, null, null, null, null); + 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); @@ -2564,8 +2901,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEquals("MyKey", dsr.toString()); List<SyncEntity> entities = new ArrayList<SyncEntity>(); - Entity e1a = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), DatapathId.of(4L), OFPort.of(5), new Date(1000)); - Entity e1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), null, DatapathId.of(4L), OFPort.of(5), new Date(0)); + 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 @@ -2593,7 +2930,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { //************************************** // Test 1: a single entity - Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), DatapathId.of(4L), OFPort.of(5), new Date(1000)); + 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", @@ -2614,7 +2951,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), null, DatapathId.of(4L), OFPort.of(5), new Date(0)); + 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()); @@ -2630,7 +2967,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { //************************************** // 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), null, null, new Date(2000)); + 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()); @@ -2648,7 +2985,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), DatapathId.of(4L), OFPort.of(6), new Date(3000)); + 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()); @@ -2662,12 +2999,11 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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), DatapathId.of(11L), OFPort.of(1), new Date(0)); + 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 " + @@ -2740,8 +3076,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.topology = mockTopology; deviceManager.setSyncStoreWriteInterval(syncStoreIntervalMs); - Entity e1a = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(3), DatapathId.of(4L), OFPort.of(5), new Date(1000)); - e1a.setActiveSince(new Date(0)); + 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()); @@ -2754,8 +3090,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), DatapathId.of(4L), OFPort.of(5), new Date(2000)); - e1b.setActiveSince(new Date(0)); + 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()); @@ -2765,8 +3101,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), DatapathId.of(4L), OFPort.of(5), new Date(3000)); - e1c.setActiveSince(new Date(0)); + 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()); @@ -2776,8 +3112,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), DatapathId.of(4L), OFPort.of(5), new Date(4000)); - e1d.setActiveSince(new Date(0)); + 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()); @@ -2790,8 +3126,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), DatapathId.of(4L), OFPort.of(6), new Date(5000)); - e1e.setActiveSince(new Date(0)); + 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()); @@ -2802,7 +3138,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { assertEntityEquals(e1e, dsr1.getEntities().get(2)); // Add a second device - Entity e2 = new Entity(MacAddress.of(2L), null, null, DatapathId.of(5L), OFPort.of(5), new Date()); + 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()); @@ -2852,7 +3188,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { private IDevice getSingleDeviceFromDeviceManager(long mac) { Iterator<? extends IDevice> diter = - deviceManager.queryDevices(MacAddress.of(mac), null, null, null, null); + 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()); @@ -2872,8 +3208,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.setInitialSyncStoreConsolidateMs(initialSyncStoreConsolidateIntervalMs); // Add Device1 with two entities with two different IPs - Entity e1a = new Entity(MacAddress.of(1L), null, IPv4Address.of(3), DatapathId.of(4L), OFPort.of(5), new Date(1000)); - Entity e1b = new Entity(MacAddress.of(1L), null, IPv4Address.of(33), DatapathId.of(4L), OFPort.of(5), new Date(2000)); + 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); @@ -2882,8 +3218,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Add Device2 with different switch-ports. Only the most recent // one should be the attachment point - Entity e2a = new Entity(MacAddress.of(2L), null, null, DatapathId.of(4L), OFPort.of(4), new Date(1000)); - Entity e2b = new Entity(MacAddress.of(2L), null, null, DatapathId.of(4L), OFPort.of(5), new Date(2000)); + 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); @@ -2909,15 +3245,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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.ofVlan(-1) }, d.getVlanId()); + 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 Integer[0], d.getIPv4Addresses()); - assertArrayEquals(new VlanVid[] { VlanVid.ofVlan(-1) }, d.getVlanId()); + 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()); @@ -2925,7 +3261,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), null, null, DatapathId.of(1L), OFPort.of(1), null); + 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))); @@ -2941,7 +3277,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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), null, null, null, null); + 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()); @@ -2957,7 +3293,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 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), null, null, null, null); + 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()); } @@ -2975,15 +3311,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Add Device1 with two entities to store and let device manager // learn - Entity e1a = new Entity(MacAddress.of(1L), null, null, DatapathId.of(4L), OFPort.of(5), new Date(1000)); - Entity e1b = new Entity(MacAddress.of(1L), null, IPv4Address.of(3), DatapathId.of(4L), OFPort.of(5), new Date(2000)); + 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), null, null, DatapathId.of(5L), OFPort.of(5), new Date()); + 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); @@ -3022,7 +3358,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // 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), null, null, null, null, null); + 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); @@ -3033,7 +3369,5 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Thread.sleep(25); // give the scheduler time to run the task versioned = storeClient.get("Device3"); assertNull(versioned.getValue()); - } - -} +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java index e820f9e082e1ce9aa4c0686f7b87f05c34d88897..47590faaaca6c85e9f0086a3ea491920cc1cbdb1 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java @@ -28,6 +28,7 @@ import java.util.Iterator; import org.junit.Test; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -52,8 +53,8 @@ public class DeviceUniqueIndexTest extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); - e1a = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); - e1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(1), DatapathId.of(1L), OFPort.of(1), new Date()); + e1a = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.of(1, 1), DatapathId.of(1L), OFPort.of(1), new Date()); + e1b = new Entity(MacAddress.of(1L), VlanVid.ofVlan(2), IPv4Address.of(1), IPv6Address.of(1, 1), DatapathId.of(1L), OFPort.of(1), new Date()); List<Entity> d1Entities = new ArrayList<Entity>(2); d1Entities.add(e1a); d1Entities.add(e1b); @@ -61,14 +62,14 @@ public class DeviceUniqueIndexTest extends TestCase { d1Entities, null); // e2 and e2 alt match in MAC and VLAN - e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), DatapathId.of(2L), OFPort.of(2), new Date()); - e2alt = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), null, null, null, null); + e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.of(2, 2), DatapathId.of(2L), OFPort.of(2), new Date()); + e2alt = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, Entity.NO_DATE); // IP is null - e3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), null, DatapathId.of(3L), OFPort.of(3), new Date()); + e3 = new Entity(MacAddress.of(3L), VlanVid.ofVlan(3), IPv4Address.NONE, IPv6Address.NONE, DatapathId.of(3L), OFPort.of(3), new Date()); // IP and switch and port are null - e4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), null, null, null, new Date()); + e4 = new Entity(MacAddress.of(4L), VlanVid.ofVlan(4), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date()); } /* @@ -142,7 +143,8 @@ public class DeviceUniqueIndexTest extends TestCase { //------------- // Test null keys DeviceUniqueIndex idx2 = new DeviceUniqueIndex( - EnumSet.of(DeviceField.IPV4, + EnumSet.of(DeviceField.IPv4, + DeviceField.IPv6, DeviceField.SWITCH)); // only one key field is null idx2.updateIndex(e3, 3L); @@ -172,4 +174,4 @@ public class DeviceUniqueIndexTest extends TestCase { // anyways. We can now add d1 ;-) assertEquals(true, idx3.updateIndex(d1, 1L)); } -} +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java index f8c0bc3f082159a81fd6cdbfb0761ebf57182a00..0feff29e737ad5479c4ee9fd849828df7f4918a0 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java @@ -23,7 +23,10 @@ import java.util.Collection; import java.util.List; import java.util.TreeSet; +import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; +import org.projectfloodlight.openflow.types.OFPort; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.SwitchPort; @@ -62,20 +65,31 @@ public class MockDevice extends Device { public IPv4Address[] getIPv4Addresses() { TreeSet<IPv4Address> vals = new TreeSet<IPv4Address>(); for (Entity e : entities) { - if (e.getIpv4Address() == null) continue; + if (e.getIpv4Address().equals(IPv4Address.NONE)) continue; vals.add(e.getIpv4Address()); } return vals.toArray(new IPv4Address[vals.size()]); } + + @Override + public IPv6Address[] getIPv6Addresses() { + TreeSet<IPv6Address> vals = new TreeSet<IPv6Address>(); + for (Entity e : entities) { + if (e.getIpv6Address().equals(IPv6Address.NONE)) continue; + vals.add(e.getIpv6Address()); + } + + return vals.toArray(new IPv6Address[vals.size()]); + } @Override public SwitchPort[] getAttachmentPoints() { ArrayList<SwitchPort> vals = new ArrayList<SwitchPort>(entities.length); for (Entity e : entities) { - if (e.getSwitchDPID() != null && - e.getSwitchPort() != null && + if (!e.getSwitchDPID().equals(DatapathId.NONE) && + !e.getSwitchPort().equals(OFPort.ZERO) && deviceManager.isValidAttachmentPoint(e.getSwitchDPID(), e.getSwitchPort())) { SwitchPort sp = new SwitchPort(e.getSwitchDPID(), e.getSwitchPort()); @@ -90,5 +104,4 @@ public class MockDevice extends Device { return "MockDevice [getEntityClass()=" + getEntityClass() + ", getEntities()=" + Arrays.toString(getEntities()) + "]"; } - -} +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java index 780e7eb8166383f1cbcf27e1aa3f5f5bdc5a87bd..33efb3253cc67dde0fb16bca1603ad3538d56e81 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java @@ -22,6 +22,7 @@ import java.util.List; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.VlanVid; @@ -62,56 +63,27 @@ public class MockDeviceManager extends DeviceManagerImpl { /** * Learn a device using the given characteristics. * @param macAddress the MAC - * @param vlan the VLAN (can be null) - * @param ipv4Address the IP (can be null) - * @param switchDPID the attachment point switch DPID (can be null) - * @param switchPort the attachment point switch port (can be null) + * @param vlan the VLAN (can be VlanVid.ZERO for untagged) + * @param ipv4Address the IPv4 (can be IPv4Address.NONE) + * @param ipv6Address the IPv6 (can be IPv6Address.NONE) + * @param switchDPID the attachment point switch DPID (can be DatapathId.NONE) + * @param switchPort the attachment point switch port (can be OFPort.ZERO) * @param processUpdates if false, will not send updates. Note that this * method is not thread safe if this is false * @return the device, either new or not */ - public IDevice learnEntity(long macAddress, Short vlan, - Integer ipv4Address, Long switchDPID, - Integer switchPort, + public IDevice learnEntity(MacAddress macAddress, VlanVid vlan, + IPv4Address ipv4Address, IPv6Address ipv6Address, DatapathId switchDPID, + OFPort switchPort, boolean processUpdates) { List<IDeviceListener> listeners = deviceListeners.getOrderedListeners(); if (!processUpdates) { deviceListeners.clearListeners(); } - VlanVid v; - IPv4Address i; - DatapathId d; - OFPort p; - - if (vlan != null && vlan.shortValue() <= 0) - vlan = null; - if (ipv4Address != null && ipv4Address == 0) - ipv4Address = null; - - if (vlan == null) { - v = VlanVid.ofVlan(-1); - } else { - v = VlanVid.ofVlan(vlan); - } - if (ipv4Address == null) { - i = IPv4Address.NONE; - } else { - i = IPv4Address.of(ipv4Address); - } - if (switchDPID == null) { - d = DatapathId.of(0); - } else { - d = DatapathId.of(switchDPID.longValue()); - } - if (switchPort == null) { - p = OFPort.ZERO; - } else { - p = OFPort.of(switchPort); - } - - IDevice res = learnDeviceByEntity(new Entity(MacAddress.of(macAddress), - v, i, d, p, new Date())); + /* Entity will enforce all but VLAN be non-null */ + IDevice res = learnDeviceByEntity(new Entity(macAddress, + vlan, ipv4Address, ipv6Address, switchDPID, switchPort, new Date())); // Restore listeners if (listeners != null) { for (IDeviceListener listener : listeners) { @@ -129,17 +101,17 @@ public class MockDeviceManager extends DeviceManagerImpl { /** * Learn a device using the given characteristics. * @param macAddress the MAC - * @param vlan the VLAN (can be null) - * @param ipv4Address the IP (can be null) - * @param switchDPID the attachment point switch DPID (can be null) - * @param switchPort the attachment point switch port (can be null) + * @param vlan the VLAN (can be VlanVid.ZERO for untagged) + * @param ipv4Address the IPv4 (can be IPv4Address.NONE) + * @param ipv6Address the IPv6 (can be IPv6Address.NONE) + * @param switchDPID the attachment point switch DPID (can be DatapathId.NONE) + * @param switchPort the attachment point switch port (can be OFPort.ZERO) * @return the device, either new or not */ - public IDevice learnEntity(long macAddress, Short vlan, - Integer ipv4Address, Long switchDPID, - Integer switchPort) { - return learnEntity(macAddress, vlan, ipv4Address, - switchDPID, switchPort, true); + public IDevice learnEntity(MacAddress macAddress, VlanVid vlan, + IPv4Address ipv4Address, IPv6Address ipv6Address, DatapathId switchDPID, + OFPort switchPort) { + return learnEntity(macAddress, vlan, ipv4Address, ipv6Address, switchDPID, switchPort, true); } @Override @@ -171,4 +143,4 @@ public class MockDeviceManager extends DeviceManagerImpl { super.init(fmc); setSyncServiceIfNotSet(new MockSyncService()); } -} +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java index 2d92357f453f21c2bf8cc5a8543168a65dd695e0..009369e7f55c5810308bc06324a1a0a7943a2237 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java @@ -59,5 +59,4 @@ public class MockEntityClassifier extends DefaultEntityClassifier { public EnumSet<IDeviceService.DeviceField> getKeyFields() { return EnumSet.of(MAC, VLAN, SWITCH, PORT); } - } \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.java index a953d5c14dfc0b69c9a899810e37c453d087d636..edc25d9d890f8670d351a9aaaceed333a43750e7 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.java @@ -23,6 +23,8 @@ import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField. import java.util.EnumSet; +import org.projectfloodlight.openflow.types.DatapathId; + import net.floodlightcontroller.devicemanager.IDeviceService; import net.floodlightcontroller.devicemanager.IEntityClass; import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; @@ -59,11 +61,11 @@ public class MockEntityClassifierMac extends DefaultEntityClassifier { if (entity.getSwitchDPID() == null) { throw new IllegalArgumentException("Not all key fields specified." + " Required fields: " + getKeyFields()); - } else if (entity.getSwitchDPID().getLong() == 1L) { + } else if (entity.getSwitchDPID().equals(DatapathId.of(1))) { return testECMac1; - } else if (entity.getSwitchDPID().getLong() == 2L) { + } else if (entity.getSwitchDPID().equals(DatapathId.of(2))) { return testECMac2; - } else if (entity.getSwitchDPID().getLong() == -1L) { + } else if (entity.getSwitchDPID().equals(DatapathId.of(-1))) { return null; } return DefaultEntityClassifier.entityClass; diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.java index c02e34069e4130f6fb0a9c2466f7b59b4ca7a440..fbb17e36ba5b0a17228da3b9f85eda8a6e11c607 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.java @@ -89,4 +89,4 @@ public class MockFlexEntityClassifier extends DefaultEntityClassifier { public EnumSet<IDeviceService.DeviceField> getKeyFields() { return EnumSet.of(MAC, VLAN, SWITCH, PORT); } -} +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java index 45eac76cfb4577227f6cc6cd3bf1ae787aa0c407..51f1faefb541b21acefbe0151385aa1a7277ad9f 100644 --- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java +++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java @@ -1,19 +1,19 @@ /** -* 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. -**/ + * 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.forwarding; @@ -45,6 +45,7 @@ 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.routing.IRoutingService; import net.floodlightcontroller.routing.Route; @@ -73,12 +74,14 @@ import org.projectfloodlight.openflow.protocol.OFVersion; 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.IpProtocol; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.TransportPort; import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.VlanVid; import org.projectfloodlight.openflow.protocol.OFPacketInReason; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; @@ -86,435 +89,697 @@ import org.sdnplatform.sync.ISyncService; import org.sdnplatform.sync.test.MockSyncService; public class ForwardingTest extends FloodlightTestCase { - protected FloodlightContext cntx; - protected MockDeviceManager deviceManager; - protected IRoutingService routingEngine; - protected Forwarding forwarding; - protected ITopologyService topology; - protected MockThreadPoolService threadPool; - protected IOFSwitch sw1, sw2; - protected OFFeaturesReply swFeatures; - protected IDevice srcDevice, dstDevice1, dstDevice2; - protected OFPacketIn packetIn; - protected OFPacketOut packetOut; - protected OFPacketOut packetOutFlooded; - protected IPacket testPacket; - protected byte[] testPacketSerialized; - protected int expected_wildcards; - protected Date currentDate; - private MockSyncService mockSyncService; - private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13); - - - @Override - public void setUp() throws Exception { - super.setUp(); - - cntx = new FloodlightContext(); - - // Module loader setup - /* - Collection<Class<? extends IFloodlightModule>> mods = new ArrayList<Class<? extends IFloodlightModule>>(); - Collection<IFloodlightService> mockedServices = new ArrayList<IFloodlightService>(); - mods.add(Forwarding.class); - routingEngine = createMock(IRoutingService.class); - topology = createMock(ITopologyService.class); - mockedServices.add(routingEngine); - mockedServices.add(topology); - FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader(); - fml.setupModules(mods, mockedServices); - mockFloodlightProvider = - (MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class); - deviceManager = - (MockDeviceManager) fml.getModuleByName(MockDeviceManager.class); - threadPool = - (MockThreadPoolService) fml.getModuleByName(MockThreadPoolService.class); - forwarding = - (Forwarding) fml.getModuleByName(Forwarding.class); - */ - mockFloodlightProvider = getMockFloodlightProvider(); - forwarding = new Forwarding(); - threadPool = new MockThreadPoolService(); - deviceManager = new MockDeviceManager(); - routingEngine = createMock(IRoutingService.class); - topology = createMock(ITopologyService.class); - mockSyncService = new MockSyncService(); - DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); - - - FloodlightModuleContext fmc = new FloodlightModuleContext(); - fmc.addService(IFloodlightProviderService.class, - mockFloodlightProvider); - fmc.addService(IThreadPoolService.class, threadPool); - fmc.addService(ITopologyService.class, topology); - fmc.addService(IRoutingService.class, routingEngine); - fmc.addService(IDeviceService.class, deviceManager); - fmc.addService(IEntityClassifierService.class, entityClassifier); - fmc.addService(ISyncService.class, mockSyncService); - fmc.addService(IDebugCounterService.class, new MockDebugCounterService()); - fmc.addService(IDebugEventService.class, new MockDebugEventService()); - fmc.addService(IOFSwitchService.class, getMockSwitchService()); - - topology.addListener(anyObject(ITopologyListener.class)); - expectLastCall().anyTimes(); - expect(topology.isIncomingBroadcastAllowed(anyObject(DatapathId.class), anyObject(OFPort.class))).andReturn(true).anyTimes(); - replay(topology); - - threadPool.init(fmc); - mockSyncService.init(fmc); - forwarding.init(fmc); - deviceManager.init(fmc); - entityClassifier.init(fmc); - threadPool.startUp(fmc); - mockSyncService.startUp(fmc); - deviceManager.startUp(fmc); - forwarding.startUp(fmc); - entityClassifier.startUp(fmc); - verify(topology); - - swFeatures = factory.buildFeaturesReply().setNBuffers(1000).build(); - // Mock switches - sw1 = EasyMock.createMock(IOFSwitch.class); - expect(sw1.getId()).andReturn(DatapathId.of(1L)).anyTimes(); - expect(sw1.getOFFactory()).andReturn(factory).anyTimes(); - expect(sw1.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes(); - - sw2 = EasyMock.createMock(IOFSwitch.class); - expect(sw2.getId()).andReturn(DatapathId.of(2L)).anyTimes(); - expect(sw2.getOFFactory()).andReturn(factory).anyTimes(); - expect(sw2.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes(); - - expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); - - expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); - - // Load the switch map - Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>(); - switches.put(DatapathId.of(1L), sw1); - switches.put(DatapathId.of(2L), sw2); - getMockSwitchService().setSwitches(switches); - - // Build test packet - testPacket = new Ethernet() - .setDestinationMACAddress("00:11:22:33:44:55") - .setSourceMACAddress("00:44:33:22:11:00") - .setEtherType(EthType.IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.1") - .setDestinationAddress("192.168.1.2") - .setPayload(new UDP() - .setSourcePort((short) 5000) - .setDestinationPort((short) 5001) - .setPayload(new Data(new byte[] {0x01})))); - - - - currentDate = new Date(); - - // Mock Packet-in - testPacketSerialized = testPacket.serialize(); - packetIn = factory.buildPacketIn() - .setMatch(factory.buildMatch() - .setExact(MatchField.IN_PORT, OFPort.of(1)) - .setExact(MatchField.ETH_SRC, MacAddress.of("00:44:33:22:11:00")) - .setExact(MatchField.ETH_DST, MacAddress.of("00:11:22:33:44:55")) - .setExact(MatchField.ETH_TYPE, EthType.IPv4) - .setExact(MatchField.IPV4_SRC, IPv4Address.of("192.168.1.1")) - .setExact(MatchField.IPV4_DST, IPv4Address.of("192.168.1.2")) - .setExact(MatchField.IP_PROTO, IpProtocol.UDP) - .setExact(MatchField.UDP_SRC, TransportPort.of(5000)) - .setExact(MatchField.UDP_DST, TransportPort.of(5001)) - .build()) - .setBufferId(OFBufferId.NO_BUFFER) - .setData(testPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .build(); - - // Mock Packet-out - List<OFAction> poactions = new ArrayList<OFAction>(); - poactions.add(factory.actions().output(OFPort.of(3), Integer.MAX_VALUE)); - packetOut = factory.buildPacketOut() - .setBufferId(this.packetIn.getBufferId()) - .setActions(poactions) - .setInPort(OFPort.of(1)) - .setData(testPacketSerialized) - .setXid(15) - .build(); - - // Mock Packet-out with OFPP_FLOOD action - poactions = new ArrayList<OFAction>(); - poactions.add(factory.actions().output(OFPort.FLOOD, Integer.MAX_VALUE)); - packetOutFlooded = factory.buildPacketOut() - .setBufferId(this.packetIn.getBufferId()) - .setInPort(packetIn.getMatch().get(MatchField.IN_PORT)) - .setXid(17) - .setActions(poactions) - .setData(testPacketSerialized) - .build(); - - IFloodlightProviderService.bcStore. - put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet)testPacket); - } - - enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 }; - public void learnDevices(DestDeviceToLearn destDeviceToLearn) { - // Build src and dest devices - MacAddress dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress(); - MacAddress dataLayerDest = - ((Ethernet)testPacket).getDestinationMACAddress(); - IPv4Address networkSource = - ((IPv4)((Ethernet)testPacket).getPayload()). - getSourceAddress(); - IPv4Address networkDest = - ((IPv4)((Ethernet)testPacket).getPayload()). - getDestinationAddress(); - - reset(topology); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))) - .andReturn(true) - .anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))) - .andReturn(true) - .anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))) - .andReturn(true) - .anyTimes(); - replay(topology); - - srcDevice = - deviceManager.learnEntity(dataLayerSource.getLong(), - null, networkSource.getInt(), - 1L, 1); - IDeviceService.fcStore. put(cntx, - IDeviceService.CONTEXT_SRC_DEVICE, - srcDevice); - if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) { - dstDevice1 = - deviceManager.learnEntity(dataLayerDest.getLong(), - null, networkDest.getInt(), - 2L, 3); - IDeviceService.fcStore.put(cntx, - IDeviceService.CONTEXT_DST_DEVICE, - dstDevice1); - } - if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) { - dstDevice2 = - deviceManager.learnEntity(dataLayerDest.getLong(), - null, networkDest.getInt(), - 1L, 3); - IDeviceService.fcStore.put(cntx, - IDeviceService.CONTEXT_DST_DEVICE, - dstDevice2); - } - verify(topology); - } - - @Test - public void testForwardMultiSwitchPath() throws Exception { - learnDevices(DestDeviceToLearn.DEVICE1); - - Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); - Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL); - - Route route = new Route(DatapathId.of(1L), DatapathId.of(2L)); - List<NodePortTuple> nptList = new ArrayList<NodePortTuple>(); - nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); - nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); - nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1))); - nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3))); - route.setPath(nptList); - expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); - - // Expected Flow-mods - Match match = packetIn.getMatch(); - OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - OFFlowMod fm1 = factory.buildFlowAdd() - .setIdleTimeout((short)5) - .setMatch(match) - .setActions(actions) - .setOutPort(action.getPort()) - .setBufferId(OFBufferId.NO_BUFFER) - .setCookie(U64.of(2L << 52)) - .setPriority(1) - .build(); - OFFlowMod fm2 = fm1.createBuilder().build(); - - sw1.write(capture(wc1)); - expectLastCall().anyTimes(); - sw2.write(capture(wc2)); - expectLastCall().anyTimes(); - - reset(topology); - expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); - expect(topology.getL2DomainId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes(); - expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); - - // Reset mocks, trigger the packet in, and validate results - replay(sw1, sw2, routingEngine, topology); - forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2, routingEngine); - - assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. - assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. - - List<OFMessage> msglist = wc1.getValues(); - - for (OFMessage m: msglist) { - if (m instanceof OFFlowMod) - assertTrue(OFMessageUtils.equalsIgnoreXid(fm1, m)); - else if (m instanceof OFPacketOut) { - assertTrue(OFMessageUtils.equalsIgnoreXid(packetOut, m)); - } - } - - OFMessage m = wc2.getValue(); - assert (m instanceof OFFlowMod); - assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2)); - } - - @Test - public void testForwardSingleSwitchPath() throws Exception { - learnDevices(DestDeviceToLearn.DEVICE2); - - Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); - Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL); - - Route route = new Route(DatapathId.of(1L), DatapathId.of(1L)); - route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); - route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); - expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); - - // Expected Flow-mods - Match match = packetIn.getMatch(); - OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - OFFlowMod fm1 = factory.buildFlowAdd() - .setIdleTimeout((short)5) - .setMatch(match) - .setActions(actions) - .setOutPort(OFPort.of(3)) - .setBufferId(OFBufferId.NO_BUFFER) - .setCookie(U64.of(2L<< 52)) - .setPriority(1) - .build(); - - // Record expected packet-outs/flow-mods - sw1.write(capture(wc1)); - expectLastCall().once(); - sw1.write(capture(wc2)); - expectLastCall().once(); - - reset(topology); - expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); - expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes(); - - // Reset mocks, trigger the packet in, and validate results - replay(sw1, sw2, routingEngine, topology); - forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2, routingEngine); - - assertTrue(wc1.hasCaptured()); - assertTrue(wc2.hasCaptured()); - - assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1)); - assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut)); - } - - /*TODO OFMessageDamper broken due to XID variability in OFMessages... need to fix @Test */ - public void testFlowModDampening() throws Exception { - learnDevices(DestDeviceToLearn.DEVICE2); - - reset(topology); - expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))) - .andReturn(true).anyTimes(); - expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); - replay(topology); - - - Route route = new Route(DatapathId.of(1L), DatapathId.of(1L)); - route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); - route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); - expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); - - // Expected Flow-mods - Match match = packetIn.getMatch(); - OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - OFFlowMod fm1 = factory.buildFlowAdd() - .setIdleTimeout((short)5) - .setMatch(match) - .setActions(actions) - .setOutPort(OFPort.of(3)) - .setBufferId(OFBufferId.NO_BUFFER) - .setCookie(U64.of(2L << 52)) - .setXid(anyLong()) - .build(); - - // Record expected packet-outs/flow-mods - // We will inject the packet_in 3 times and expect 1 flow mod and - // 3 packet outs due to flow mod dampening - sw1.write(fm1); - expectLastCall().times(1); - // Update new expected XID - sw1.write(packetOut.createBuilder().setXid(anyLong()).build()); - expectLastCall().times(3); - - reset(topology); - expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); - expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes(); - - // Reset mocks, trigger the packet in, and validate results - replay(sw1, routingEngine, topology); - forwarding.receive(sw1, this.packetIn, cntx); - forwarding.receive(sw1, this.packetIn, cntx); - forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, routingEngine); - } - - @Test - public void testForwardNoPath() throws Exception { - learnDevices(DestDeviceToLearn.NONE); - - // Set no destination attachment point or route - // expect no Flow-mod but expect the packet to be flooded - - Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); - - // Reset mocks, trigger the packet in, and validate results - reset(topology); - expect(topology.isIncomingBroadcastAllowed(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), - OFPort.of(anyShort()))) - .andReturn(true) - .anyTimes(); - expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) - .andReturn(true).anyTimes(); - // Reset XID to expected (dependent on prior unit tests) - sw1.write(capture(wc1)); - expectLastCall().once(); - replay(sw1, sw2, routingEngine, topology); - forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2, routingEngine); - - assertTrue(wc1.hasCaptured()); - assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFlooded)); - } - -} + protected FloodlightContext cntx; + protected MockDeviceManager deviceManager; + protected IRoutingService routingEngine; + protected Forwarding forwarding; + protected ITopologyService topology; + protected MockThreadPoolService threadPool; + protected IOFSwitch sw1, sw2; + protected OFFeaturesReply swFeatures; + protected IDevice srcDevice, dstDevice1, dstDevice2; /* reuse for IPv4 and IPv6 */ + protected OFPacketIn packetIn; + protected OFPacketIn packetInIPv6; + protected OFPacketOut packetOut; + protected OFPacketOut packetOutIPv6; + protected OFPacketOut packetOutFlooded; + protected OFPacketOut packetOutFloodedIPv6; + protected IPacket testPacket; + protected IPacket testPacketIPv6; + protected byte[] testPacketSerialized; + protected byte[] testPacketSerializedIPv6; + protected int expected_wildcards; + protected Date currentDate; + private MockSyncService mockSyncService; + private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13); + + + @Override + public void setUp() throws Exception { + super.setUp(); + + cntx = new FloodlightContext(); + + // Module loader setup + mockFloodlightProvider = getMockFloodlightProvider(); + forwarding = new Forwarding(); + threadPool = new MockThreadPoolService(); + deviceManager = new MockDeviceManager(); + routingEngine = createMock(IRoutingService.class); + topology = createMock(ITopologyService.class); + mockSyncService = new MockSyncService(); + DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); + + FloodlightModuleContext fmc = new FloodlightModuleContext(); + fmc.addService(IFloodlightProviderService.class, + mockFloodlightProvider); + fmc.addService(IThreadPoolService.class, threadPool); + fmc.addService(ITopologyService.class, topology); + fmc.addService(IRoutingService.class, routingEngine); + fmc.addService(IDeviceService.class, deviceManager); + fmc.addService(IEntityClassifierService.class, entityClassifier); + fmc.addService(ISyncService.class, mockSyncService); + fmc.addService(IDebugCounterService.class, new MockDebugCounterService()); + fmc.addService(IDebugEventService.class, new MockDebugEventService()); + fmc.addService(IOFSwitchService.class, getMockSwitchService()); + + topology.addListener(anyObject(ITopologyListener.class)); + expectLastCall().anyTimes(); + expect(topology.isIncomingBroadcastAllowed(anyObject(DatapathId.class), anyObject(OFPort.class))).andReturn(true).anyTimes(); + replay(topology); + + threadPool.init(fmc); + mockSyncService.init(fmc); + forwarding.init(fmc); + deviceManager.init(fmc); + entityClassifier.init(fmc); + threadPool.startUp(fmc); + mockSyncService.startUp(fmc); + deviceManager.startUp(fmc); + forwarding.startUp(fmc); + entityClassifier.startUp(fmc); + verify(topology); + + swFeatures = factory.buildFeaturesReply().setNBuffers(1000).build(); + // Mock switches + sw1 = EasyMock.createMock(IOFSwitch.class); + expect(sw1.getId()).andReturn(DatapathId.of(1L)).anyTimes(); + expect(sw1.getOFFactory()).andReturn(factory).anyTimes(); + expect(sw1.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes(); + + sw2 = EasyMock.createMock(IOFSwitch.class); + expect(sw2.getId()).andReturn(DatapathId.of(2L)).anyTimes(); + expect(sw2.getOFFactory()).andReturn(factory).anyTimes(); + expect(sw2.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes(); + + expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); + + expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); + + // Load the switch map + Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>(); + switches.put(DatapathId.of(1L), sw1); + switches.put(DatapathId.of(2L), sw2); + getMockSwitchService().setSwitches(switches); + + // Build test packet + testPacket = new Ethernet() + .setDestinationMACAddress("00:11:22:33:44:55") + .setSourceMACAddress("00:44:33:22:11:00") + .setEtherType(EthType.IPv4) + .setPayload( + new IPv4() + .setTtl((byte) 128) + .setSourceAddress("192.168.1.1") + .setDestinationAddress("192.168.1.2") + .setPayload(new UDP() + .setSourcePort((short) 5000) + .setDestinationPort((short) 5001) + .setPayload(new Data(new byte[] {0x01})))); + + testPacketIPv6 = new Ethernet() + .setDestinationMACAddress("00:11:22:33:44:55") + .setSourceMACAddress("00:44:33:22:11:00") + .setEtherType(EthType.IPv6) + .setPayload( + new IPv6() + .setHopLimit((byte) 128) + .setSourceAddress(IPv6Address.of(1, 1)) + .setDestinationAddress(IPv6Address.of(2, 2)) + .setNextHeader(IpProtocol.UDP) + .setPayload(new UDP() + .setSourcePort((short) 5000) + .setDestinationPort((short) 5001) + .setPayload(new Data(new byte[] {0x01})))); + + currentDate = new Date(); + + // Mock Packet-in + testPacketSerialized = testPacket.serialize(); + testPacketSerializedIPv6 = testPacketIPv6.serialize(); + + packetIn = factory.buildPacketIn() + .setMatch(factory.buildMatch() + .setExact(MatchField.IN_PORT, OFPort.of(1)) + .setExact(MatchField.ETH_SRC, MacAddress.of("00:44:33:22:11:00")) + .setExact(MatchField.ETH_DST, MacAddress.of("00:11:22:33:44:55")) + .setExact(MatchField.ETH_TYPE, EthType.IPv4) + .setExact(MatchField.IPV4_SRC, IPv4Address.of("192.168.1.1")) + .setExact(MatchField.IPV4_DST, IPv4Address.of("192.168.1.2")) + .setExact(MatchField.IP_PROTO, IpProtocol.UDP) + .setExact(MatchField.UDP_SRC, TransportPort.of(5000)) + .setExact(MatchField.UDP_DST, TransportPort.of(5001)) + .build()) + .setBufferId(OFBufferId.NO_BUFFER) + .setData(testPacketSerialized) + .setReason(OFPacketInReason.NO_MATCH) + .build(); + packetInIPv6 = factory.buildPacketIn() + .setMatch(factory.buildMatch() + .setExact(MatchField.IN_PORT, OFPort.of(1)) + .setExact(MatchField.ETH_SRC, MacAddress.of("00:44:33:22:11:00")) + .setExact(MatchField.ETH_DST, MacAddress.of("00:11:22:33:44:55")) + .setExact(MatchField.ETH_TYPE, EthType.IPv6) + .setExact(MatchField.IPV6_SRC, IPv6Address.of(1, 1)) + .setExact(MatchField.IPV6_DST, IPv6Address.of(2, 2)) + .setExact(MatchField.IP_PROTO, IpProtocol.UDP) + .setExact(MatchField.UDP_SRC, TransportPort.of(5000)) + .setExact(MatchField.UDP_DST, TransportPort.of(5001)) + .build()) + .setBufferId(OFBufferId.NO_BUFFER) + .setData(testPacketSerializedIPv6) + .setReason(OFPacketInReason.NO_MATCH) + .build(); + + // Mock Packet-out + List<OFAction> poactions = new ArrayList<OFAction>(); + poactions.add(factory.actions().output(OFPort.of(3), Integer.MAX_VALUE)); + packetOut = factory.buildPacketOut() + .setBufferId(this.packetIn.getBufferId()) + .setActions(poactions) + .setInPort(OFPort.of(1)) + .setData(testPacketSerialized) + .setXid(15) + .build(); + packetOutIPv6 = factory.buildPacketOut() + .setBufferId(this.packetInIPv6.getBufferId()) + .setActions(poactions) + .setInPort(OFPort.of(1)) + .setData(testPacketSerializedIPv6) + .setXid(15) + .build(); + + // Mock Packet-out with OFPP_FLOOD action + poactions = new ArrayList<OFAction>(); + poactions.add(factory.actions().output(OFPort.FLOOD, Integer.MAX_VALUE)); + packetOutFlooded = factory.buildPacketOut() + .setBufferId(this.packetIn.getBufferId()) + .setInPort(packetIn.getMatch().get(MatchField.IN_PORT)) + .setXid(17) + .setActions(poactions) + .setData(testPacketSerialized) + .build(); + packetOutFloodedIPv6 = factory.buildPacketOut() + .setBufferId(this.packetInIPv6.getBufferId()) + .setInPort(packetInIPv6.getMatch().get(MatchField.IN_PORT)) + .setXid(17) + .setActions(poactions) + .setData(testPacketSerializedIPv6) + .build(); + } + + void removeDeviceFromContext() { + IFloodlightProviderService.bcStore. + remove(cntx, + IFloodlightProviderService.CONTEXT_PI_PAYLOAD); + IFloodlightProviderService.bcStore. + remove(cntx, + IDeviceService.CONTEXT_SRC_DEVICE); + IFloodlightProviderService.bcStore. + remove(cntx, + IDeviceService.CONTEXT_DST_DEVICE); + } + + enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 }; + public void learnDevices(DestDeviceToLearn destDeviceToLearn) { + // Build src and dest devices + MacAddress dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress(); + MacAddress dataLayerDest = + ((Ethernet)testPacket).getDestinationMACAddress(); + IPv4Address networkSource = + ((IPv4)((Ethernet)testPacket).getPayload()). + getSourceAddress(); + IPv4Address networkDest = + ((IPv4)((Ethernet)testPacket).getPayload()). + getDestinationAddress(); + + reset(topology); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))) + .andReturn(true) + .anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))) + .andReturn(true) + .anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))) + .andReturn(true) + .anyTimes(); + replay(topology); + + srcDevice = + deviceManager.learnEntity(dataLayerSource, VlanVid.ZERO, + networkSource, IPv6Address.NONE, + DatapathId.of(1), OFPort.of(1)); + IDeviceService.fcStore. put(cntx, + IDeviceService.CONTEXT_SRC_DEVICE, + srcDevice); + if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) { + dstDevice1 = + deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO, + networkDest, IPv6Address.NONE, + DatapathId.of(2), OFPort.of(3)); + IDeviceService.fcStore.put(cntx, + IDeviceService.CONTEXT_DST_DEVICE, + dstDevice1); + } + if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) { + dstDevice2 = + deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO, + networkDest, IPv6Address.NONE, + DatapathId.of(1), OFPort.of(3)); + IDeviceService.fcStore.put(cntx, + IDeviceService.CONTEXT_DST_DEVICE, + dstDevice2); + } + verify(topology); + + IFloodlightProviderService.bcStore. + put(cntx, + IFloodlightProviderService.CONTEXT_PI_PAYLOAD, + (Ethernet)testPacket); + } + + public void learnDevicesIPv6(DestDeviceToLearn destDeviceToLearn) { + // Build src and dest devices + MacAddress dataLayerSource = ((Ethernet)testPacketIPv6).getSourceMACAddress(); + MacAddress dataLayerDest = + ((Ethernet)testPacketIPv6).getDestinationMACAddress(); + IPv6Address networkSource = + ((IPv6)((Ethernet)testPacketIPv6).getPayload()). + getSourceAddress(); + IPv6Address networkDest = + ((IPv6)((Ethernet)testPacketIPv6).getPayload()). + getDestinationAddress(); + + reset(topology); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))) + .andReturn(true) + .anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))) + .andReturn(true) + .anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))) + .andReturn(true) + .anyTimes(); + replay(topology); + + srcDevice = + deviceManager.learnEntity(dataLayerSource, VlanVid.ZERO, + IPv4Address.NONE, networkSource, + DatapathId.of(1), OFPort.of(1)); + IDeviceService.fcStore.put(cntx, + IDeviceService.CONTEXT_SRC_DEVICE, + srcDevice); + if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) { + dstDevice1 = + deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO, + IPv4Address.NONE, networkDest, + DatapathId.of(2), OFPort.of(3)); + IDeviceService.fcStore.put(cntx, + IDeviceService.CONTEXT_DST_DEVICE, + dstDevice1); + } + if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) { + dstDevice2 = + deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO, + IPv4Address.NONE, networkDest, + DatapathId.of(1), OFPort.of(3)); + IDeviceService.fcStore.put(cntx, + IDeviceService.CONTEXT_DST_DEVICE, + dstDevice2); + } + verify(topology); + + IFloodlightProviderService.bcStore. + put(cntx, + IFloodlightProviderService.CONTEXT_PI_PAYLOAD, + (Ethernet)testPacketIPv6); + } + + @Test + public void testForwardMultiSwitchPath() throws Exception { + learnDevices(DestDeviceToLearn.DEVICE1); + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL); + + Route route = new Route(DatapathId.of(1L), DatapathId.of(2L)); + List<NodePortTuple> nptList = new ArrayList<NodePortTuple>(); + nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); + nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); + nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1))); + nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3))); + route.setPath(nptList); + expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); + + // Expected Flow-mods + Match match = packetIn.getMatch(); + OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); + List<OFAction> actions = new ArrayList<OFAction>(); + actions.add(action); + + OFFlowMod fm1 = factory.buildFlowAdd() + .setIdleTimeout((short)5) + .setMatch(match) + .setActions(actions) + .setOutPort(action.getPort()) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.of(2L << 52)) + .setPriority(1) + .build(); + OFFlowMod fm2 = fm1.createBuilder().build(); + + sw1.write(capture(wc1)); + expectLastCall().anyTimes(); + sw2.write(capture(wc2)); + expectLastCall().anyTimes(); + + reset(topology); + expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.getL2DomainId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes(); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); + + // Reset mocks, trigger the packet in, and validate results + replay(sw1, sw2, routingEngine, topology); + forwarding.receive(sw1, this.packetIn, cntx); + verify(sw1, sw2, routingEngine); + + assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. + assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. + + List<OFMessage> msglist = wc1.getValues(); + + for (OFMessage m: msglist) { + if (m instanceof OFFlowMod) + assertTrue(OFMessageUtils.equalsIgnoreXid(fm1, m)); + else if (m instanceof OFPacketOut) { + assertTrue(OFMessageUtils.equalsIgnoreXid(packetOut, m)); + } + } + + OFMessage m = wc2.getValue(); + assert (m instanceof OFFlowMod); + assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2)); + + removeDeviceFromContext(); + } + + @Test + public void testForwardMultiSwitchPathIPv6() throws Exception { + learnDevicesIPv6(DestDeviceToLearn.DEVICE1); + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL); + + Route route = new Route(DatapathId.of(1L), DatapathId.of(2L)); + List<NodePortTuple> nptList = new ArrayList<NodePortTuple>(); + nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); + nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); + nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1))); + nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3))); + route.setPath(nptList); + expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); + + // Expected Flow-mods + Match match = packetInIPv6.getMatch(); + OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); + List<OFAction> actions = new ArrayList<OFAction>(); + actions.add(action); + + OFFlowMod fm1 = factory.buildFlowAdd() + .setIdleTimeout((short)5) + .setMatch(match) + .setActions(actions) + .setOutPort(action.getPort()) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.of(2L << 52)) + .setPriority(1) + .build(); + OFFlowMod fm2 = fm1.createBuilder().build(); + + sw1.write(capture(wc1)); + expectLastCall().anyTimes(); + sw2.write(capture(wc2)); + expectLastCall().anyTimes(); + + reset(topology); + expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.getL2DomainId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes(); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); + + // Reset mocks, trigger the packet in, and validate results + replay(sw1, sw2, routingEngine, topology); + forwarding.receive(sw1, this.packetInIPv6, cntx); + verify(sw1, sw2, routingEngine); + + assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. + assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. + + List<OFMessage> msglist = wc1.getValues(); + + for (OFMessage m: msglist) { + if (m instanceof OFFlowMod) + assertTrue(OFMessageUtils.equalsIgnoreXid(fm1, m)); + else if (m instanceof OFPacketOut) { + assertTrue(OFMessageUtils.equalsIgnoreXid(packetOutIPv6, m)); + } + } + + OFMessage m = wc2.getValue(); + assert (m instanceof OFFlowMod); + assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2)); + + removeDeviceFromContext(); + } + + @Test + public void testForwardSingleSwitchPath() throws Exception { + learnDevices(DestDeviceToLearn.DEVICE2); + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL); + + Route route = new Route(DatapathId.of(1L), DatapathId.of(1L)); + route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); + route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); + expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); + + // Expected Flow-mods + Match match = packetIn.getMatch(); + OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); + List<OFAction> actions = new ArrayList<OFAction>(); + actions.add(action); + + OFFlowMod fm1 = factory.buildFlowAdd() + .setIdleTimeout((short)5) + .setMatch(match) + .setActions(actions) + .setOutPort(OFPort.of(3)) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.of(2L<< 52)) + .setPriority(1) + .build(); + + // Record expected packet-outs/flow-mods + sw1.write(capture(wc1)); + expectLastCall().once(); + sw1.write(capture(wc2)); + expectLastCall().once(); + + reset(topology); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); + expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes(); + + // Reset mocks, trigger the packet in, and validate results + replay(sw1, sw2, routingEngine, topology); + forwarding.receive(sw1, this.packetIn, cntx); + verify(sw1, sw2, routingEngine); + + assertTrue(wc1.hasCaptured()); + assertTrue(wc2.hasCaptured()); + + assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1)); + assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut)); + + removeDeviceFromContext(); + } + + @Test + public void testForwardSingleSwitchPathIPv6() throws Exception { + learnDevicesIPv6(DestDeviceToLearn.DEVICE2); + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL); + + Route route = new Route(DatapathId.of(1L), DatapathId.of(1L)); + route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); + route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); + expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); + + // Expected Flow-mods + Match match = packetInIPv6.getMatch(); + OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); + List<OFAction> actions = new ArrayList<OFAction>(); + actions.add(action); + + OFFlowMod fm1 = factory.buildFlowAdd() + .setIdleTimeout((short)5) + .setMatch(match) + .setActions(actions) + .setOutPort(OFPort.of(3)) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.of(2L<< 52)) + .setPriority(1) + .build(); + + // Record expected packet-outs/flow-mods + sw1.write(capture(wc1)); + expectLastCall().once(); + sw1.write(capture(wc2)); + expectLastCall().once(); + + reset(topology); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); + expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes(); + + // Reset mocks, trigger the packet in, and validate results + replay(sw1, sw2, routingEngine, topology); + forwarding.receive(sw1, this.packetInIPv6, cntx); + verify(sw1, sw2, routingEngine); + + assertTrue(wc1.hasCaptured()); + assertTrue(wc2.hasCaptured()); + + assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1)); + assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOutIPv6)); + + removeDeviceFromContext(); + } + + /*TODO OFMessageDamper broken due to XID variability in OFMessages... need to fix @Test */ + /*TODO make an IPv6 test for this once OFMessageDamper fixed */ + public void testFlowModDampening() throws Exception { + learnDevices(DestDeviceToLearn.DEVICE2); + + reset(topology); + expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))) + .andReturn(true).anyTimes(); + expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + replay(topology); + + + Route route = new Route(DatapathId.of(1L), DatapathId.of(1L)); + route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1))); + route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3))); + expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce(); + + // Expected Flow-mods + Match match = packetIn.getMatch(); + OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE); + List<OFAction> actions = new ArrayList<OFAction>(); + actions.add(action); + + OFFlowMod fm1 = factory.buildFlowAdd() + .setIdleTimeout((short)5) + .setMatch(match) + .setActions(actions) + .setOutPort(OFPort.of(3)) + .setBufferId(OFBufferId.NO_BUFFER) + .setCookie(U64.of(2L << 52)) + .setXid(anyLong()) + .build(); + + // Record expected packet-outs/flow-mods + // We will inject the packet_in 3 times and expect 1 flow mod and + // 3 packet outs due to flow mod dampening + sw1.write(fm1); + expectLastCall().times(1); + // Update new expected XID + sw1.write(packetOut.createBuilder().setXid(anyLong()).build()); + expectLastCall().times(3); + + reset(topology); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes(); + expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes(); + + // Reset mocks, trigger the packet in, and validate results + replay(sw1, routingEngine, topology); + forwarding.receive(sw1, this.packetIn, cntx); + forwarding.receive(sw1, this.packetIn, cntx); + forwarding.receive(sw1, this.packetIn, cntx); + verify(sw1, routingEngine); + + removeDeviceFromContext(); + } + + @Test + public void testForwardNoPath() throws Exception { + learnDevices(DestDeviceToLearn.NONE); + + // Set no destination attachment point or route + // expect no Flow-mod but expect the packet to be flooded + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + + // Reset mocks, trigger the packet in, and validate results + reset(topology); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), + OFPort.of(anyShort()))) + .andReturn(true) + .anyTimes(); + expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) + .andReturn(true).anyTimes(); + // Reset XID to expected (dependent on prior unit tests) + sw1.write(capture(wc1)); + expectLastCall().once(); + replay(sw1, sw2, routingEngine, topology); + forwarding.receive(sw1, this.packetIn, cntx); + verify(sw1, sw2, routingEngine); + + assertTrue(wc1.hasCaptured()); + assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFlooded)); + + removeDeviceFromContext(); + } + + @Test + public void testForwardNoPathIPv6() throws Exception { + learnDevicesIPv6(DestDeviceToLearn.NONE); + + // Set no destination attachment point or route + // expect no Flow-mod but expect the packet to be flooded + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + + // Reset mocks, trigger the packet in, and validate results + reset(topology); + expect(topology.isIncomingBroadcastAllowed(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), + OFPort.of(anyShort()))) + .andReturn(true) + .anyTimes(); + expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) + .andReturn(true).anyTimes(); + // Reset XID to expected (dependent on prior unit tests) + sw1.write(capture(wc1)); + expectLastCall().once(); + replay(sw1, sw2, routingEngine, topology); + forwarding.receive(sw1, this.packetInIPv6, cntx); + verify(sw1, sw2, routingEngine); + + assertTrue(wc1.hasCaptured()); + assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFloodedIPv6)); + + removeDeviceFromContext(); + } +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java index a2640a98032f44aaa52c765ca2a01b240ef46816..0aa8d933ea11f233eaad23cd3d94847503d64ec3 100644 --- a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java +++ b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java @@ -47,11 +47,13 @@ import org.projectfloodlight.openflow.protocol.OFPacketOut; import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.types.EthType; import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.IpProtocol; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.VlanVid; import org.projectfloodlight.openflow.protocol.OFPacketInReason; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.match.MatchField; @@ -621,18 +623,18 @@ public class LoadBalancerTest extends FloodlightTestCase { MacAddress dataLayerDest2 = MacAddress.of("00:00:00:00:00:04"); IPv4Address networkDest2 = IPv4Address.of("10.0.0.4"); - deviceManager.learnEntity(dataLayerSource1.getLong(), - null, networkSource1.getInt(), - 1L, 1); - deviceManager.learnEntity(dataLayerSource2.getLong(), - null, networkSource2.getInt(), - 1L, 2); - deviceManager.learnEntity(dataLayerDest1.getLong(), - null, networkDest1.getInt(), - 1L, 3); - deviceManager.learnEntity(dataLayerDest2.getLong(), - null, networkDest2.getInt(), - 1L, 4); + deviceManager.learnEntity(dataLayerSource1, + VlanVid.ZERO, networkSource1, IPv6Address.NONE, + DatapathId.of(1), OFPort.of(1)); + deviceManager.learnEntity(dataLayerSource2, + VlanVid.ZERO, networkSource2, IPv6Address.NONE, + DatapathId.of(1), OFPort.of(2)); + deviceManager.learnEntity(dataLayerDest1, + VlanVid.ZERO, networkDest1, IPv6Address.NONE, + DatapathId.of(1), OFPort.of(3)); + deviceManager.learnEntity(dataLayerDest2, + VlanVid.ZERO, networkDest2, IPv6Address.NONE, + DatapathId.of(1), OFPort.of(4)); // in bound #1 Route route1 = new Route(DatapathId.of(1L), DatapathId.of(1L)); diff --git a/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java b/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java index 9a90fef2d53ecbe616e64c8f94f172c3998ebd56..3c07e937b3a309833f9e283b69a24441b952522a 100644 --- a/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java +++ b/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java @@ -32,9 +32,11 @@ import org.projectfloodlight.openflow.protocol.OFVersion; 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.ISyncService; import org.sdnplatform.sync.test.MockSyncService; @@ -357,8 +359,8 @@ public class VirtualNetworkFilterTest extends FloodlightTestCase { IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet)mac1ToGwPacketIntestPacket); - deviceService.learnEntity(((Ethernet)mac1ToGwPacketIntestPacket).getDestinationMACAddress().getLong(), - null, IPv4.toIPv4Address(gw1), null, null); + deviceService.learnEntity(((Ethernet)mac1ToGwPacketIntestPacket).getDestinationMACAddress(), + VlanVid.ZERO, IPv4Address.of(gw1), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO); Command ret = listener.receive(sw1, mac1ToGwPacketIn, cntx); assertTrue(ret == Command.CONTINUE); }