diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionBigSwitchVendor.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionBigSwitchVendor.java deleted file mode 100644 index 147820f479bea7596961e29225931f5856118648..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionBigSwitchVendor.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.action.OFActionVendor; - -public abstract class OFActionBigSwitchVendor extends OFActionVendor { - public static int MINIMUM_LENGTH = 12; - public static int BSN_VENDOR_ID = OFBigSwitchVendorData.BSN_VENDOR_ID; - - protected int subtype; - - protected OFActionBigSwitchVendor(int subtype) { - super(); - super.setLength((short)MINIMUM_LENGTH); - super.setVendor(BSN_VENDOR_ID); - this.subtype = subtype; - } - - public int getSubtype() { - return this.subtype; - } - - public void setSubtype(int subtype) { - this.subtype = subtype; - } - - @Override - public void readFrom(ChannelBuffer data) { - super.readFrom(data); - this.subtype = data.readInt(); - } - - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeInt(this.subtype); - } - - @Override - public int hashCode() { - final int prime = 379; - int result = super.hashCode(); - result = prime * result + vendor; - result = prime * result + subtype; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof OFActionBigSwitchVendor)) { - return false; - } - OFActionBigSwitchVendor other = (OFActionBigSwitchVendor) obj; - if (subtype != other.subtype) { - return false; - } - return true; - } - - @Override - public String toString() { - return super.toString() + "; subtype=" + subtype; - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionMirror.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionMirror.java deleted file mode 100644 index 3b55ca7201234a7d39f76db2416fc3ac1a1e1298..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionMirror.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; - - -public class OFActionMirror extends OFActionBigSwitchVendor { - public final static int MINIMUM_LENGTH = 12; - public final static int BSN_ACTION_MIRROR = 1; - - protected int destPort; - protected int vlanTag; - protected byte copyStage; - protected byte pad0; - protected byte pad1; - protected byte pad2; - - public OFActionMirror(short portNumber) { - super(BSN_ACTION_MIRROR); - super.setLength((short) (OFActionBigSwitchVendor.MINIMUM_LENGTH + OFActionMirror.MINIMUM_LENGTH)); - this.destPort = portNumber; - this.vlanTag = 0; - this.copyStage = 0; - } - - public int getDestPort() { - return destPort; - } - - public void setDestPort(int destPort) { - this.destPort = destPort; - } - - public int getVlanTag() { - return vlanTag; - } - - public void setVlanTag(int vlanTag) { - this.vlanTag = vlanTag; - } - - public byte getCopyStage() { - return copyStage; - } - - public void setCopyStage(byte copyStage) { - this.copyStage = copyStage; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + copyStage; - result = prime * result + destPort; - result = prime * result + pad0; - result = prime * result + pad1; - result = prime * result + pad2; - result = prime * result + vlanTag; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - OFActionMirror other = (OFActionMirror) obj; - if (copyStage != other.copyStage) return false; - if (destPort != other.destPort) return false; - if (pad0 != other.pad0) return false; - if (pad1 != other.pad1) return false; - if (pad2 != other.pad2) return false; - if (vlanTag != other.vlanTag) return false; - return true; - } - - @Override - public void readFrom(ChannelBuffer data) { - super.readFrom(data); - this.destPort = data.readInt(); - this.vlanTag = data.readInt(); - this.copyStage = data.readByte(); - this.pad0 = data.readByte(); - this.pad1 = data.readByte(); - this.pad2 = data.readByte(); - } - - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeInt(this.destPort); - data.writeInt(this.vlanTag); - data.writeByte(this.copyStage); - data.writeByte(this.pad0); - data.writeByte(this.pad1); - data.writeByte(this.pad2); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(type); - builder.append("["); - builder.append("BSN-MIRROR"); - builder.append(", Dest Port: "); - builder.append(destPort); - builder.append(", Vlan: "); - builder.append(vlanTag); - builder.append(", Copy Stage: "); - builder.append(copyStage); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrement.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrement.java deleted file mode 100644 index 51b829a815f5ee92e2972de55bfb1c94cee4a38a..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrement.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; - -public class OFActionNiciraTtlDecrement extends OFActionNiciraVendor { - public static int MINIMUM_LENGTH_TTL_DECREMENT = 16; - public static final short TTL_DECREMENT_SUBTYPE = 18; - - - public OFActionNiciraTtlDecrement() { - super(TTL_DECREMENT_SUBTYPE); - super.setLength((short)MINIMUM_LENGTH_TTL_DECREMENT); - } - - @Override - public void readFrom(ChannelBuffer data) { - super.readFrom(data); - data.skipBytes(6); // pad - } - - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeZero(6); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(type); - builder.append("["); - builder.append("NICIRA-TTL-DECR"); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraVendor.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraVendor.java deleted file mode 100644 index b4d9fa523baff8fb12150d2e5665300b7b4cd39a..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraVendor.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.action.OFActionVendor; -import org.openflow.vendor.nicira.OFNiciraVendorData; - -/** - * FIXME: this should really be handled by a consistent parse tree for - * different vendor actions but for the time being this works and gets the - * job done. - * - * @author gregor - * - */ -public class OFActionNiciraVendor extends OFActionVendor { - public static int MINIMUM_LENGTH = 16; - public static int NICIRA_VENDOR_ID = OFNiciraVendorData.NX_VENDOR_ID; - - protected short subtype; - - protected OFActionNiciraVendor(short subtype) { - // We don't allow direct instantiation of this class because its - // minimum length is 16 and the only way to guarantee this is by - // having a subclass that properly adds padding. - super(); - super.setLength((short)MINIMUM_LENGTH); - super.setVendor(NICIRA_VENDOR_ID); - this.subtype = subtype; - } - - public short getSubtype() { - return this.subtype; - } - - public void setSubtype(short subtype) { - this.subtype = subtype; - } - - @Override - public void readFrom(ChannelBuffer data) { - super.readFrom(data); - this.subtype = data.readShort(); - } - - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeShort(this.subtype); - } - - @Override - public int hashCode() { - final int prime = 379; - int result = super.hashCode(); - result = prime * result + vendor; - result = prime * result + subtype; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof OFActionNiciraVendor)) { - return false; - } - OFActionNiciraVendor other = (OFActionNiciraVendor) obj; - if (subtype != other.subtype) { - return false; - } - return true; - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIP.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIP.java deleted file mode 100644 index 9cd851c634178c22af5edd467712f51104e53e88..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIP.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import net.floodlightcontroller.core.web.serializers.IPv4Serializer; -import net.floodlightcontroller.packet.IPv4; - -import org.jboss.netty.buffer.ChannelBuffer; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -public class OFActionTunnelDstIP extends OFActionBigSwitchVendor { - public final static int MINIMUM_LENGTH_TUNNEL_DST = 16; - public final static int SET_TUNNEL_DST_SUBTYPE = 2; - - protected int dstIPAddr; - - public OFActionTunnelDstIP() { - super(SET_TUNNEL_DST_SUBTYPE); - super.setLength((short)MINIMUM_LENGTH_TUNNEL_DST); - } - - public OFActionTunnelDstIP(int dstIPAddr) { - this(); - this.dstIPAddr = dstIPAddr; - } - - @JsonSerialize(using=IPv4Serializer.class) - public int getTunnelDstIP() { - return this.dstIPAddr; - } - - public void setTunnelDstIP(int ipAddr) { - this.dstIPAddr = ipAddr; - } - - @Override - public void readFrom(ChannelBuffer data) { - super.readFrom(data); - this.dstIPAddr = data.readInt(); - } - - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeInt(this.dstIPAddr); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + dstIPAddr; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - OFActionTunnelDstIP other = (OFActionTunnelDstIP) obj; - if (dstIPAddr != other.dstIPAddr) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(type); - builder.append("["); - builder.append("BSN-SET-TUNNEL-DST-IP"); - builder.append(", IP: "); - builder.append(IPv4.fromIPv4Address(dstIPAddr)); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorActionFactory.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorActionFactory.java deleted file mode 100644 index 3b58cabf632df06fbbc187e3f8e0bdf14efa05cd..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorActionFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.action.OFActionVendor; -import org.openflow.protocol.factory.OFVendorActionFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OFBigSwitchVendorActionFactory implements OFVendorActionFactory { - protected static Logger logger = - LoggerFactory.getLogger(OFBigSwitchVendorActionFactory.class); - - static class OFActionBigSwitchVendorDemux extends OFActionBigSwitchVendor { - OFActionBigSwitchVendorDemux() { - super((short) 0); - } - } - - @Override - public OFActionVendor readFrom(ChannelBuffer data) { - data.markReaderIndex(); - OFActionBigSwitchVendor demux = new OFActionBigSwitchVendorDemux(); - demux.readFrom(data); - data.resetReaderIndex(); - - switch(demux.getSubtype()) { - case OFActionMirror.BSN_ACTION_MIRROR: - OFActionMirror mirrorAction = new OFActionMirror((short) 0); - mirrorAction.readFrom(data); - return mirrorAction; - case OFActionTunnelDstIP.SET_TUNNEL_DST_SUBTYPE: - OFActionTunnelDstIP tunnelAction = new OFActionTunnelDstIP(); - tunnelAction.readFrom(data); - return tunnelAction; - default: - logger.error("Unknown BSN vendor action subtype: "+demux.getSubtype()); - return null; - } - } - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorData.java deleted file mode 100644 index b5288f1381a5d5706a1813a4ff625fbcf94ffc3e..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorData.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.vendor.OFVendorData; - -/** - * Base class for vendor data corresponding to BigSwitch vendor extensions - * BigSwitch vendor data always starts with a 4-byte integer data type value - * - * @author Munish Mehta (munish.mehta@bigswitch.com) - */ -public class OFBigSwitchVendorData implements OFVendorData { - - public static final int BSN_VENDOR_ID = 0x005c16c7; - - /** - * The value of the integer data type at the beginning of the vendor data - */ - protected int dataType; - - /** - * Construct BigSwitch vendor data with the specified data type - * @param dataType : the data type value at the beginning (opcode) - */ - public OFBigSwitchVendorData(int dataType) { - super(); - this.dataType = dataType; - } - - /** - * Get the data type value at the beginning of the vendor data - * @return - */ - public int getDataType() { - return dataType; - } - - /** - * Set the data type value - * @param dataType - */ - public void setDataType(int dataType) { - this.dataType = dataType; - } - - /** - * Get the length of the vendor data. This implementation will normally be - * the superclass for another class that will override this to return the - * overall vendor data length. This implementation just returns the length - * of the part that includes the 4-byte integer data type value at the - * beginning of the vendor data - */ - @Override - public int getLength() { - return 4; - } - - /** - * Read the vendor data from the ChannelBuffer - * @param data the channel buffer from which we're deserializing - * @param length the length to the end of the enclosing message - */ - @Override - public void readFrom(ChannelBuffer data, int length) { - dataType = data.readInt(); - } - - /** - * Write the vendor data to the ChannelBuffer - * @param data the channel buffer to which we're serializing - */ - @Override - public void writeTo(ChannelBuffer data) { - data.writeInt(dataType); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + dataType; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - OFBigSwitchVendorData other = (OFBigSwitchVendorData) obj; - if (dataType != other.dataType) return false; - return true; - } - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorExtensions.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorExtensions.java deleted file mode 100644 index 0b3d069c4a1af871433509094f7a73e001fda17e..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorExtensions.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.vendor.OFBasicVendorDataType; -import org.openflow.protocol.vendor.OFBasicVendorId; -import org.openflow.protocol.vendor.OFVendorId; - -public class OFBigSwitchVendorExtensions { - private static boolean initialized = false; - - public static synchronized void initialize() { - if (initialized) - return; - - OFBasicVendorId bsnVendorId = - new OFBasicVendorId(OFBigSwitchVendorData.BSN_VENDOR_ID, 4); - OFVendorId.registerVendorId(bsnVendorId); - - // register data types used for big tap - OFBasicVendorDataType setEntryVendorData = - new OFBasicVendorDataType( - OFNetmaskSetVendorData.BSN_SET_IP_MASK_ENTRY, - OFNetmaskSetVendorData.getInstantiable()); - bsnVendorId.registerVendorDataType(setEntryVendorData); - - OFBasicVendorDataType getEntryVendorDataRequest = - new OFBasicVendorDataType( - OFNetmaskGetVendorDataRequest.BSN_GET_IP_MASK_ENTRY_REQUEST, - OFNetmaskGetVendorDataRequest.getInstantiable()); - bsnVendorId.registerVendorDataType(getEntryVendorDataRequest); - - OFBasicVendorDataType getEntryVendorDataReply = - new OFBasicVendorDataType( - OFNetmaskGetVendorDataReply.BSN_GET_IP_MASK_ENTRY_REPLY, - OFNetmaskGetVendorDataReply.getInstantiable()); - bsnVendorId.registerVendorDataType(getEntryVendorDataReply); - - // register data types used for tunneling - OFBasicVendorDataType getIntfIPVendorDataRequest = - new OFBasicVendorDataType( - OFInterfaceIPRequestVendorData.BSN_GET_INTERFACE_IP_REQUEST, - OFInterfaceIPRequestVendorData.getInstantiable()); - bsnVendorId.registerVendorDataType(getIntfIPVendorDataRequest); - - OFBasicVendorDataType getIntfIPVendorDataReply = - new OFBasicVendorDataType( - OFInterfaceIPReplyVendorData.BSN_GET_INTERFACE_IP_REPLY, - OFInterfaceIPReplyVendorData.getInstantiable()); - bsnVendorId.registerVendorDataType(getIntfIPVendorDataReply); - - - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableSetVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableSetVendorData.java deleted file mode 100644 index 3dd8310148e423889250a281ee240ef6e13f7f3c..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableSetVendorData.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - -public class OFBsnL2TableSetVendorData extends OFBsnL2TableVendorData { - - protected static Instantiable<OFVendorData> instantiableSingleton = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFBsnL2TableSetVendorData(); - } - }; - - public static final int BSN_L2_TABLE_SET = 12; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFBsnL2TableSetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiableSingleton; - } - - public OFBsnL2TableSetVendorData() { - super(BSN_L2_TABLE_SET); - } - - public OFBsnL2TableSetVendorData(boolean l2TableEnabled, - short l2TablePriority) { - super(BSN_L2_TABLE_SET, l2TableEnabled, l2TablePriority); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableVendorData.java deleted file mode 100644 index 14e6178d1b4793855b1b6ee8d0946c6f87fa79d0..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableVendorData.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; - -public class OFBsnL2TableVendorData extends OFBigSwitchVendorData { - /* - * uint8_t l2_table_enable; // 1 == enabled, 0 == disabled - * uint8_t pad; - * uint16_t l2_table_priority; // priority of all flows in L2 table - * uint8_t pad[4]; - */ - protected boolean l2TableEnabled; - protected short l2TablePriority; - - - public OFBsnL2TableVendorData(int dataType) { - super(dataType); - this.l2TableEnabled = false; - this.l2TablePriority = (short)0; - } - - - public OFBsnL2TableVendorData(int dataType, boolean l2TableEnabled, - short l2TablePriority) { - super(dataType); - this.l2TableEnabled = l2TableEnabled; - this.l2TablePriority = l2TablePriority; - } - - - public boolean isL2TableEnabled() { - return l2TableEnabled; - } - - - public short getL2TablePriority() { - return l2TablePriority; - } - - - public void setL2TableEnabled(boolean l2TableEnabled) { - this.l2TableEnabled = l2TableEnabled; - } - - - public void setL2TablePriority(short l2TablePriority) { - this.l2TablePriority = l2TablePriority; - } - - - @Override - public int getLength() { - return super.getLength() + 8; // 8 additional bytes - } - - /* - * (non-Javadoc) - * @see com.bigswitch.floodlight.vendor.OFBigSwitchVendorData#readFrom(org.jboss.netty.buffer.ChannelBuffer, int) - */ - @Override - public void readFrom(ChannelBuffer data, int length) { - super.readFrom(data, length); - l2TableEnabled = (data.readByte() == 0) ? false : true; - data.readByte(); // pad - l2TablePriority = data.readShort(); - data.readInt(); // 4 bad bytes - } - - /* - * (non-Javadoc) - * @see com.bigswitch.floodlight.vendor.OFBigSwitchVendorData#writeTo(org.jboss.netty.buffer.ChannelBuffer) - */ - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeByte(isL2TableEnabled() ? 1 : 0); - data.writeByte(0); // pad - data.writeShort(l2TablePriority); - data.writeInt(0); // 4 pad bytes - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnPktinSuppressionSetRequestVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBsnPktinSuppressionSetRequestVendorData.java deleted file mode 100644 index da5c33db03397b80d540c6d1c71f2f37e774ac3b..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnPktinSuppressionSetRequestVendorData.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - -public class OFBsnPktinSuppressionSetRequestVendorData - extends OFBigSwitchVendorData { - protected static Instantiable<OFVendorData> instantiableSingleton = - new Instantiable<OFVendorData>() { - @Override - public OFVendorData instantiate() { - return new OFBsnL2TableSetVendorData(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFBsnL2TableSetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiableSingleton; - } - - public static final int BSN_PKTIN_SUPPRESSION_SET_REQUEST = 11; - /* - * uint8_t enabled; // 0 to disable the extension, 1 to enable it - * uint8_t pad; - * uint16_t idle_timeout; // idle_timeout for new flows - * uint16_t hard_timeout; // idle_timeout for new flows - * uint16_t priority; // priority for new flows - * uint64_t cookie; // cookie for new flows - */ - - protected boolean suppressionEnabled; - protected short idleTimeout; - protected short hardTimeout; - protected short priority; - protected long cookie; - - public OFBsnPktinSuppressionSetRequestVendorData() { - super(BSN_PKTIN_SUPPRESSION_SET_REQUEST); - } - - public OFBsnPktinSuppressionSetRequestVendorData(boolean suppressionEnabled, - short idleTimeout, - short hardTimeout, - short priority, - long cookie) { - super(BSN_PKTIN_SUPPRESSION_SET_REQUEST); - this.suppressionEnabled = suppressionEnabled; - this.idleTimeout = idleTimeout; - this.hardTimeout = hardTimeout; - this.priority = priority; - this.cookie = cookie; - } - - public boolean isSuppressionEnabled() { - return suppressionEnabled; - } - - public short getIdleTimeout() { - return idleTimeout; - } - - public short getHardTimeout() { - return hardTimeout; - } - - public short getPriority() { - return priority; - } - - public long getCookie() { - return cookie; - } - - public void setSuppressionEnabled(boolean suppressionEnabled) { - this.suppressionEnabled = suppressionEnabled; - } - - public void setIdleTimeout(short idleTimeout) { - this.idleTimeout = idleTimeout; - } - - public void setHardTimeout(short hardTimeout) { - this.hardTimeout = hardTimeout; - } - - public void setPriority(short priority) { - this.priority = priority; - } - - public void setCookie(long cookie) { - this.cookie = cookie; - } - - @Override - public int getLength() { - return super.getLength() + 16; - } - - @Override - public void readFrom(ChannelBuffer data, int length) { - super.readFrom(data, length); - suppressionEnabled = (data.readByte() != 0); - data.readByte(); - idleTimeout = data.readShort(); - hardTimeout = data.readShort(); - priority = data.readShort(); - cookie = data.readLong(); - } - - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeByte(suppressionEnabled ? 1 : 0); - data.writeByte(0); // pad - data.writeShort(idleTimeout); - data.writeShort(hardTimeout); - data.writeShort(priority); - data.writeLong(cookie); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + (int) (cookie ^ (cookie >>> 32)); - result = prime * result + hardTimeout; - result = prime * result + idleTimeout; - result = prime * result + priority; - result = prime * result + (suppressionEnabled ? 1231 : 1237); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - OFBsnPktinSuppressionSetRequestVendorData other = (OFBsnPktinSuppressionSetRequestVendorData) obj; - if (cookie != other.cookie) return false; - if (hardTimeout != other.hardTimeout) return false; - if (idleTimeout != other.idleTimeout) return false; - if (priority != other.priority) return false; - if (suppressionEnabled != other.suppressionEnabled) return false; - return true; - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPReplyVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPReplyVendorData.java deleted file mode 100644 index 380ba43c299c7ccaaccafbdd846e92ea72a848ef..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPReplyVendorData.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import java.util.ArrayList; -import java.util.List; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - -public class OFInterfaceIPReplyVendorData extends OFBigSwitchVendorData { - - protected List<OFInterfaceVendorData> interfaces; - protected int length; - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFInterfaceIPReplyVendorData(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFInterfaceIPReplyVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to reply with IP addresses of all interfaces - */ - public static final int BSN_GET_INTERFACE_IP_REPLY = 10; - - /** - * Construct an interface IP reply vendor data - */ - public OFInterfaceIPReplyVendorData() { - super(BSN_GET_INTERFACE_IP_REPLY); - } - - /** - * @return the total length of the vendor-data part of the interface IP reply - * message. The OF header (8B) and vendor (4B) are taken care of by the - * OFVendor class MINIMUM_LENGTH. This method returns the length of the - * vendor-extension-subtype (4B) + the length of the interfaces - */ - @Override - public int getLength() { - return length; - } - - /** - * Set the length of this message - * - * @param length - */ - public void setLength(int length) { - this.length = length; - - } - - /** - * @return the interfaces - */ - public List<OFInterfaceVendorData> getInterfaces() { - return interfaces; - } - - /** - * @param intfs the ones to set - */ - public void setInterfaces(List<OFInterfaceVendorData> intfs) { - this.interfaces = intfs; - if (intfs == null) { - this.setLength(super.getLength()); - } else { - this.setLength(super.getLength() + intfs.size() - * OFInterfaceVendorData.MINIMUM_LENGTH); - } - } - - /** - * Read from the ChannelBuffer - * @param data the channel buffer from which we're deserializing - * @param length the length to the end of the enclosing message - */ - @Override - public void readFrom(ChannelBuffer data, int length) { - //datatype read by super class - super.readFrom(data, length); - - if (this.interfaces == null) { - this.interfaces = new ArrayList<OFInterfaceVendorData>(); - } else { - this.interfaces.clear(); - } - int intfCount = (length - 4) - / OFInterfaceVendorData.MINIMUM_LENGTH; - - OFInterfaceVendorData intf; - for (int i = 0; i < intfCount; ++i) { - intf = new OFInterfaceVendorData(); - intf.readFrom(data); - this.interfaces.add(intf); - } - } - - /** - * Write to the ChannelBuffer - * @param data the channel buffer to which we're serializing - */ - @Override - public void writeTo(ChannelBuffer data) { - // datatype written by super class - super.writeTo(data); - if (this.interfaces != null) { - for (OFInterfaceVendorData intf : this.interfaces) { - intf.writeTo(data); - } - } - } - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPRequestVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPRequestVendorData.java deleted file mode 100644 index 9caf6e54ad299e488b217722941d7b4ae057fc72..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPRequestVendorData.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - -public class OFInterfaceIPRequestVendorData extends OFBigSwitchVendorData { - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFInterfaceIPRequestVendorData(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFInterfaceIPRequestVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to request IP addresses of all interfaces - */ - public static final int BSN_GET_INTERFACE_IP_REQUEST = 9; - - /** - * Construct an interface IP request vendor data - */ - public OFInterfaceIPRequestVendorData() { - super(BSN_GET_INTERFACE_IP_REQUEST); - } - - /** - * @return the total length of the interface IP request message - * the length is already accounted for in the super class - */ - @Override - public int getLength() { - return super.getLength(); - } - - /** - * Read from the ChannelBuffer - * @param data the channel buffer from which we're deserializing - * @param length the length to the end of the enclosing message - */ - @Override - public void readFrom(ChannelBuffer data, int length) { - super.readFrom(data, length); - } - - /** - * Write to the ChannelBuffer - * @param data the channel buffer to which we're serializing - */ - @Override - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - } - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceVendorData.java deleted file mode 100644 index 0b6f30de4c677b5c694fb2037b759462c1827c29..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceVendorData.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.Arrays; - -import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import org.jboss.netty.buffer.ChannelBuffer; - -public class OFInterfaceVendorData { - public static int MINIMUM_LENGTH = 32; - private static int OFP_ETH_ALEN = 6; - private static int OFP_MAX_PORT_NAME_LEN = 16; - - protected byte[] hardwareAddress; - protected String name; - protected int ipv4Addr; - protected int ipv4AddrMask; - - /** - * @return the hardwareAddress - */ - @JsonSerialize(using=ByteArrayMACSerializer.class) - public byte[] getHardwareAddress() { - return hardwareAddress; - } - - /** - * @param hardwareAddress the hardwareAddress to set - */ - public void setHardwareAddress(byte[] hardwareAddress) { - if (hardwareAddress.length != OFP_ETH_ALEN) - throw new RuntimeException("Hardware address must have length " - + OFP_ETH_ALEN); - this.hardwareAddress = hardwareAddress; - } - - public int getIpv4Addr() { - return ipv4Addr; - } - - public void setIpv4Addr(int ipv4Addr) { - this.ipv4Addr = ipv4Addr; - } - - public int getIpv4AddrMask() { - return ipv4AddrMask; - } - - public void setIpv4AddrMask(int ipv4AddrMask) { - this.ipv4AddrMask = ipv4AddrMask; - } - - /** - * @return the name - */ - public String getName() { - return name; - } - - /** - * @param name the name to set - */ - public void setName(String name) { - this.name = name; - } - - /** - * Write this message's binary format to the specified ByteBuffer - * @param data - */ - public void writeTo(ChannelBuffer data) { - data.writeBytes(hardwareAddress); - data.writeBytes(new byte[] {0, 0}); - - try { - byte[] name = this.name.getBytes("ASCII"); - if (name.length < OFP_MAX_PORT_NAME_LEN) { - data.writeBytes(name); - for (int i = name.length; i < OFP_MAX_PORT_NAME_LEN; ++i) { - data.writeByte((byte) 0); - } - } else { - data.writeBytes(name, 0, 15); - data.writeByte((byte) 0); - } - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - - data.writeInt(ipv4Addr); - data.writeInt(ipv4AddrMask); - } - - /** - * Read this message off the wire from the specified ByteBuffer - * @param data - */ - public void readFrom(ChannelBuffer data) { - if (this.hardwareAddress == null) - this.hardwareAddress = new byte[OFP_ETH_ALEN]; - data.readBytes(this.hardwareAddress); - data.readBytes(new byte[2]); - - byte[] name = new byte[16]; - data.readBytes(name); - // find the first index of 0 - int index = 0; - for (byte b : name) { - if (0 == b) - break; - ++index; - } - this.name = new String(Arrays.copyOf(name, index), - Charset.forName("ascii")); - ipv4Addr = data.readInt(); - ipv4AddrMask = data.readInt(); - } - - -} \ No newline at end of file diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataReply.java b/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataReply.java deleted file mode 100644 index d8d83b404eb8b3a31d369e3e49fb9a15ed3760c6..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataReply.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - - -/** - * Subclass of OFVendorData - */ -public class OFMirrorGetVendorDataReply extends OFNetmaskVendorData { - - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFMirrorGetVendorDataReply(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFNetmaskGetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to represent REPLY of GET_MASK request - */ - public static final int BSN_GET_MIRRORING_REPLY = 5; - - /** - * Construct a get network mask vendor data - */ - public OFMirrorGetVendorDataReply() { - super(BSN_GET_MIRRORING_REPLY); - } - - /** - * Construct a get network mask vendor data for a specific table entry - */ - public OFMirrorGetVendorDataReply(byte tableIndex, int netMask) { - super(BSN_GET_MIRRORING_REPLY, tableIndex, netMask); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataRequest.java b/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataRequest.java deleted file mode 100644 index 6692cdfdde002140a87256f62cdb8cfa7a26f52d..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataRequest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - - -/** - * Subclass of OFVendorData - */ -public class OFMirrorGetVendorDataRequest extends OFNetmaskVendorData { - - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFMirrorGetVendorDataRequest(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFNetmaskGetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to request an entry in the switch netmask table - */ - public static final int BSN_GET_MIRRORING_REQUEST = 4; - - /** - * Construct a get network mask vendor data - */ - public OFMirrorGetVendorDataRequest() { - super(BSN_GET_MIRRORING_REQUEST); - } - - /** - * Construct a get network mask vendor data for a specific table entry - */ - public OFMirrorGetVendorDataRequest(byte tableIndex, int netMask) { - super(BSN_GET_MIRRORING_REQUEST, tableIndex, netMask); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorSetVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorSetVendorData.java deleted file mode 100644 index 5eba6512b7c4f07f9087aabe4f52e5cd0e300bee..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorSetVendorData.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; - -public class OFMirrorSetVendorData extends OFBigSwitchVendorData { - - /** - * Opcode/dataType to set mirroring - */ - public static final int BSN_SET_MIRRORING = 3; - - protected byte reportMirrorPorts; - protected byte pad1; - protected byte pad2; - protected byte pad3; - - public OFMirrorSetVendorData() { - super(BSN_SET_MIRRORING); - this.reportMirrorPorts=1; - } - - public byte getReportMirrorPorts() { - return reportMirrorPorts; - } - - public void setReportMirrorPorts(byte report) { - this.reportMirrorPorts = report; - } - - /** - * @return the total length vendor date - */ - @Override - public int getLength() { - return super.getLength() + 4; // 4 extra bytes - } - - /** - * Read the vendor data from the channel buffer - * @param data: the channel buffer from which we are deserializing - * @param length: the length to the end of the enclosing message - */ - public void readFrom(ChannelBuffer data, int length) { - super.readFrom(data, length); - reportMirrorPorts = data.readByte(); - pad1 = data.readByte(); - pad2 = data.readByte(); - pad3 = data.readByte(); - } - - /** - * Write the vendor data to the channel buffer - */ - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeByte(reportMirrorPorts); - data.writeByte(pad1); - data.writeByte(pad2); - data.writeByte(pad3); - } - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataReply.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataReply.java deleted file mode 100644 index 62d711020b71f8c962ff2fd068451acb3d9f9ab7..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataReply.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - - -/** - * Subclass of OFVendorData - * - * @author munish_mehta - */ -public class OFNetmaskGetVendorDataReply extends OFNetmaskVendorData { - - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFNetmaskGetVendorDataReply(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFNetmaskGetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to represent REPLY of GET_MASK request - */ - public static final int BSN_GET_IP_MASK_ENTRY_REPLY = 2; - - /** - * Construct a get network mask vendor data - */ - public OFNetmaskGetVendorDataReply() { - super(BSN_GET_IP_MASK_ENTRY_REPLY); - } - - /** - * Construct a get network mask vendor data for a specific table entry - */ - public OFNetmaskGetVendorDataReply(byte tableIndex, int netMask) { - super(BSN_GET_IP_MASK_ENTRY_REPLY, tableIndex, netMask); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataRequest.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataRequest.java deleted file mode 100644 index 1d075e9a3b9a87584f92b6ad7ea04442457f5ac9..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataRequest.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - - -/** - * Subclass of OFVendorData - * - * @author munish_mehta - */ -public class OFNetmaskGetVendorDataRequest extends OFNetmaskVendorData { - - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFNetmaskGetVendorDataRequest(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFNetmaskGetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to request an entry in the switch netmask table - */ - public static final int BSN_GET_IP_MASK_ENTRY_REQUEST = 1; - - /** - * Construct a get network mask vendor data - */ - public OFNetmaskGetVendorDataRequest() { - super(BSN_GET_IP_MASK_ENTRY_REQUEST); - } - - /** - * Construct a get network mask vendor data for a specific table entry - */ - public OFNetmaskGetVendorDataRequest(byte tableIndex, int netMask) { - super(BSN_GET_IP_MASK_ENTRY_REQUEST, tableIndex, netMask); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskSetVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskSetVendorData.java deleted file mode 100644 index 54421c10334acb5d7ca793c699f5005977a3a873..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskSetVendorData.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.Instantiable; -import org.openflow.protocol.vendor.OFVendorData; - -public class OFNetmaskSetVendorData extends OFNetmaskVendorData { - - - protected static Instantiable<OFVendorData> instantiable = - new Instantiable<OFVendorData>() { - public OFVendorData instantiate() { - return new OFNetmaskSetVendorData(); - } - }; - - /** - * @return a subclass of Instantiable<OFVendorData> that instantiates - * an instance of OFNetmaskSetVendorData. - */ - public static Instantiable<OFVendorData> getInstantiable() { - return instantiable; - } - - /** - * Opcode/dataType to set an entry in the switch netmask table - */ - public static final int BSN_SET_IP_MASK_ENTRY = 0; - - /** - * Construct a get network mask vendor data - */ - public OFNetmaskSetVendorData() { - super(BSN_SET_IP_MASK_ENTRY); - } - - /** - * Construct a get network mask vendor data for a specific table entry - */ - public OFNetmaskSetVendorData(byte tableIndex, int netMask) { - super(BSN_SET_IP_MASK_ENTRY, tableIndex, netMask); - } -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskVendorData.java deleted file mode 100644 index 66539f98e757e8b133eaf04c115557fad8904ebd..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskVendorData.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; - - -/** - * Class that represents the vendor data in the netmask table request - * extension implemented by Arista switches - * - * @author munish_mehta (munish.mehta@bigswitch.com) - */ - -public class OFNetmaskVendorData extends OFBigSwitchVendorData { - - /** - * Table index for set or get of the the entry from netmask table - */ - protected byte tableIndex; - protected byte pad1; - protected byte pad2; - protected byte pad3; - protected int netMask; - - public OFNetmaskVendorData(int dataType) { - super(dataType); - this.tableIndex = 0; - this.netMask = (int)0xffffffffL; - } - - public OFNetmaskVendorData(int dataType, byte table_index, int netmask) { - super(dataType); - this.tableIndex = table_index; - this.netMask = netmask; - } - - - public byte getTableIndex() { - return tableIndex; - } - - public void setTableIndex(byte tableIndex) { - this.tableIndex = tableIndex; - } - - public int getNetMask() { - return netMask; - } - - public void setNetMask(int netMask) { - this.netMask = netMask; - } - - /** - * @return the total length of the netmask vendor data - */ - @Override - public int getLength() { - return super.getLength() + 8; // 8 extra bytes - } - - /** - * Read the vendor data from the channel buffer - * @param data: the channel buffer from which we are deserializing - * @param length: the length to the end of the enclosing message - */ - public void readFrom(ChannelBuffer data, int length) { - super.readFrom(data, length); - tableIndex = data.readByte(); - pad1 = data.readByte(); - pad2 = data.readByte(); - pad3 = data.readByte(); - netMask = data.readInt(); - } - - /** - * Write the vendor data to the channel buffer - */ - public void writeTo(ChannelBuffer data) { - super.writeTo(data); - data.writeByte(tableIndex); - data.writeByte(pad1); - data.writeByte(pad2); - data.writeByte(pad3); - data.writeInt(netMask); - } - - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNiciraVendorActionFactory.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNiciraVendorActionFactory.java deleted file mode 100644 index 716373794f263aa3db5a60d316d982f7ce668a5f..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFNiciraVendorActionFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.openflow.protocol.action.OFActionVendor; -import org.openflow.protocol.factory.OFVendorActionFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OFNiciraVendorActionFactory implements OFVendorActionFactory { - protected static Logger logger = - LoggerFactory.getLogger(OFNiciraVendorActionFactory.class); - - static class OFActionNiciraVendorDemux extends OFActionNiciraVendor { - OFActionNiciraVendorDemux() { - super((short) 0); - } - } - - @Override - public OFActionVendor readFrom(ChannelBuffer data) { - data.markReaderIndex(); - OFActionNiciraVendorDemux demux = new OFActionNiciraVendorDemux(); - demux.readFrom(data); - data.resetReaderIndex(); - - switch(demux.getSubtype()) { - case OFActionNiciraTtlDecrement.TTL_DECREMENT_SUBTYPE: - OFActionNiciraTtlDecrement ttlAction = new OFActionNiciraTtlDecrement(); - ttlAction.readFrom(data); - return ttlAction; - default: - logger.error("Unknown Nicira vendor action subtype: "+demux.getSubtype()); - return null; - } - } - -} diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFVendorActions.java b/src/main/java/com/bigswitch/floodlight/vendor/OFVendorActions.java deleted file mode 100644 index 0b555340cea7abe3364d1c05b7feaa7be0b3ff0d..0000000000000000000000000000000000000000 --- a/src/main/java/com/bigswitch/floodlight/vendor/OFVendorActions.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.bigswitch.floodlight.vendor; - -import org.openflow.protocol.factory.OFVendorActionRegistry; - -public final class OFVendorActions { - public static final void registerStandardVendorActions() { - OFVendorActionRegistry registry = OFVendorActionRegistry.getInstance(); - registry.register(OFActionBigSwitchVendor.BSN_VENDOR_ID, new OFBigSwitchVendorActionFactory()); - registry.register(OFActionNiciraVendor.NICIRA_VENDOR_ID, new OFNiciraVendorActionFactory()); - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java index ce3e1786f90660064f7cc0e8e0ed6b634670ce5d..c91e55fc1720c5e36307cfb108084fe9f156da0e 100644 --- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java +++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java @@ -54,7 +54,7 @@ public interface IFloodlightProviderService extends * representation of the payload of a packet-in message. */ public static final String CONTEXT_PI_PAYLOAD = - "org.projectfloodlight.core.IFloodlightProvider.piPayload"; + "net.floodlightcontroller.core.IFloodlightProvider.piPayload"; /** * A FloodlightContextStore object that can be used to retrieve the diff --git a/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java b/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java deleted file mode 100644 index 9a0348767c6d7b952cb9496169d3477b180d6865..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java +++ /dev/null @@ -1,532 +0,0 @@ -/** - * 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.core; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; - -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.projectfloodlight.openflow.protocol.OFFlowMod; -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFPacketOut; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.util.HexString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.ArrayList; -import org.apache.thrift.TException; -import org.apache.thrift.transport.TFramedTransport; -import org.apache.thrift.transport.TTransport; -import org.apache.thrift.transport.TSocket; -import org.apache.thrift.protocol.TBinaryProtocol; -import org.apache.thrift.protocol.TProtocol; - -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packetstreamer.thrift.*; -import net.floodlightcontroller.threadpool.IThreadPoolService; - -@LogMessageCategory("OpenFlow Message Tracing") -public class OFMessageFilterManager - implements IOFMessageListener, IFloodlightModule, IOFMessageFilterManagerService { - - /** - * @author Srini - */ - protected static Logger log = LoggerFactory.getLogger(OFMessageFilterManager.class); - - // The port and client reference for packet streaming - protected int serverPort = 9090; - protected final int MaxRetry = 1; - protected static volatile TTransport transport = null; - protected static volatile PacketStreamer.Client packetClient = null; - - protected IFloodlightProviderService floodlightProvider = null; - protected IThreadPoolService threadPool = null; - // filter List is a key value pair. Key is the session id, - // value is the filter rules. - protected ConcurrentHashMap<String, - ConcurrentHashMap<String, - String>> filterMap = null; - protected ConcurrentHashMap<String, Long> filterTimeoutMap = null; - protected Timer timer = null; - - protected int MAX_FILTERS=5; - protected long MAX_FILTER_TIME= 300000; // maximum filter time is 5 minutes. - protected int TIMER_INTERVAL = 1000; // 1 second time interval. - - public static final String SUCCESS = "0"; - public static final String FILTER_SETUP_FAILED = "-1001"; - public static final String FILTER_NOT_FOUND = "-1002"; - public static final String FILTER_LIMIT_REACHED = "-1003"; - public static final String FILTER_SESSION_ID_NOT_FOUND = "-1004"; - public static final String SERVICE_UNAVAILABLE = "-1005"; - - public enum FilterResult { - /* - * FILTER_NOT_DEFINED: Filter is not defined - * FILTER_NO_MATCH: Filter is defined and the packet doesn't - * match the filter - * FILTER_MATCH: Filter is defined and the packet matches - * the filter - */ - FILTER_NOT_DEFINED, FILTER_NO_MATCH, FILTER_MATCH - } - - protected String addFilter(ConcurrentHashMap<String,String> f, long delta) { - - // Create unique session ID. - int prime = 33791; - String s = null; - int i; - - if ((filterMap == null) || (filterTimeoutMap == null)) - return String.format("%s", FILTER_SETUP_FAILED); - - for (i=0; i<MAX_FILTERS; ++i) { - Integer x = prime + i; - s = String.format("%d", x.hashCode()); - // implies you can use this key for session id. - if (!filterMap.containsKey(s)) break; - } - - if (i==MAX_FILTERS) { - return FILTER_LIMIT_REACHED; - } - - filterMap.put(s, f); - if (filterTimeoutMap.containsKey(s)) filterTimeoutMap.remove(s); - filterTimeoutMap.put(s, delta); - - // set the timer as there will be no existing timers. - if (filterMap.size() == 1) { - TimeoutFilterTask task = new TimeoutFilterTask(this); - Timer timer = new Timer(); - timer.schedule (task, TIMER_INTERVAL); - // Keep the listeners to avoid race condition - //startListening(); - } - return s; // the return string is the session ID. - } - - @Override - public String setupFilter(String sid, - ConcurrentHashMap<String,String> f, - int deltaInMilliSeconds) { - - if (sid == null) { - // Delta in filter needs to be milliseconds - log.debug("Adding new filter: {} for {} ms", f, deltaInMilliSeconds); - return addFilter(f, deltaInMilliSeconds); - } else {// this is the session id. - // we will ignore the hash map features. - if (deltaInMilliSeconds > 0) - return refreshFilter(sid, deltaInMilliSeconds); - else - return deleteFilter(sid); - } - } - - public int timeoutFilters() { - Iterator<String> i = filterTimeoutMap.keySet().iterator(); - - while(i.hasNext()) { - String s = i.next(); - - Long t = filterTimeoutMap.get(s); - if (t != null) { - i.remove(); - t -= TIMER_INTERVAL; - if (t > 0) { - filterTimeoutMap.put(s, t); - } else deleteFilter(s); - } else deleteFilter(s); - } - return filterMap.size(); - } - - protected String refreshFilter(String s, int delta) { - Long t = filterTimeoutMap.get(s); - if (t != null) { - filterTimeoutMap.remove(s); - t += delta; // time is in milliseconds - if (t > MAX_FILTER_TIME) t = MAX_FILTER_TIME; - filterTimeoutMap.put(s, t); - return SUCCESS; - } else return FILTER_SESSION_ID_NOT_FOUND; - } - - @LogMessageDoc(level="ERROR", - message="Error while terminating packet " + - "filter session", - explanation="An unknown error occurred while terminating " + - "a packet filter session.", - recommendation=LogMessageDoc.GENERIC_ACTION) - protected String deleteFilter(String sessionId) { - - if (filterMap.containsKey(sessionId)) { - filterMap.remove(sessionId); - try { - if (packetClient != null) - packetClient.terminateSession(sessionId); - } catch (TException e) { - log.error("Error while terminating packet " + - "filter session", e); - } - log.debug("Deleted Filter {}. # of filters" + - " remaining: {}", sessionId, filterMap.size()); - return SUCCESS; - } else return FILTER_SESSION_ID_NOT_FOUND; - } - - public HashSet<String> getMatchedFilters(OFMessage m, FloodlightContext cntx) { - - HashSet<String> matchedFilters = new HashSet<String>(); - - // This default function is written to match on packet ins and - // packet outs. - Ethernet eth = null; - - if (m.getType() == OFType.PACKET_IN) { - eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - } else if (m.getType() == OFType.PACKET_OUT) { - eth = new Ethernet(); - OFPacketOut p = (OFPacketOut) m; - - // No MAC match if packetOut doesn't have the packet. - if (p.getData() == null) return null; - - eth.deserialize(p.getData(), 0, p.getData().length); - } else if (m.getType() == OFType.FLOW_MOD) { - // flow-mod can't be matched by mac. - return null; - } - - if (eth == null) return null; - - Iterator<String> filterIt = filterMap.keySet().iterator(); - while (filterIt.hasNext()) { // for every filter - boolean filterMatch = false; - String filterSessionId = filterIt.next(); - Map<String,String> filter = filterMap.get(filterSessionId); - - // If the filter has empty fields, then it is not considered as a match. - if (filter == null || filter.isEmpty()) continue; - Iterator<String> fieldIt = filter.keySet().iterator(); - while (fieldIt.hasNext()) { - String filterFieldType = fieldIt.next(); - String filterFieldValue = filter.get(filterFieldType); - if (filterFieldType.equals("mac")) { - - String srcMac = HexString.toHexString(eth.getSourceMACAddress()); - String dstMac = HexString.toHexString(eth.getDestinationMACAddress()); - log.debug("srcMac: {}, dstMac: {}", srcMac, dstMac); - - if (filterFieldValue.equals(srcMac) || - filterFieldValue.equals(dstMac)){ - filterMatch = true; - } else { - filterMatch = false; - break; - } - } - } - if (filterMatch) { - matchedFilters.add(filterSessionId); - } - } - - if (matchedFilters.isEmpty()) - return null; - else - return matchedFilters; - } - - @LogMessageDoc(level="ERROR", - message="Failed to establish connection with the " + - "packetstreamer server.", - explanation="The message tracing server is not running " + - "or otherwise unavailable.", - recommendation=LogMessageDoc.CHECK_CONTROLLER) - public boolean connectToPSServer() { - int numRetries = 0; - if (transport != null && transport.isOpen()) { - return true; - } - - while (numRetries++ < MaxRetry) { - try { - TFramedTransport t = - new TFramedTransport(new TSocket("localhost", - serverPort)); - t.open(); - - TProtocol protocol = new TBinaryProtocol(t); - packetClient = new PacketStreamer.Client(protocol); - - log.debug("Have a connection to packetstreamer server " + - "localhost:{}", serverPort); - transport = t; - break; - } catch (TException x) { - try { - // Wait for 1 second before retry - if (numRetries < MaxRetry) { - Thread.sleep(1000); - } - } catch (Exception e) {} - } - } - - if (numRetries > MaxRetry) { - log.error("Failed to establish connection with the " + - "packetstreamer server."); - return false; - } - return true; - } - - public void disconnectFromPSServer() { - if (transport != null && transport.isOpen()) { - log.debug("Close the connection to packetstreamer server" + - " localhost:{}", serverPort); - transport.close(); - } - } - - @Override - public String getName() { - return "messageFilterManager"; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return (type == OFType.PACKET_IN && name.equals("devicemanager")); - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return (type == OFType.PACKET_IN && name.equals("learningswitch")); - } - - @Override - @LogMessageDoc(level="ERROR", - message="Error while sending packet", - explanation="Failed to send a message to the message " + - "tracing server", - recommendation=LogMessageDoc.CHECK_CONTROLLER) - public Command receive(IOFSwitch sw, OFMessage msg, - FloodlightContext cntx) { - - if (filterMap == null || filterMap.isEmpty()) return Command.CONTINUE; - - HashSet<String> matchedFilters = null; - if (log.isDebugEnabled()) { - log.debug("Received packet {} from switch {}", - msg, sw.getStringId()); - } - - matchedFilters = getMatchedFilters(msg, cntx); - if (matchedFilters == null) { - return Command.CONTINUE; - } else { - try { - sendPacket(matchedFilters, sw, msg, cntx, true); - } catch (Exception e) { - log.error("Error while sending packet", e); - } - } - - return Command.CONTINUE; - } - - - public class TimeoutFilterTask extends TimerTask { - - OFMessageFilterManager filterManager; - ScheduledExecutorService ses = threadPool.getScheduledExecutor(); - - public TimeoutFilterTask(OFMessageFilterManager manager) { - filterManager = manager; - } - - public void run() { - int x = filterManager.timeoutFilters(); - - if (x > 0) { // there's at least one filter still active. - Timer timer = new Timer(); - timer.schedule(new TimeoutFilterTask(filterManager), - TIMER_INTERVAL); - } else { - // Don't stop the listener to avoid race condition - //stopListening(); - } - } - } - - public int getNumberOfFilters() { - return filterMap.size(); - } - - public int getMaxFilterSize() { - return MAX_FILTERS; - } - - protected void sendPacket(HashSet<String> matchedFilters, IOFSwitch sw, - OFMessage msg, FloodlightContext cntx, boolean sync) - throws TException { - Message sendMsg = new Message(); - Packet packet = new Packet(); - ChannelBuffer bb; - sendMsg.setPacket(packet); - - List<String> sids = new ArrayList<String>(matchedFilters); - - sendMsg.setSessionIDs(sids); - packet.setMessageType(OFMessageType.findByValue((msg.getType().ordinal()))); - - switch (msg.getType()) { - case PACKET_IN: - OFPacketIn pktIn = (OFPacketIn)msg; - packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), - pktIn.getInPort())); - bb = ChannelBuffers.buffer(pktIn.getLength()); - pktIn.writeTo(bb); - packet.setData(OFMessage.getData(sw, msg, cntx)); - break; - case PACKET_OUT: - OFPacketOut pktOut = (OFPacketOut)msg; - packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), - pktOut.getInPort())); - bb = ChannelBuffers.buffer(pktOut.getLength()); - pktOut.writeTo(bb); - packet.setData(OFMessage.getData(sw, msg, cntx)); - break; - case FLOW_MOD: - OFFlowMod offlowMod = (OFFlowMod)msg; - packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), - offlowMod. - getOutPort())); - bb = ChannelBuffers.buffer(offlowMod.getLength()); - offlowMod.writeTo(bb); - packet.setData(OFMessage.getData(sw, msg, cntx)); - break; - default: - packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), - (short)0)); - String strData = "Unknown packet"; - packet.setData(strData.getBytes()); - break; - } - - try { - if (transport == null || - !transport.isOpen() || - packetClient == null) { - if (!connectToPSServer()) { - // No need to sendPacket if can't make connection to - // the server - return; - } - } - if (sync) { - log.debug("Send packet sync: {}", packet.toString()); - packetClient.pushMessageSync(sendMsg); - } else { - log.debug("Send packet sync: ", packet.toString()); - packetClient.pushMessageAsync(sendMsg); - } - } catch (Exception e) { - log.error("Error while sending packet", e); - disconnectFromPSServer(); - connectToPSServer(); - } - } - - // IFloodlightModule methods - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IOFMessageFilterManagerService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - // We are the class that implements the service - m.put(IOFMessageFilterManagerService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IThreadPoolService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - this.floodlightProvider = - context.getServiceImpl(IFloodlightProviderService.class); - this.threadPool = - context.getServiceImpl(IThreadPoolService.class); - } - - @Override - public void startUp(FloodlightModuleContext context) { - // This is our 'constructor' - - filterMap = new ConcurrentHashMap<String, ConcurrentHashMap<String,String>>(); - filterTimeoutMap = new ConcurrentHashMap<String, Long>(); - serverPort = - Integer.parseInt(System.getProperty("net.floodlightcontroller." + - "packetstreamer.port", "9090")); - - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - floodlightProvider.addOFMessageListener(OFType.PACKET_OUT, this); - floodlightProvider.addOFMessageListener(OFType.FLOW_MOD, this); - } -} diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitch.java b/src/main/java/net/floodlightcontroller/core/OFSwitch.java index 38b5ddaa6b2bb7a49a3a31deadb1b21cd2719a94..4a09ac480c60d96396bfcedf41fb4ce2996cbb5f 100644 --- a/src/main/java/net/floodlightcontroller/core/OFSwitch.java +++ b/src/main/java/net/floodlightcontroller/core/OFSwitch.java @@ -52,6 +52,7 @@ import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFeaturesReply; import org.projectfloodlight.openflow.protocol.OFFlowWildcards; import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFPortConfig; import org.projectfloodlight.openflow.protocol.OFPortDesc; import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply; import org.projectfloodlight.openflow.protocol.OFPortReason; @@ -235,7 +236,8 @@ public class OFSwitch implements IOFSwitchBackend { for(OFPortDesc p: newPortsByNumber.values()) { newPortList.add(p); newPortsByName.put(p.getName().toLowerCase(), p); - if (p.getState().contains(OFPortState.LIVE)) { + if (!p.getState().contains(OFPortState.LINK_DOWN) + && !p.getConfig().contains(OFPortConfig.PORT_DOWN)) { newEnabledPortList.add(p); newEnabledPortNumbers.add(p.getPortNo()); } @@ -409,10 +411,16 @@ public class OFSwitch implements IOFSwitchBackend { // A simple modify of a exiting port // A previous port with this number exists and it's name // also matches the new port. Find the differences - if (prevPort.getState().contains(OFPortState.LIVE) && !newPort.getState().contains(OFPortState.LIVE)) { + if ((!prevPort.getState().contains(OFPortState.LINK_DOWN) + && !prevPort.getConfig().contains(OFPortConfig.PORT_DOWN)) + && (newPort.getState().contains(OFPortState.LINK_DOWN) + || newPort.getConfig().contains(OFPortConfig.PORT_DOWN))) { events.add(new PortChangeEvent(newPort, PortChangeType.DOWN)); - } else if (!prevPort.getState().contains(OFPortState.LIVE) && newPort.getState().contains(OFPortState.LIVE)) { + } else if ((prevPort.getState().contains(OFPortState.LINK_DOWN) + || prevPort.getConfig().contains(OFPortConfig.PORT_DOWN)) + && (!newPort.getState().contains(OFPortState.LINK_DOWN) + && !newPort.getConfig().contains(OFPortConfig.PORT_DOWN))) { events.add(new PortChangeEvent(newPort, PortChangeType.UP)); } else { @@ -455,7 +463,7 @@ public class OFSwitch implements IOFSwitchBackend { /** * Compare the current ports of this switch to the newPorts list and - * return the changes that would be applied to transfort the current + * return the changes that would be applied to transform the current * ports to the new ports. No internal data structures are updated * see {@link #compareAndUpdatePorts(List, boolean)} * @@ -553,7 +561,10 @@ public class OFSwitch implements IOFSwitchBackend { String.format("%s (%d)", duplicatePort.getName(), duplicatePort.getPortNo().getPortNumber())); throw new IllegalArgumentException(msg); } - if (p.getState().contains(OFPortState.LIVE)) { + //TODO @Ryan How to handle port state? + // Enabled = not down admin (config) or phys (state) + if (!p.getConfig().contains(OFPortConfig.PORT_DOWN) + && !p.getState().contains(OFPortState.LINK_DOWN)) { newEnabledPortList.add(p); newEnabledPortNumbers.add(p.getPortNo()); } diff --git a/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java b/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java index cca90d3a35d8c1988c00f69282be51e8d123d65c..557d8417db5dadb117202fd75fad0cab02efdba2 100644 --- a/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java +++ b/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java @@ -49,6 +49,6 @@ public class PortChangeEvent { */ @Override public String toString() { - return "[" + type + " " + String.format("%s (%d)", port.getName(), port.getPortNo()) + "]"; + return "[" + type + " " + String.format("%s (%d)", port.getName(), port.getPortNo().getPortNumber()) + "]"; } } \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java b/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java index e22640a91f07b81fe1dba80dd4c81052d4e65610..972321f62e1f2323c5916340d96346ad7d240bc4 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java +++ b/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java @@ -22,7 +22,7 @@ import org.kohsuke.args4j.Option; * Expresses the port settings of OpenFlow controller. */ public class CmdLineSettings { - public static final String DEFAULT_CONFIG_FILE = "config/floodlight.properties"; + public static final String DEFAULT_CONFIG_FILE = "src/main/resources/floodlightdefault.properties"; @Option(name="-cf", aliases="--configFile", metaVar="FILE", usage="Floodlight configuration file") private String configFile = DEFAULT_CONFIG_FILE; diff --git a/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java index 12716c4bab5c4b4afeb55089a5ee7264e2d46148..e28d428a2a2cb210600a3ea700bdb112648c70f6 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java +++ b/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java @@ -25,7 +25,6 @@ import net.floodlightcontroller.core.internal.IOFSwitchService; import net.floodlightcontroller.core.internal.Controller; import net.floodlightcontroller.core.module.Run; -import org.projectfloodlight.openflow.protocol.OFType; import org.sdnplatform.sync.ISyncService; import net.floodlightcontroller.core.IFloodlightProviderService; @@ -33,7 +32,6 @@ import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.debugcounter.IDebugCounterService; import net.floodlightcontroller.debugevent.IDebugEventService; import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; @@ -76,7 +74,6 @@ public class FloodlightProvider implements IFloodlightModule { dependencies.add(IStorageSourceService.class); dependencies.add(IPktInProcessingTimeService.class); dependencies.add(IRestApiService.class); - dependencies.add(ICounterStoreService.class); dependencies.add(IDebugCounterService.class); dependencies.add(IDebugEventService.class); dependencies.add(IOFSwitchService.class); @@ -91,8 +88,6 @@ public class FloodlightProvider implements IFloodlightModule { context.getServiceImpl(IStorageSourceService.class)); controller.setPktInProcessingService( context.getServiceImpl(IPktInProcessingTimeService.class)); - controller.setCounterStore( - context.getServiceImpl(ICounterStoreService.class)); controller.setDebugCounter( context.getServiceImpl(IDebugCounterService.class)); controller.setDebugEvent( @@ -103,6 +98,8 @@ public class FloodlightProvider implements IFloodlightModule { context.getServiceImpl(IThreadPoolService.class)); controller.setSyncService( context.getServiceImpl(ISyncService.class)); + controller.setSwitchService( + context.getServiceImpl(IOFSwitchService.class)); controller.init(context.getConfigParams(this)); } @@ -116,16 +113,4 @@ public class FloodlightProvider implements IFloodlightModule { public void run() throws FloodlightModuleException { controller.run(); } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - // TODO Auto-generated method stub - return false; - } } diff --git a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java index 1896d27207e2ba176abbf063cc80aac279831e74..24e105ed06a96824231e3e1de5aeee5be6010672 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java +++ b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java @@ -5,10 +5,12 @@ import java.util.Map; import java.util.Set; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.LogicalOFMessageCategory; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.rest.SwitchRepresentation; + import org.projectfloodlight.openflow.types.DatapathId; public interface IOFSwitchService extends IFloodlightService { @@ -57,6 +59,13 @@ public interface IOFSwitchService extends IFloodlightService { * @param listener The module that wants to listen for events */ void addOFSwitchListener(IOFSwitchListener listener); + + /** + * Add a switch driver + * @param manufacturerDescriptionPrefix + * @param driver + */ + void addOFSwitchDriver(String manufacturerDescriptionPrefix, IOFSwitchDriver driver); /** * Remove a switch listener diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java b/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java index f37da6707e7e24db99315f16ba02e935a898b00f..92a106307f6c85b4a7e3b322826f1258d893f677 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java +++ b/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java @@ -1,22 +1,17 @@ package net.floodlightcontroller.core.internal; -import java.util.Date; import java.util.Map.Entry; import javax.annotation.Nonnull; +import java.util.Date; import net.floodlightcontroller.core.HARole; -import net.floodlightcontroller.core.internal.Controller; -import net.floodlightcontroller.core.internal.RoleManagerCounters; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IOFSwitchBackend; -import net.floodlightcontroller.core.internal.IOFSwitchService; -import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler; +import net.floodlightcontroller.core.IShutdownService; +import net.floodlightcontroller.core.RoleInfo; import net.floodlightcontroller.core.internal.Controller.IUpdate; - -import net.floodlightcontroller.core.internal.RoleManager; -import net.floodlightcontroller.core.internal.RoleManager.SwitchRoleUpdate; import org.projectfloodlight.openflow.protocol.OFControllerRole; import org.projectfloodlight.openflow.types.DatapathId; import org.slf4j.Logger; @@ -25,7 +20,6 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import net.floodlightcontroller.core.RoleInfo; /** * A utility class to manage the <i>controller roles</i>. @@ -49,8 +43,8 @@ import net.floodlightcontroller.core.RoleInfo; public class RoleManager { private volatile RoleInfo currentRoleInfo; private final Controller controller; + private final IShutdownService shutdownService; private final RoleManagerCounters counters; - private volatile boolean notifiedLeader; private static final Logger log = LoggerFactory.getLogger(RoleManager.class); @@ -61,16 +55,19 @@ public class RoleManager { * @throws NullPointerException if role or roleChangeDescription is null */ public RoleManager(@Nonnull Controller controller, + @Nonnull IShutdownService shutdownService, @Nonnull HARole role, @Nonnull String roleChangeDescription) { Preconditions.checkNotNull(controller, "controller must not be null"); Preconditions.checkNotNull(role, "role must not be null"); Preconditions.checkNotNull(roleChangeDescription, "roleChangeDescription must not be null"); + Preconditions.checkNotNull(shutdownService, "shutdownService must not be null"); this.currentRoleInfo = new RoleInfo(role, roleChangeDescription, new Date()); this.controller = controller; + this.shutdownService = shutdownService; this.counters = new RoleManagerCounters(controller.getDebugCounter()); } @@ -160,7 +157,6 @@ public class RoleManager { if(!switchesHaveAnotherMaster()){ // No valid cluster controller connections found, become ACTIVE! setRole(HARole.ACTIVE, "Leader election assigned ACTIVE role"); - notifiedLeader = false; } } @@ -182,7 +178,7 @@ public class RoleManager { } public void notifyControllerConnectionUpdate() { - if(notifiedLeader && currentRoleInfo.getRole() != HARole.ACTIVE) { + if(currentRoleInfo.getRole() != HARole.ACTIVE) { attemptActiveTransition(); } } @@ -228,7 +224,7 @@ public class RoleManager { String reason = String.format("Received role request to " + "transition from ACTIVE to STANDBY (reason: %s)", getRoleInfo().getRoleChangeDescription()); - //TODO @Ryan shutdownService.terminate(reason, 0); + shutdownService.terminate(reason, 0); } } } diff --git a/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java b/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java index 7a44f1d29f9c501bdbb55c0c64479e50a2f60573..ed7da2dff8d2ee9d33c7121a9a17ca651deca78d 100644 --- a/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java +++ b/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java @@ -17,20 +17,23 @@ package net.floodlightcontroller.core.types; +import org.projectfloodlight.openflow.types.MacAddress; +import org.projectfloodlight.openflow.types.VlanVid; + public class MacVlanPair { - public Long mac; - public Short vlan; - public MacVlanPair(Long mac, Short vlan) { - this.mac = mac; - this.vlan = vlan; + public MacAddress mac; + public VlanVid vlan; + public MacVlanPair(MacAddress mac2, VlanVid vlan2) { + this.mac = mac2; + this.vlan = vlan2; } - public long getMac() { - return mac.longValue(); + public MacAddress getMac() { + return mac; } - public short getVlan() { - return vlan.shortValue(); + public VlanVid getVlan() { + return vlan; } public boolean equals(Object o) { diff --git a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java deleted file mode 100644 index 48ff7d9beb31921b2bfee97f52a85fc82bd94ae5..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java +++ /dev/null @@ -1,169 +0,0 @@ -/** -* 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.core.util; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/*** - * A static utility class to register flow cookiue AppIds and generating - * flow cookies for a particular App` - * - * An "app" is a module or piece of code that can install flows in a switch. - * E.g., Forwarding and StaticFlowPusher are apps. An App is identified by a - * 12 bit integer, the id. Furthermore, an App has a name. The id value must - * be unique but the same name can be registered for multiple numeric ids. - * TODO: should we enforce unique names - * - * This class is thread-safe. - * - * The 64 bit OpenFlow cookie field used in the following way - * <li> Bit 63 -- 52 (12 bit): the AppId - * <li> Bit 51 -- 32 (20 bit): currently unused. Set to 0. - * <li> Bit 31 -- 0 (32 bit): user data - * - * FIXME: The class should be a singleton. The registration method should - * return an instance of class. This instance should then be used to generate - * flow cookies. Ideally, we would also represent a flow cookie as a class - * instance. - * - * - * @author capveg - * - */ - -public class AppCookie { - static final int APP_ID_BITS = 12; - static final long APP_ID_MASK = (1L << APP_ID_BITS) - 1; - static final int APP_ID_SHIFT = (64 - APP_ID_BITS); - - static final long USER_MASK = 0x00000000FFFFFFFFL; - - /**the following bit will be set accordingly if the field is rewritten by application. e.g. VRS or floating IP - * FIXME: these should not be in AppCookie and they shoul not use - * the reserved bit range*/ - static final int SRC_MAC_REWRITE_BIT=33; - static final int DEST_MAC_REWRITE_BIT=34; - static final int SRC_IP_REWRITE_BIT=35; - static final int DEST_IP_REWRITE_BIT=36; - - - static final long REWRITE_MASK= 0x000f00000000L; - private static ConcurrentMap<Integer, String> appIdMap = - new ConcurrentHashMap<Integer, String>(); - - /** - * Encapsulate an application ID and a user block of stuff into a cookie - * - * @param application An ID to identify the application - * @param user Some application specific data - * @return a cookie for use in OFFlowMod.setCookie() - * @throws IllegalStateException if the application has not been registered - */ - - static public long makeCookie(int application, int user) { - if (!appIdMap.containsKey(application)) { - throw new AppIDNotRegisteredException(application); - } - long longApp = application; - long longUser = user & USER_MASK; // mask to prevent sign extend - return (longApp << APP_ID_SHIFT) | longUser; - } - - /** - * Extract the application id from a flow cookie. Does <em>not</em> check - * whether the application id is registered - * @param cookie - * @return - */ - static public int extractApp(long cookie) { - return (int)((cookie >>> APP_ID_SHIFT) & APP_ID_MASK); - } - - static public int extractUser(long cookie) { - return (int)(cookie & USER_MASK); - } - - static public boolean isRewriteFlagSet(long cookie) { - if ((cookie & REWRITE_MASK) !=0L) - return true; - return false; - } - static public boolean isSrcMacRewriteFlagSet(long cookie) { - if ((cookie & (1L << (SRC_MAC_REWRITE_BIT-1))) !=0L) - return true; - return false; - } - static public boolean isDestMacRewriteFlagSet(long cookie) { - if ((cookie & (1L << (DEST_MAC_REWRITE_BIT-1))) !=0L) - return true; - return false; - } - static public boolean isSrcIpRewriteFlagSet(long cookie) { - if ((cookie & (1L << (SRC_IP_REWRITE_BIT-1))) !=0L) - return true; - return false; - } - static public boolean isDestIpRewriteFlagSet(long cookie) { - if ((cookie & (1L << (DEST_IP_REWRITE_BIT-1))) !=0L) - return true; - return false; - } - static public long setSrcMacRewriteFlag(long cookie) { - return cookie | (1L << (SRC_MAC_REWRITE_BIT-1)); - } - static public long setDestMacRewriteFlag(long cookie) { - return cookie | (1L << (DEST_MAC_REWRITE_BIT-1)); - } - static public long setSrcIpRewriteFlag(long cookie) { - return cookie | (1L << (SRC_IP_REWRITE_BIT-1)); - } - static public long setDestIpRewriteFlag(long cookie) { - return cookie | (1L << (DEST_IP_REWRITE_BIT-1)); - } - /** - * A lame attempt to prevent duplicate application ID. - * TODO: Once bigdb is merged, we should expose appID->appName map - * via REST API so CLI doesn't need a separate copy of the map. - * - * @param application - * @param appName - * @throws AppIDInUseException - */ - public static void registerApp(int application, String appName) - throws AppIDException - { - if ((application & APP_ID_MASK) != application) { - throw new InvalidAppIDValueException(application); - } - String oldApp = appIdMap.putIfAbsent(application, appName); - if (oldApp != null && !oldApp.equals(appName)) { - throw new AppIDInUseException(application, oldApp, appName); - } - } - - /** - * Retrieves the application name registered for the given application id - * or null if the application has not been registered - * @param application - * @return - */ - public static String getAppName(int application) { - return appIdMap.get(application); - } -} diff --git a/src/main/java/net/floodlightcontroller/core/util/AppIDException.java b/src/main/java/net/floodlightcontroller/core/util/AppIDException.java deleted file mode 100644 index efcb6d5856d56dd88d9b33a1785e9a2293b30027..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/AppIDException.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.floodlightcontroller.core.util; - -public class AppIDException extends RuntimeException { - private static final long serialVersionUID = 7038554747318757572L; - - public AppIDException() { - super(); - } - - public AppIDException(String message) { - super(message); - } -} - diff --git a/src/main/java/net/floodlightcontroller/core/util/AppIDInUseException.java b/src/main/java/net/floodlightcontroller/core/util/AppIDInUseException.java deleted file mode 100644 index 077def6a3b91ef59d37450173958360f23f31533..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/AppIDInUseException.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.floodlightcontroller.core.util; - -public class AppIDInUseException extends AppIDException { - private static final long serialVersionUID = 3167241821651094997L; - - public AppIDInUseException(int appId, String oldAppName, - String newAppName) { - super(String.format("Tried to register application IdD %s for %s, but" + - "already registered for %s.", appId, oldAppName, newAppName)); - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/core/util/AppIDNotRegisteredException.java b/src/main/java/net/floodlightcontroller/core/util/AppIDNotRegisteredException.java deleted file mode 100644 index 4dab9610137f52e9e75639442dacc103d99ed19e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/AppIDNotRegisteredException.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.floodlightcontroller.core.util; - -public class AppIDNotRegisteredException extends AppIDException { - private static final long serialVersionUID = -9195312786292237763L; - - public AppIDNotRegisteredException(int application) { - super("Application Id " + application + " has not been registered"); - } - -} diff --git a/src/main/java/net/floodlightcontroller/core/util/InvalidAppIDValueException.java b/src/main/java/net/floodlightcontroller/core/util/InvalidAppIDValueException.java deleted file mode 100644 index de5e9e400dc7e25e96f7530fd7957f3aa565fce8..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/InvalidAppIDValueException.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.floodlightcontroller.core.util; - -/** - * Thrown when an invalid app Id registration is attempted. - * @author gregor - * - */ -public class InvalidAppIDValueException extends AppIDException { - private static final long serialVersionUID = -1866481021012360918L; - - public InvalidAppIDValueException(long invalidId) { - super("Application ID " + invalidId + "is not valid"); - } - -} diff --git a/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java b/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java deleted file mode 100644 index da3c16444582e01c2c93108c0e5678c9138db6fe..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java +++ /dev/null @@ -1,136 +0,0 @@ -/** -* 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.core.util; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.IListener; -import net.floodlightcontroller.core.annotations.LogMessageDoc; - -/** - * Maintain lists of listeners ordered by dependency. - * - * @author readams - * - */ -public class ListenerDispatcher<U, T extends IListener<U>> { - protected static Logger logger = LoggerFactory.getLogger(ListenerDispatcher.class); - volatile List<T> listeners = new ArrayList<T>(); - - private void visit(List<T> newlisteners, U type, HashSet<T> visited, - List<T> ordering, T listener) { - if (!visited.contains(listener)) { - visited.add(listener); - - for (T i : newlisteners) { - if (ispre(type, i, listener)) { - visit(newlisteners, type, visited, ordering, i); - } - } - ordering.add(listener); - } - } - - private boolean ispre(U type, T l1, T l2) { - return (l2.isCallbackOrderingPrereq(type, l1.getName()) || - l1.isCallbackOrderingPostreq(type, l2.getName())); - } - - /** - * Add a listener to the list of listeners - * @param listener - */ - @LogMessageDoc(level="ERROR", - message="No listener dependency solution: " + - "No listeners without incoming dependencies", - explanation="The set of listeners installed " + - "have dependencies with no solution", - recommendation="Install a different set of listeners " + - "or install all dependencies. This is a defect in " + - "the controller installation.") - public void addListener(U type, T listener) { - List<T> newlisteners = new ArrayList<T>(); - if (listeners != null) - newlisteners.addAll(listeners); - - newlisteners.add(listener); - // Find nodes without outgoing edges - List<T> terminals = new ArrayList<T>(); - for (T i : newlisteners) { - boolean isterm = true; - for (T j : newlisteners) { - if (ispre(type, i, j)) { - isterm = false; - break; - } - } - if (isterm) { - terminals.add(i); - } - } - - if (terminals.size() == 0) { - logger.error("No listener dependency solution: " + - "No listeners without incoming dependencies"); - listeners = newlisteners; - return; - } - - // visit depth-first traversing in the opposite order from - // the dependencies. Note we will not generally detect cycles - HashSet<T> visited = new HashSet<T>(); - List<T> ordering = new ArrayList<T>(); - for (T term : terminals) { - visit(newlisteners, type, visited, ordering, term); - } - listeners = ordering; - } - - /** - * Remove the given listener - * @param listener the listener to remove - */ - public void removeListener(T listener) { - if (listeners != null) { - List<T> newlisteners = new ArrayList<T>(); - newlisteners.addAll(listeners); - newlisteners.remove(listener); - listeners = newlisteners; - } - } - - /** - * Clear all listeners - */ - public void clearListeners() { - listeners = new ArrayList<T>(); - } - - /** - * Get the ordered list of listeners ordered by dependencies - * @return - */ - public List<T> getOrderedListeners() { - return listeners; - } -} diff --git a/src/main/java/net/floodlightcontroller/core/util/MutableInteger.java b/src/main/java/net/floodlightcontroller/core/util/MutableInteger.java deleted file mode 100644 index 0f070fa659e59f1efb397be2b11c9d9193095b36..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/MutableInteger.java +++ /dev/null @@ -1,55 +0,0 @@ -/** -* 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.core.util; - -public class MutableInteger extends Number { - private static final long serialVersionUID = 1L; - int mutableInt; - - public MutableInteger(int value) { - this.mutableInt = value; - } - - public void setValue(int value) { - this.mutableInt = value; - } - - @Override - public double doubleValue() { - return (double) mutableInt; - } - - @Override - public float floatValue() { - // TODO Auto-generated method stub - return (float) mutableInt; - } - - @Override - public int intValue() { - // TODO Auto-generated method stub - return mutableInt; - } - - @Override - public long longValue() { - // TODO Auto-generated method stub - return (long) mutableInt; - } - -} diff --git a/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java b/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java deleted file mode 100644 index 07729e533cacda933365652113f9a5ad1516a6aa..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java +++ /dev/null @@ -1,162 +0,0 @@ -/** -* 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.core.util; - -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import net.floodlightcontroller.core.annotations.LogMessageDoc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This allows you to represent a task that should be queued for future execution - * but where you only want the task to complete once in response to some sequence - * of events. For example, if you get a change notification and want to reload state, - * you only want to reload the state once, at the end, and don't want to queue - * an update for every notification that might come in. - * - * The semantics are as follows: - * * If the task hasn't begun yet, do not queue a new task - * * If the task has begun, set a bit to restart it after the current task finishes - */ -public class SingletonTask { - protected static Logger logger = LoggerFactory.getLogger(SingletonTask.class); - - protected static class SingletonTaskContext { - protected boolean taskShouldRun = false; - protected boolean taskRunning = false; - - protected SingletonTaskWorker waitingTask = null; - } - - protected static class SingletonTaskWorker implements Runnable { - SingletonTask parent; - boolean canceled = false; - long nextschedule = 0; - - public SingletonTaskWorker(SingletonTask parent) { - super(); - this.parent = parent; - } - - @Override - @LogMessageDoc(level="ERROR", - message="Exception while executing task", - recommendation=LogMessageDoc.GENERIC_ACTION) - public void run() { - synchronized (parent.context) { - if (canceled || !parent.context.taskShouldRun) - return; - - parent.context.taskRunning = true; - parent.context.taskShouldRun = false; - } - - try { - parent.task.run(); - } catch (Exception e) { - logger.error("Exception while executing task", e); - } - - synchronized (parent.context) { - parent.context.taskRunning = false; - - if (parent.context.taskShouldRun) { - long now = System.nanoTime(); - if ((nextschedule <= 0 || (nextschedule - now) <= 0)) { - parent.ses.execute(this); - } else { - parent.ses.schedule(this, - nextschedule-now, - TimeUnit.NANOSECONDS); - } - } - } - } - } - - protected SingletonTaskContext context = new SingletonTaskContext(); - protected Runnable task; - protected ScheduledExecutorService ses; - - - /** - * Construct a new SingletonTask for the given runnable. The context - * is used to manage the state of the task execution and can be shared - * by more than one instance of the runnable. - * @param context - * @param Task - */ - public SingletonTask(ScheduledExecutorService ses, - Runnable task) { - super(); - this.task = task; - this.ses = ses; - } - - /** - * Schedule the task to run if there's not already a task scheduled - * If there is such a task waiting that has not already started, it - * cancel that task and reschedule it to run at the given time. If the - * task is already started, it will cause the task to be rescheduled once - * it completes to run after delay from the time of reschedule. - * - * @param delay the delay in scheduling - * @param unit the timeunit of the delay - */ - public void reschedule(long delay, TimeUnit unit) { - boolean needQueue = true; - SingletonTaskWorker stw = null; - - synchronized (context) { - if (context.taskRunning || context.taskShouldRun) { - if (context.taskRunning) { - // schedule to restart at the right time - if (delay > 0) { - long now = System.nanoTime(); - long then = - now + TimeUnit.NANOSECONDS.convert(delay, unit); - context.waitingTask.nextschedule = then; - } else { - context.waitingTask.nextschedule = 0; - } - needQueue = false; - } else { - // cancel and requeue - context.waitingTask.canceled = true; - context.waitingTask = null; - } - } - - context.taskShouldRun = true; - - if (needQueue) { - stw = context.waitingTask = new SingletonTaskWorker(this); - } - } - - if (needQueue) { - if (delay <= 0) - ses.execute(stw); - else - ses.schedule(stw, delay, unit); - } - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/core/util/URIUtil.java b/src/main/java/net/floodlightcontroller/core/util/URIUtil.java deleted file mode 100644 index 01a44ccf0cda6782ebbcaef9c5874361c4c272b0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/util/URIUtil.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.floodlightcontroller.core.util; - -import java.net.URI; - -public class URIUtil { - - public static URI createURI(String hostname, int port) { - return URI.create("tcp://" + hostname + ":" + port); - } -} diff --git a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java index cea740239ce1bfa20ad0d705135d507beaa188bb..169faaf9c1ca8f04630d1b885e1bff47cba09611 100644 --- a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java @@ -24,7 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import net.floodlightcontroller.core.IFloodlightProviderService; +import net.floodlightcontroller.core.internal.IOFSwitchService; import org.projectfloodlight.openflow.protocol.OFFeaturesReply; import org.projectfloodlight.openflow.protocol.OFStatsReply; @@ -79,10 +79,10 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase { return model; } - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); - Set<DatapathId> switchDpids = floodlightProvider.getAllSwitchDpids(); + IOFSwitchService switchService = + (IOFSwitchService) getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); + Set<DatapathId> switchDpids = switchService.getAllSwitchDpids(); List<GetConcurrentStatsThread> activeThreads = new ArrayList<GetConcurrentStatsThread>(switchDpids.size()); List<GetConcurrentStatsThread> pendingRemovalThreads = new ArrayList<GetConcurrentStatsThread>(); GetConcurrentStatsThread t; diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java index 9ad593788f05401a717e32cfa5943ca1b508f909..9da5c493bc4be59c3443ec82db58d389f746bc9e 100644 --- a/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java @@ -21,7 +21,7 @@ import org.restlet.resource.ServerResource; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.RoleInfo; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; +import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.annotations.LogMessageDoc; import org.restlet.resource.Get; @@ -49,9 +49,9 @@ public class ControllerRoleResource extends ServerResource { recommendation=LogMessageDoc.CHECK_CONTROLLER) public void setRole(RoleInfo roleInfo) { //Role role = Role.lookupRole(roleInfo.getRole()); - Role role = null; + HARole role = null; try { - role = Role.valueOf(roleInfo.getRole().toUpperCase()); + role = roleInfo.getRole(); } catch (IllegalArgumentException e) { // The role value in the REST call didn't match a valid diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java index 457cc91c20fc15d854abeb148eccc27daef1c2d1..c04eb5eef1dad04b7918e52c5df4673fdee29505 100644 --- a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java @@ -25,8 +25,9 @@ import java.util.Map; import java.util.Collection; import java.util.Set; -import net.floodlightcontroller.core.IFloodlightProviderService; +import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.internal.IOFSwitchService; import net.floodlightcontroller.util.FilterIterator; import org.projectfloodlight.openflow.protocol.OFCapabilities; @@ -64,7 +65,7 @@ public class ControllerSwitchesResource extends ServerResource { public Map<String,String> getDescription() { Map<String,String> rv = new HashMap<String, String>(); - if (sw.getDescriptionStatistics() == null) { + if (sw.getSwitchDescription() == null) { rv.put("manufacturer", ""); rv.put("hardware", ""); rv.put("software", ""); @@ -72,15 +73,15 @@ public class ControllerSwitchesResource extends ServerResource { rv.put("datapath", ""); } else { rv.put("manufacturer", - sw.getDescriptionStatistics().getManufacturerDescription()); + sw.getSwitchDescription().getManufacturerDescription()); rv.put("hardware", - sw.getDescriptionStatistics().getHardwareDescription()); + sw.getSwitchDescription().getHardwareDescription()); rv.put("software", - sw.getDescriptionStatistics().getSoftwareDescription()); + sw.getSwitchDescription().getSoftwareDescription()); rv.put("serialNum", - sw.getDescriptionStatistics().getSerialNumber()); + sw.getSwitchDescription().getSerialNumber()); rv.put("datapath", - sw.getDescriptionStatistics().getDatapathDescription()); + sw.getSwitchDescription().getDatapathDescription()); } return rv; } @@ -104,9 +105,9 @@ public class ControllerSwitchesResource extends ServerResource { } public String getHarole() { - if (sw.getHARole() == null) + if (sw.getControllerRole() == null) return "null"; - return sw.getHARole().toString(); + return HARole.ofOFRole(sw.getControllerRole()).toString(); } public String getInetAddress() { @@ -156,9 +157,9 @@ public class ControllerSwitchesResource extends ServerResource { @Get("json") public Iterator<SwitchJsonSerializerWrapper> retrieve() { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); + IOFSwitchService switchService = + (IOFSwitchService) getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); DatapathId switchDPID = null; @@ -174,7 +175,7 @@ public class ControllerSwitchesResource extends ServerResource { } if (switchDPID != null) { IOFSwitch sw = - floodlightProvider.getSwitch(switchDPID); + switchService.getSwitch(switchDPID); if (sw != null) { SwitchJsonSerializerWrapper wrappedSw = new SwitchJsonSerializerWrapper(sw); @@ -186,7 +187,7 @@ public class ControllerSwitchesResource extends ServerResource { form.getFirstValue("dpid__startswith", true); Iterator<IOFSwitch> iofSwitchIter = - floodlightProvider.getAllSwitchMap().values().iterator(); + switchService.getAllSwitchMap().values().iterator(); Iterator<SwitchJsonSerializerWrapper> switer = new SwitchJsonSerializerWrapperIterator(iofSwitchIter); if (dpidStartsWith != null) { diff --git a/src/main/java/net/floodlightcontroller/core/web/CounterResource.java b/src/main/java/net/floodlightcontroller/core/web/CounterResource.java index fb680d7c94b4a6af0cfdad5fd288c095e2c3ffd1..35c771c2cdd8682132af72d26f8ddb74d7a8560a 100644 --- a/src/main/java/net/floodlightcontroller/core/web/CounterResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/CounterResource.java @@ -19,11 +19,12 @@ package net.floodlightcontroller.core.web; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; -import net.floodlightcontroller.counter.CounterValue; -import net.floodlightcontroller.counter.ICounter; +import net.floodlightcontroller.debugcounter.DebugCounterResource; +import net.floodlightcontroller.debugcounter.IDebugCounter; import org.restlet.resource.Get; @@ -33,26 +34,20 @@ public class CounterResource extends CounterResourceBase { String counterTitle = (String) getRequestAttributes().get("counterTitle"); Map<String, Object> model = new HashMap<String,Object>(); - CounterValue v; + long dc; if (counterTitle.equalsIgnoreCase("all")) { - Map<String, ICounter> counters = this.counterStore.getAll(); + List<DebugCounterResource> counters = this.debugCounterService.getAllCounterValues(); if (counters != null) { - Iterator<Map.Entry<String, ICounter>> it = - counters.entrySet().iterator(); + Iterator<DebugCounterResource> it = counters.iterator(); while (it.hasNext()) { - Entry<String, ICounter> entry = it.next(); - String counterName = entry.getKey(); - v = entry.getValue().getCounterValue(); - - if (CounterValue.CounterType.LONG == v.getType()) { - model.put(counterName, v.getLong()); - } else if (v.getType() == CounterValue.CounterType.DOUBLE) { - model.put(counterName, v.getDouble()); - } + DebugCounterResource dcr = it.next(); + String counterName = dcr.getCounterHierarchy(); + dc = dcr.getCounterValue(); + model.put(counterName, dc); } } } else { - ICounter counter = this.counterStore.getCounter(counterTitle); + List<DebugCounterResource> counter = this.debugCounterService.getCounterHierarchy(moduleName, counterTitle); if (counter != null) { v = counter.getCounterValue(); } else { diff --git a/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java index 70e90ed231431b7c88e1377183671698686b5f75..ecf3935f313d6b8e520640ce4aa118f9ecb74148 100644 --- a/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java +++ b/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java @@ -17,19 +17,18 @@ package net.floodlightcontroller.core.web; -import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.debugcounter.IDebugCounterService; import org.restlet.resource.ResourceException; import org.restlet.resource.ServerResource; public class CounterResourceBase extends ServerResource { - protected ICounterStoreService counterStore; + protected IDebugCounterService debugCounterService; @Override protected void doInit() throws ResourceException { super.doInit(); - counterStore = - (ICounterStoreService)getContext().getAttributes(). - get(ICounterStoreService.class.getCanonicalName()); + debugCounterService = (IDebugCounterService) getContext().getAttributes(). + get(IDebugCounterService.class.getCanonicalName()); } } diff --git a/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java b/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java deleted file mode 100644 index ad3ea5640cf61a20f4698363410a76dce26106d4..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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; - -import java.util.Map; - -import org.restlet.resource.Get; - -import net.floodlightcontroller.core.module.ModuleLoaderResource; - -public class LoadedModuleLoaderResource extends ModuleLoaderResource { - /** - * Retrieves information about all modules available - * to Floodlight. - * @return Information about all modules available. - */ - @Get("json") - public Map<String, Object> retrieve() { - return retrieveInternal(true); - } -} diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java index f8f9ff0e643e369cd3e342ddd933a302b4340cae..98c2a73753f0cb3fe84597eac0a64b29d61999a3 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java @@ -26,9 +26,7 @@ import java.util.Map; import org.projectfloodlight.openflow.types.DatapathId; import org.restlet.resource.Get; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.counter.CounterStore.NetworkLayer; -import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.core.internal.IOFSwitchService; /** * Get the counter categories for a particular switch @@ -37,9 +35,9 @@ import net.floodlightcontroller.counter.ICounterStoreService; public class SwitchCounterCategoriesResource extends CounterResourceBase { @Get("json") public Map<String, Object> retrieve() { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); + IOFSwitchService switchService = + (IOFSwitchService)getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); HashMap<String,Object> model = new HashMap<String,Object>(); String switchID = (String) getRequestAttributes().get("switchId"); @@ -47,7 +45,7 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase { String layer = (String) getRequestAttributes().get("layer"); if (switchID.equalsIgnoreCase("all")) { - for (DatapathId dpid : floodlightProvider.getAllSwitchDpids()) { + for (DatapathId dpid : switchService.getAllSwitchDpids()) { switchID = dpid.toString(); getOneSwitchCounterCategoriesJson(model, switchID, counterName, layer); diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java index f078dd8c198687537a1a1365026b40400ab7bc95..61667daee959a7788753bc065613a3bf59cae462 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java @@ -25,9 +25,7 @@ import java.util.Map; import org.projectfloodlight.openflow.types.DatapathId; import org.restlet.resource.Get; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.counter.ICounter; -import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.core.internal.IOFSwitchService; /** * Get counters for a particular switch @@ -36,9 +34,9 @@ import net.floodlightcontroller.counter.ICounterStoreService; public class SwitchCounterResource extends CounterResourceBase { @Get("json") public Map<String, Object> retrieve() { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); + IOFSwitchService switchService = + (IOFSwitchService)getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); HashMap<String,Object> model = new HashMap<String,Object>(); String switchID = (String) getRequestAttributes().get("switchId"); @@ -46,7 +44,7 @@ public class SwitchCounterResource extends CounterResourceBase { if (switchID.equalsIgnoreCase("all")) { getOneSwitchCounterJson(model, ICounterStoreService.CONTROLLER_NAME, counterName); - for (DatapathId dpid : floodlightProvider.getAllSwitchDpids()) { + for (DatapathId dpid : switchService.getAllSwitchDpids()) { switchID = dpid.toString(); getOneSwitchCounterJson(model, switchID, counterName); diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java index aa48eb3c1c63deb2f603f0668ffe5edc1999dd95..9730a82b80ef14184371fff8f77792bf289b1582 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java @@ -25,29 +25,33 @@ import java.util.concurrent.TimeUnit; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.annotations.LogMessageDoc; +import net.floodlightcontroller.core.internal.IOFSwitchService; -import org.projectfloodlight.openflow.protocol.OFFactories; -import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.protocol.OFFeaturesReply; +import org.projectfloodlight.openflow.protocol.match.Match; +import org.projectfloodlight.openflow.protocol.queueprop.OFQueueProp; +import org.projectfloodlight.openflow.types.DatapathId; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.TableId; +import org.projectfloodlight.openflow.protocol.OFFeaturesRequest; import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; -import org.projectfloodlight.openflow.protocol.OFMatch; -import org.projectfloodlight.openflow.protocol.OFPortDesc; +import org.projectfloodlight.openflow.protocol.OFQueueProperties; +import org.projectfloodlight.openflow.protocol.OFStatsReply; +import org.projectfloodlight.openflow.protocol.OFStatsRequest; import org.projectfloodlight.openflow.protocol.OFAggregateStatsRequest; -import org.projectfloodlight.openflow.protocol.OFAggregateStatsReply; import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest; import org.projectfloodlight.openflow.protocol.OFPortStatsRequest; import org.projectfloodlight.openflow.protocol.OFQueueStatsRequest; import org.projectfloodlight.openflow.protocol.OFStatsType; -import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.util.HexString; -import org.projectfloodlight.openflow.protocol.OFStatsReply; -import org.projectfloodlight.openflow.protocol.OFStatsRequest; -import org.projectfloodlight.openflow.types.DatapathId; import org.restlet.resource.ResourceException; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.primitives.UnsignedLong; +import com.google.common.util.concurrent.ListenableFuture; + /** * Base class for server resources related to switches * @author readams @@ -75,69 +79,50 @@ public class SwitchResourceBase extends ServerResource { LogMessageDoc.GENERIC_ACTION) protected List<OFStatsReply> getSwitchStatistics(DatapathId switchId, OFStatsType statType) { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); - - IOFSwitch sw = floodlightProvider.getSwitch(switchId); - - OFFactory factory = OFFactories.getFactory(OFVersion.OF_13); - OFFlowStatsRequest flowStatsRequest = factory.buildFlowStatsRequest() - .build(); - - Future<List<OFFlowStatsReply>> future = sw.queryStatistics(flowStatsRequest); - return future.get(); - - - sw.get - - Future<List<OFStatsReply>> future; + IOFSwitchService switchService = + (IOFSwitchService) getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); + + IOFSwitch sw = switchService.getSwitch(switchId); + ListenableFuture<?> future; List<OFStatsReply> values = null; - if (sw != null) - { - OFFactory - OFStatsRequest<> req = new OFFactory. - req.cre(statType); - int requestLength = req.getLengthU(); + if (sw != null) { + OFStatsRequest<?> req; if (statType == OFStatsType.FLOW) { - OFStatsRequest specificReq = new OFFlowStatisticsRequest(); - OFMatch match = new OFMatch(); - match.setWildcards(0xffffffff); - specificReq.setMatch(match); - specificReq.setOutPort(OFPort.OFPP_NONE.getValue()); - specificReq.setTableId((byte) 0xff); - req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); - requestLength += specificReq.getLength(); - } else if (statType == OFStatisticsType.AGGREGATE) { - OFAggregateStatisticsRequest specificReq = new OFAggregateStatisticsRequest(); - OFMatch match = new OFMatch(); - match.setWildcards(0xffffffff); - specificReq.setMatch(match); - specificReq.setOutPort(OFPort.OFPP_NONE.getValue()); - specificReq.setTableId((byte) 0xff); - req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); - requestLength += specificReq.getLength(); - } else if (statType == OFStatisticsType.PORT) { - OFPortStatisticsRequest specificReq = new OFPortStatisticsRequest(); - specificReq.setPortNumber(OFPort.OFPP_NONE.getValue()); - req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); - requestLength += specificReq.getLength(); - } else if (statType == OFStatisticsType.QUEUE) { - OFQueueStatisticsRequest specificReq = new OFQueueStatisticsRequest(); - specificReq.setPortNumber(OFPort.OFPP_ALL.getValue()); - // LOOK! openflowj does not define OFPQ_ALL! pulled this from openflow.h - // note that I haven't seen this work yet though... - specificReq.setQueueId(0xffffffff); - req.setStatistics(Collections.singletonList((OFStatistics)specificReq)); - requestLength += specificReq.getLength(); - } else if (statType == OFStatisticsType.DESC || - statType == OFStatisticsType.TABLE) { + Match match = sw.getOFFactory().buildMatch().build(); + req = sw.getOFFactory().buildFlowStatsRequest() + .setMatch(match) + .setOutPort(OFPort.ANY) + .setTableId(TableId.ALL) + .build(); + } else if (statType == OFStatsType.AGGREGATE) { + Match match = sw.getOFFactory().buildMatch().build(); + req = sw.getOFFactory().buildAggregateStatsRequest() + .setMatch(match) + .setOutPort(OFPort.ANY) + .setTableId(TableId.ALL) + .build(); + } else if (statType == OFStatsType.PORT) { + req = sw.getOFFactory().buildPortStatsRequest() + .setPortNo(OFPort.ANY) + .build(); + } else if (statType == OFStatsType.QUEUE) { + req = sw.getOFFactory().buildQueueStatsRequest() + .setPortNo(OFPort.ANY) + .setQueueId(UnsignedLong.MAX_VALUE.longValue()) + .build(); + } else if (statType == OFStatsType.DESC || + statType == OFStatsType.TABLE) { // pass - nothing todo besides set the type above + req = sw.getOFFactory().buildDescStatsRequest() + .build(); + } else { + //TODO @Ryan what to do about no matches in the if...elseif statements? + req = sw.getOFFactory().buildDescStatsRequest().build(); } - req.setLengthU(requestLength); try { - future = sw.queryStatistics(req); - values = future.get(10, TimeUnit.SECONDS); + future = sw.writeStatsRequest(req); + values = (List<OFStatsReply>) future.get(10, TimeUnit.SECONDS); } catch (Exception e) { log.error("Failure retrieving statistics from switch " + sw, e); } @@ -145,21 +130,24 @@ public class SwitchResourceBase extends ServerResource { return values; } - protected List<OFStatistics> getSwitchStatistics(String switchId, OFStatisticsType statType) { - return getSwitchStatistics(HexString.toLong(switchId), statType); + protected List<OFStatsReply> getSwitchStatistics(String switchId, OFStatsType statType) { + return getSwitchStatistics(DatapathId.of(switchId), statType); } - protected OFFeaturesReply getSwitchFeaturesReply(long switchId) { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); + protected OFFeaturesReply getSwitchFeaturesReply(DatapathId switchId) { + IOFSwitchService switchService = + (IOFSwitchService) getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); - IOFSwitch sw = floodlightProvider.getSwitch(switchId); + IOFSwitch sw = switchService.getSwitch(switchId); Future<OFFeaturesReply> future; OFFeaturesReply featuresReply = null; + //TODO @Ryan The only thing to set in an OFFeaturesRequest is the XID. I'm not sure + // if it matters what I set it to. Will it have a default value of the next available? + OFFeaturesRequest featuresRequest = sw.getOFFactory().buildFeaturesRequest().build(); if (sw != null) { try { - future = sw.querySwitchFeaturesReply(); + future = sw.writeRequest(featuresRequest); featuresReply = future.get(10, TimeUnit.SECONDS); } catch (Exception e) { log.error("Failure getting features reply from switch" + sw, e); @@ -170,7 +158,7 @@ public class SwitchResourceBase extends ServerResource { } protected OFFeaturesReply getSwitchFeaturesReply(String switchId) { - return getSwitchFeaturesReply(HexString.toLong(switchId)); + return getSwitchFeaturesReply(DatapathId.of(switchId)); } -} +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java index d7b4c01290368ce9b89b5a36c05c2aa236219926..63ccc7178552ed994abdce4785f06b94e4c50790 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java @@ -21,9 +21,10 @@ import java.util.HashMap; import org.projectfloodlight.openflow.types.DatapathId; import org.restlet.resource.ServerResource; -import net.floodlightcontroller.core.IFloodlightProviderService; +import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.RoleInfo; +import net.floodlightcontroller.core.internal.IOFSwitchService; import org.restlet.resource.Get; import org.slf4j.Logger; @@ -35,9 +36,9 @@ public class SwitchRoleResource extends ServerResource { @Get("json") public Object getRole() { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); + IOFSwitchService switchService = + (IOFSwitchService)getContext().getAttributes(). + get(IOFSwitchService.class.getCanonicalName()); String switchId = (String) getRequestAttributes().get("switchId"); @@ -45,19 +46,21 @@ public class SwitchRoleResource extends ServerResource { if (switchId.equalsIgnoreCase("all")) { HashMap<String,RoleInfo> model = new HashMap<String,RoleInfo>(); - for (IOFSwitch sw: floodlightProvider.getAllSwitchMap().values()) { + for (IOFSwitch sw: switchService.getAllSwitchMap().values()) { switchId = sw.getStringId(); - roleInfo = new RoleInfo(sw.getHARole(), null); + //TODO @Ryan not sure what the changeDescription string should be here. + roleInfo = new RoleInfo(HARole.ofOFRole(sw.getControllerRole()), "", null); model.put(switchId, roleInfo); } return model; } DatapathId dpid = DatapathId.of(switchId); - IOFSwitch sw = floodlightProvider.getSwitch(dpid); + IOFSwitch sw = switchService.getSwitch(dpid); if (sw == null) return null; - roleInfo = new RoleInfo(sw.getHARole(), null); + //TODO @Ryan not sure what the changeDescription string should be here. + roleInfo = new RoleInfo(HARole.ofOFRole(sw.getControllerRole()), "", null); return roleInfo; } } diff --git a/src/main/java/net/floodlightcontroller/counter/CounterStore.java b/src/main/java/net/floodlightcontroller/counter/CounterStore.java deleted file mode 100644 index d3067e60d5a75ec31e3b5ae911a3f5c8633e6137..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/CounterStore.java +++ /dev/null @@ -1,582 +0,0 @@ -/** - * 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.counter; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.counter.CounterValue.CounterType; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; - -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.types.DatapathId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implements a central store for system counters. These counters include - * overall packet-in, packet-out, and flow-mod counters. Additional packet-in - * counters are maintained for bcast/unicast/multicast traffic, as well as counters - * for traffic types based on ethertype and ip-proto (maintained on a per switch - * and controller level). These counters are maintained without the involvement of - * any other module in the system. For per-module counters and other detailed - * debug services, consider IDebugCounterService. - * - * @authors Kyle, Kanzhe, Mandeep and Saurav - */ -public class CounterStore implements IFloodlightModule, ICounterStoreService { - protected static Logger log = LoggerFactory.getLogger(CounterStore.class); - - public enum NetworkLayer { - L2, L3, L4 - } - - protected class CounterEntry { - protected ICounter counter; - String title; - } - - protected class MutableInt { - int value = 0; - public void increment() { value += 1; } - public int get() { return value; } - public void set(int val) { value = val; } - } - - protected class CounterKeyTuple { - OFType msgType; - DatapathId dpid; - short l3type; - byte l4type; - - public CounterKeyTuple(OFType msgType, DatapathId dpid, short l3type, byte l4type){ - this.msgType = msgType; - this.dpid = dpid; - this.l3type = l3type; - this.l4type = l4type; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (!(obj instanceof CounterKeyTuple)) return false; - CounterKeyTuple other = (CounterKeyTuple) obj; - if (this.msgType == other.msgType && - this.dpid == other.dpid && - this.l3type == other.l3type && - this.l4type == other.l4type) - return true; - return false; - } - - @Override - public int hashCode() { - final int prime = 283; - int result = 1; - result = prime * result + msgType.hashCode(); - result = prime * result + (int) (dpid.getLong() ^ (dpid.getLong() >>> 32)); - result = prime * result + l3type; - result = prime * result + l4type; - return result; - } - } - - /** - * Counter storage across all threads. These are periodically updated from the - * local per thread counters by the updateFlush method. - */ - protected ConcurrentHashMap<CounterKeyTuple, List<ICounter>> - pktinCounters = new ConcurrentHashMap<CounterKeyTuple, List<ICounter>>(); - protected ConcurrentHashMap<CounterKeyTuple, List<ICounter>> - pktoutCounters = new ConcurrentHashMap<CounterKeyTuple, List<ICounter>>(); - - /** - * Thread local counter stores - */ - protected final ThreadLocal<Map<CounterKeyTuple,MutableInt>> pktin_local_buffer = - new ThreadLocal<Map<CounterKeyTuple,MutableInt>>() { - @Override - protected Map<CounterKeyTuple,MutableInt> initialValue() { - return new HashMap<CounterKeyTuple,MutableInt>(); - } - }; - - protected final ThreadLocal<Map<CounterKeyTuple,MutableInt>> pktout_local_buffer = - new ThreadLocal<Map<CounterKeyTuple,MutableInt>>() { - @Override - protected Map<CounterKeyTuple,MutableInt> initialValue() { - return new HashMap<CounterKeyTuple,MutableInt>(); - } - }; - - /** - * A cache of counterName --> Counter used to retrieve counters quickly via - * string-counter-keys - */ - protected ConcurrentHashMap<String, CounterEntry> nameToCEIndex = - new ConcurrentHashMap<String, CounterEntry>(); - - /** - * Counter Categories grouped by network layers - * NetworkLayer -> CounterToCategories - */ - protected static Map<NetworkLayer, Map<String, List<String>>> layeredCategories = - new ConcurrentHashMap<NetworkLayer, Map<String, List<String>>> (); - - //******************************* - // ICounterStoreService - //******************************* - - @Override - public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth) { - if (((OFPacketIn)m).getData().length <= 0) { - return; - } - CounterKeyTuple countersKey = this.getCountersKey(sw, m, eth); - Map<CounterKeyTuple, MutableInt> pktin_buffer = this.pktin_local_buffer.get(); - MutableInt currval = pktin_buffer.get(countersKey); - - if (currval == null) { - this.createPacketInCounters(sw, m, eth); // create counters as side effect (if required) - currval = new MutableInt(); - pktin_buffer.put(countersKey, currval); - } - currval.increment(); - return; - } - - @Override - public void updatePktOutFMCounterStoreLocal(IOFSwitch sw, OFMessage m) { - CounterKeyTuple countersKey = this.getCountersKey(sw, m, null); - Map<CounterKeyTuple, MutableInt> pktout_buffer = this.pktout_local_buffer.get(); - MutableInt currval = pktout_buffer.get(countersKey); - - if (currval == null) { - this.getPktOutFMCounters(sw, m); // create counters as side effect (if required) - currval = new MutableInt(); - pktout_buffer.put(countersKey, currval); - } - currval.increment(); - return; - } - - @Override - public void updateFlush() { - Date date = new Date(); - Map<CounterKeyTuple, MutableInt> pktin_buffer = this.pktin_local_buffer.get(); - for (CounterKeyTuple key : pktin_buffer.keySet()) { - MutableInt currval = pktin_buffer.get(key); - int delta = currval.get(); - - if (delta > 0) { - List<ICounter> counters = this.pktinCounters.get(key); - if (counters != null) { - for (ICounter c : counters) { - c.increment(date, delta); - } - } - } - } - // We could do better "GC" of counters that have not been update "recently" - pktin_buffer.clear(); - - Map<CounterKeyTuple, MutableInt> pktout_buffer = this.pktout_local_buffer.get(); - for (CounterKeyTuple key : pktout_buffer.keySet()) { - MutableInt currval = pktout_buffer.get(key); - int delta = currval.get(); - - if (delta > 0) { - List<ICounter> counters = this.pktoutCounters.get(key); - if (counters != null) { - for (ICounter c : counters) { - c.increment(date, delta); - } - } - } - } - // We could do better "GC" of counters that have not been update "recently" - pktout_buffer.clear(); - } - - @Override - public ICounter createCounter(String key, CounterValue.CounterType type) { - CounterEntry ce; - ICounter c; - - c = SimpleCounter.createCounter(new Date(), type); - ce = new CounterEntry(); - ce.counter = c; - ce.title = key; - nameToCEIndex.putIfAbsent(key, ce); - - return nameToCEIndex.get(key).counter; - } - - @Override - public ICounter getCounter(String key) { - CounterEntry counter = nameToCEIndex.get(key); - if (counter != null) { - return counter.counter; - } else { - return null; - } - } - - /* (non-Javadoc) - * @see net.floodlightcontroller.counter.ICounterStoreService#getAll() - */ - @Override - public Map<String, ICounter> getAll() { - Map<String, ICounter> ret = new ConcurrentHashMap<String, ICounter>(); - for(Map.Entry<String, CounterEntry> counterEntry : this.nameToCEIndex.entrySet()) { - String key = counterEntry.getKey(); - ICounter counter = counterEntry.getValue().counter; - ret.put(key, counter); - } - return ret; - } - - @Override - public List<String> getAllCategories(String counterName, NetworkLayer layer) { - if (layeredCategories.containsKey(layer)) { - Map<String, List<String>> counterToCategories = layeredCategories.get(layer); - if (counterToCategories.containsKey(counterName)) { - return counterToCategories.get(counterName); - } - } - return null; - } - - /** - * Create a title based on switch ID, portID, vlanID, and counterName - * If portID is -1, the title represents the given switch only - * If portID is a non-negative number, the title represents the port on the given switch - */ - public static String createCounterName(String switchID, int portID, String counterName) { - if (portID < 0) { - return switchID + TitleDelimitor + counterName; - } else { - return switchID + TitleDelimitor + portID + TitleDelimitor + counterName; - } - } - - //******************************* - // Internal Methods - //******************************* - - protected CounterKeyTuple getCountersKey(IOFSwitch sw, OFMessage m, Ethernet eth) { - OFType mtype = m.getType(); - short l3type = 0; - byte l4type = 0; - - if (eth != null) { - l3type = eth.getEtherType(); - if (eth.getPayload() instanceof IPv4) { - IPv4 ipV4 = (IPv4)eth.getPayload(); - l4type = ipV4.getProtocol(); - } - } - return new CounterKeyTuple(mtype, sw.getId(), l3type, l4type); - } - - protected List<ICounter> createPacketInCounters(IOFSwitch sw, OFMessage m, Ethernet eth) { - /* If possible, find and return counters for this tuple */ - CounterKeyTuple countersKey = this.getCountersKey(sw, m, eth); - List<ICounter> counters = - this.pktinCounters.get(countersKey); - if (counters != null) { - return counters; - } - - /* - * Create the required counters - */ - counters = new ArrayList<ICounter>(); - - int l3type = eth.getEtherType() & 0xffff; - String switchIdHex = sw.getStringId(); - String etherType = String.format("%04x", eth.getEtherType()); - String packetName = m.getType().getClass().getName(); - packetName = packetName.substring(packetName.lastIndexOf('.')+1); - - // L2 Type - String l2Type = null; - if (eth.isBroadcast()) { - l2Type = BROADCAST; - } - else if (eth.isMulticast()) { - l2Type = MULTICAST; - } - else { - l2Type = UNICAST; - } - - /* - * Use alias for L3 type - * Valid EtherType must be greater than or equal to 0x0600 - * It is V1 Ethernet Frame if EtherType < 0x0600 - */ - if (l3type < 0x0600) { - etherType = "0599"; - } - if (TypeAliases.l3TypeAliasMap != null && - TypeAliases.l3TypeAliasMap.containsKey(etherType)) { - etherType = TypeAliases.l3TypeAliasMap.get(etherType); - } - else { - etherType = "L3_" + etherType; - } - - // overall controller packet counter names - String controllerCounterName = - CounterStore.createCounterName( - CONTROLLER_NAME, - -1, - packetName); - counters.add(createCounter(controllerCounterName, - CounterType.LONG)); - - String switchCounterName = - CounterStore.createCounterName( - switchIdHex, - -1, - packetName); - counters.add(createCounter(switchCounterName, - CounterType.LONG)); - - // L2 counter names - String controllerL2CategoryCounterName = - CounterStore.createCounterName( - CONTROLLER_NAME, - -1, - packetName, - l2Type, - NetworkLayer.L2); - counters.add(createCounter(controllerL2CategoryCounterName, - CounterType.LONG)); - - String switchL2CategoryCounterName = - CounterStore.createCounterName( - switchIdHex, - -1, - packetName, - l2Type, - NetworkLayer.L2); - counters.add(createCounter(switchL2CategoryCounterName, - CounterType.LONG)); - - // L3 counter names - String controllerL3CategoryCounterName = - CounterStore.createCounterName( - CONTROLLER_NAME, - -1, - packetName, - etherType, - NetworkLayer.L3); - counters.add(createCounter(controllerL3CategoryCounterName, - CounterType.LONG)); - - String switchL3CategoryCounterName = - CounterStore.createCounterName( - switchIdHex, - -1, - packetName, - etherType, - NetworkLayer.L3); - counters.add(createCounter(switchL3CategoryCounterName, - CounterType.LONG)); - - // L4 counters - if (eth.getPayload() instanceof IPv4) { - - // resolve protocol alias - IPv4 ipV4 = (IPv4)eth.getPayload(); - String l4name = String.format("%02x", ipV4.getProtocol()); - if (TypeAliases.l4TypeAliasMap != null && - TypeAliases.l4TypeAliasMap.containsKey(l4name)) { - l4name = TypeAliases.l4TypeAliasMap.get(l4name); - } - else { - l4name = "L4_" + l4name; - } - - // create counters - String controllerL4CategoryCounterName = - CounterStore.createCounterName( - CONTROLLER_NAME, - -1, - packetName, - l4name, - NetworkLayer.L4); - counters.add(createCounter(controllerL4CategoryCounterName, - CounterType.LONG)); - - String switchL4CategoryCounterName = - CounterStore.createCounterName( - switchIdHex, - -1, - packetName, - l4name, - NetworkLayer.L4); - counters.add(createCounter(switchL4CategoryCounterName, - CounterType.LONG)); - - } - - /* Add to map and return */ - this.pktinCounters.putIfAbsent(countersKey, counters); - return this.pktinCounters.get(countersKey); - } - - protected List<ICounter> getPktOutFMCounters(IOFSwitch sw, OFMessage m) { - /* If possible, find and return counters for this tuple */ - CounterKeyTuple countersKey = this.getCountersKey(sw, m, null); - List<ICounter> counters = - this.pktoutCounters.get(countersKey); - if (counters != null) { - return counters; - } - - /* - * Create the required counters - */ - counters = new ArrayList<ICounter>(); - - /* String values for names */ - String switchIdHex = sw.getStringId(); - String packetName = m.getType().getClass().getName(); - packetName = packetName.substring(packetName.lastIndexOf('.')+1); - - String controllerFMCounterName = - CounterStore.createCounterName( - CONTROLLER_NAME, - -1, - packetName); - counters.add(createCounter(controllerFMCounterName, - CounterValue.CounterType.LONG)); - - String switchFMCounterName = - CounterStore.createCounterName( - switchIdHex, - -1, - packetName); - counters.add(createCounter(switchFMCounterName, - CounterValue.CounterType.LONG)); - - /* Add to map and return */ - this.pktoutCounters.putIfAbsent(countersKey, counters); - return this.pktoutCounters.get(countersKey); - - } - - /** - * Create a title based on switch ID, portID, vlanID, counterName, and subCategory - * If portID is -1, the title represents the given switch only - * If portID is a non-negative number, the title represents the port on the given switch - * For example: PacketIns can be further categorized based on L2 etherType or L3 protocol - */ - protected static String createCounterName(String switchID, int portID, String counterName, - String subCategory, NetworkLayer layer) { - String fullCounterName = ""; - String groupCounterName = ""; - - if (portID < 0) { - groupCounterName = switchID + TitleDelimitor + counterName; - fullCounterName = groupCounterName + TitleDelimitor + subCategory; - } else { - groupCounterName = switchID + TitleDelimitor + portID + TitleDelimitor + counterName; - fullCounterName = groupCounterName + TitleDelimitor + subCategory; - } - - Map<String, List<String>> counterToCategories; - if (layeredCategories.containsKey(layer)) { - counterToCategories = layeredCategories.get(layer); - } else { - counterToCategories = new ConcurrentHashMap<String, List<String>> (); - layeredCategories.put(layer, counterToCategories); - } - - List<String> categories; - if (counterToCategories.containsKey(groupCounterName)) { - categories = counterToCategories.get(groupCounterName); - } else { - categories = new ArrayList<String>(); - counterToCategories.put(groupCounterName, categories); - } - - if (!categories.contains(subCategory)) { - categories.add(subCategory); - } - return fullCounterName; - } - - //******************************* - // IFloodlightProvider - //******************************* - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> services = - new ArrayList<Class<? extends IFloodlightService>>(1); - services.add(ICounterStoreService.class); - return services; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(ICounterStoreService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - // no-op, no dependencies - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - // no-op for now - } - - @Override - public void startUp(FloodlightModuleContext context) { - // no-op for now - } - -} diff --git a/src/main/java/net/floodlightcontroller/counter/CounterValue.java b/src/main/java/net/floodlightcontroller/counter/CounterValue.java deleted file mode 100644 index 1852d5cc5b7a4dc9e7fcd841c4c9764e67f66084..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/CounterValue.java +++ /dev/null @@ -1,102 +0,0 @@ -/** -* 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.counter; - -/** - * The class defines the counter value type and value - * - * @author Kanzhe - * - */ -public class CounterValue { - public enum CounterType { - LONG, - DOUBLE - } - - protected CounterType type; - protected long longValue; - protected double doubleValue; - - public CounterValue(CounterType type) { - this.type = CounterType.LONG; - this.longValue = 0; - this.doubleValue = 0.0; - } - - /** - * This method is only applicable to type long. - * Setter() should be used for type double - */ - public void increment(long delta) { - if (this.type == CounterType.LONG) { - this.longValue += delta; - } else { - throw new IllegalArgumentException("Invalid counter type. This counter is not a long type."); - } - } - - public void setLongValue(long value) { - if (this.type == CounterType.LONG) { - this.longValue = value; - } else { - throw new IllegalArgumentException("Invalid counter type. This counter is not a long type."); - } - } - - public void setDoubleValue(double value) { - if (this.type == CounterType.DOUBLE) { - this.doubleValue = value; - } else { - throw new IllegalArgumentException("Invalid counter type. This counter is not a double type."); - } - } - - public long getLong() { - if (this.type == CounterType.LONG) { - return this.longValue; - } else { - throw new IllegalArgumentException("Invalid counter type. This counter is not a long type."); - } - } - - public double getDouble() { - if (this.type == CounterType.DOUBLE) { - return this.doubleValue; - } else { - throw new IllegalArgumentException("Invalid counter type. This counter is not a double type."); - } - } - - - public CounterType getType() { - return this.type; - } - - public String toString() { - String ret = "{type: "; - if (this.type == CounterType.DOUBLE) { - ret += "Double" + ", value: " + this.doubleValue + "}"; - } else { - ret += "Long" + ", value: " + this.longValue + "}"; - } - return ret; - } - - -} diff --git a/src/main/java/net/floodlightcontroller/counter/ICounter.java b/src/main/java/net/floodlightcontroller/counter/ICounter.java deleted file mode 100644 index 0e31fdecd6a75419b9ccab92cd4a94e33f6f8cda..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/ICounter.java +++ /dev/null @@ -1,71 +0,0 @@ -/** -* 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. -**/ - -/** - * Simple interface for a counter whose value can be retrieved in several different - * time increments (last x seconds, minutes, hours, days) - */ -package net.floodlightcontroller.counter; - -import java.util.Date; - -/** - * @author kyle - * - */ -public interface ICounter { - - /** - * Most commonly used method - */ - public void increment(); - - /** - * Used primarily for flushing thread local updates - */ - public void increment(Date d, long delta); - - /** - * Counter value setter - */ - public void setCounter(Date d, CounterValue value); - - /** - * Return the most current value - */ - public Date getCounterDate(); - - /** - * Return the most current value - */ - public CounterValue getCounterValue(); - - /** - * Reset the value - */ - public void reset(Date d); - - - public static enum DateSpan { - REALTIME, - SECONDS, - MINUTES, - HOURS, - DAYS, - WEEKS - } -} diff --git a/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java b/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java deleted file mode 100644 index 79bf4548d6e6a6fc677eb3ebd5da3c2918808e55..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.counter; - -import java.util.List; -import java.util.Map; - -import org.projectfloodlight.openflow.protocol.OFMessage; - -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.counter.CounterStore.NetworkLayer; -import net.floodlightcontroller.packet.Ethernet; - -public interface ICounterStoreService extends IFloodlightService { - - public final static String CONTROLLER_NAME = "controller"; - public final static String TitleDelimitor = "__"; - - /** Broadcast and multicast */ - public final static String BROADCAST = "broadcast"; - public final static String MULTICAST = "multicast"; - public final static String UNICAST = "unicast"; - - /** L2 EtherType subCategories */ - public final static String L3ET_IPV4 = "L3_IPv4"; - - /** - * Update packetIn counters - * - * @param sw - * @param m - * @param eth - */ - public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth); - - /** - * This method can only be used to update packetOut and flowmod counters - * - * @param sw - * @param ofMsg - */ - public void updatePktOutFMCounterStoreLocal(IOFSwitch sw, OFMessage ofMsg); - - /** - * Flush Local Counter Updates - * - */ - public void updateFlush(); - - /** - * Retrieve a list of subCategories by counterName. - * null if nothing. - */ - public List<String> getAllCategories(String counterName, - NetworkLayer layer); - - /** - * Create a new ICounter and set the title. Note that the title must be - * unique, otherwise this will throw an IllegalArgumentException. - * - * @param key - * @param type - * @return - */ - public ICounter createCounter(String key, CounterValue.CounterType type); - - /** - * Retrieves a counter with the given title, or null if none can be found. - */ - public ICounter getCounter(String key); - - /** - * Returns an immutable map of title:counter with all of the counters in the store. - * - * (Note - this method may be slow - primarily for debugging/UI) - */ - public Map<String, ICounter> getAll(); -} diff --git a/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java b/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java deleted file mode 100644 index eff67dcacfa1a85b48c8fdaf820250046310912e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.counter; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.projectfloodlight.openflow.protocol.OFMessage; - -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.counter.CounterStore.NetworkLayer; -import net.floodlightcontroller.counter.CounterValue.CounterType; -import net.floodlightcontroller.packet.Ethernet; - -/** - * An ICounsterStoreService implementation that does nothing. - * This is used mainly for performance testing or if you don't - * want to use the counterstore. - * @author alexreimers - * - */ -public class NullCounterStore implements IFloodlightModule, - ICounterStoreService { - - private ICounter emptyCounter; - private List<String> emptyList; - private Map<String, ICounter> emptyMap; - - @Override - public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth) { - // no-op - } - - @Override - public void updatePktOutFMCounterStoreLocal(IOFSwitch sw, OFMessage ofMsg) { - // no-op - } - - @Override - public void updateFlush() { - // no-op - } - - @Override - public List<String> - getAllCategories(String counterName, NetworkLayer layer) { - return emptyList; - } - - @Override - public ICounter createCounter(String key, CounterType type) { - return emptyCounter; - } - - @Override - public ICounter getCounter(String key) { - return emptyCounter; - } - - @Override - public Map<String, ICounter> getAll() { - return emptyMap; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> services = - new ArrayList<Class<? extends IFloodlightService>>(1); - services.add(ICounterStoreService.class); - return services; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(ICounterStoreService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - // None, return null - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - emptyCounter = new SimpleCounter(new Date(), CounterType.LONG); - emptyList = new ArrayList<String>(); - emptyMap = new HashMap<String, ICounter>(); - } - - @Override - public void startUp(FloodlightModuleContext context) { - // no-op - } -} diff --git a/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java b/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java deleted file mode 100644 index dd0daf31797ace63ad0d1c8004ec8b016cb19dc9..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java +++ /dev/null @@ -1,129 +0,0 @@ -/** -* 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.counter; - -import java.util.Date; - - - -/** - * This is a simple counter implementation that doesn't support data series. - * The idea is that floodlight only keeps the realtime value for each counter, - * statd, a statistics collection daemon, samples counters at a user-defined interval - * and pushes the values to a database, which keeps time-based data series. - * @author Kanzhe - * - */ -public class SimpleCounter implements ICounter { - - protected CounterValue counter; - protected Date samplingTime; - protected Date startDate; - - /** - * Factory method to create a new counter instance. - * - * @param startDate - * @return - */ - public static ICounter createCounter(Date startDate, CounterValue.CounterType type) { - SimpleCounter cc = new SimpleCounter(startDate, type); - return cc; - } - - /** - * Factory method to create a copy of a counter instance. - * - * @param startDate - * @return - */ - public static ICounter createCounter(ICounter copy) { - if (copy == null || - copy.getCounterDate() == null || - copy.getCounterValue() == null) { - return null; - } - - SimpleCounter cc = new SimpleCounter(copy.getCounterDate(), - copy.getCounterValue().getType()); - cc.setCounter(copy.getCounterDate(), copy.getCounterValue()); - return cc; - } - - /** - * Protected constructor - use createCounter factory method instead - * @param startDate - */ - protected SimpleCounter(Date startDate, CounterValue.CounterType type) { - init(startDate, type); - } - - protected void init(Date startDate, CounterValue.CounterType type) { - this.startDate = startDate; - this.samplingTime = new Date(); - this.counter = new CounterValue(type); - } - - /** - * This is the key method that has to be both fast and very thread-safe. - */ - @Override - synchronized public void increment() { - this.increment(new Date(), 1); - } - - @Override - synchronized public void increment(Date d, long delta) { - this.samplingTime = d; - this.counter.increment(delta); - } - - @Override -synchronized public void setCounter(Date d, CounterValue value) { - this.samplingTime = d; - this.counter = value; - } - - /** - * This is the method to retrieve the current value. - */ - @Override - synchronized public CounterValue getCounterValue() { - return this.counter; - } - - /** - * This is the method to retrieve the last sampling time. - */ - @Override - synchronized public Date getCounterDate() { - return this.samplingTime; - } - - /** - * Reset value. - */ - @Override - synchronized public void reset(Date startDate) { - init(startDate, this.counter.getType()); - } - -} diff --git a/src/main/java/net/floodlightcontroller/counter/TypeAliases.java b/src/main/java/net/floodlightcontroller/counter/TypeAliases.java deleted file mode 100644 index b88c50256be82274bd1cb4aaf68392ed315a87b3..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/counter/TypeAliases.java +++ /dev/null @@ -1,206 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.counter; - -import java.util.HashMap; -import java.util.Map; - -/** - * Class to contain some statically initialized data - * @author readams - * - */ -public class TypeAliases { - protected static final Map<String,String> l3TypeAliasMap = - new HashMap<String, String>(); - static { - l3TypeAliasMap.put("0599", "L3_V1Ether"); - l3TypeAliasMap.put("0800", "L3_IPv4"); - l3TypeAliasMap.put("0806", "L3_ARP"); - l3TypeAliasMap.put("8035", "L3_RARP"); - l3TypeAliasMap.put("809b", "L3_AppleTalk"); - l3TypeAliasMap.put("80f3", "L3_AARP"); - l3TypeAliasMap.put("8100", "L3_802_1Q"); - l3TypeAliasMap.put("8137", "L3_Novell_IPX"); - l3TypeAliasMap.put("8138", "L3_Novell"); - l3TypeAliasMap.put("86dd", "L3_IPv6"); - l3TypeAliasMap.put("8847", "L3_MPLS_uni"); - l3TypeAliasMap.put("8848", "L3_MPLS_multi"); - l3TypeAliasMap.put("8863", "L3_PPPoE_DS"); - l3TypeAliasMap.put("8864", "L3_PPPoE_SS"); - l3TypeAliasMap.put("886f", "L3_MSFT_NLB"); - l3TypeAliasMap.put("8870", "L3_Jumbo"); - l3TypeAliasMap.put("889a", "L3_HyperSCSI"); - l3TypeAliasMap.put("88a2", "L3_ATA_Ethernet"); - l3TypeAliasMap.put("88a4", "L3_EtherCAT"); - l3TypeAliasMap.put("88a8", "L3_802_1ad"); - l3TypeAliasMap.put("88ab", "L3_Ether_Powerlink"); - l3TypeAliasMap.put("88cc", "L3_LLDP"); - l3TypeAliasMap.put("88cd", "L3_SERCOS_III"); - l3TypeAliasMap.put("88e5", "L3_802_1ae"); - l3TypeAliasMap.put("88f7", "L3_IEEE_1588"); - l3TypeAliasMap.put("8902", "L3_802_1ag_CFM"); - l3TypeAliasMap.put("8906", "L3_FCoE"); - l3TypeAliasMap.put("9000", "L3_Loop"); - l3TypeAliasMap.put("9100", "L3_Q_in_Q"); - l3TypeAliasMap.put("cafe", "L3_LLT"); - } - - protected static final Map<String,String> l4TypeAliasMap = - new HashMap<String, String>(); - static { - l4TypeAliasMap.put("00", "L4_HOPOPT"); - l4TypeAliasMap.put("01", "L4_ICMP"); - l4TypeAliasMap.put("02", "L4_IGAP_IGMP_RGMP"); - l4TypeAliasMap.put("03", "L4_GGP"); - l4TypeAliasMap.put("04", "L4_IP"); - l4TypeAliasMap.put("05", "L4_ST"); - l4TypeAliasMap.put("06", "L4_TCP"); - l4TypeAliasMap.put("07", "L4_UCL"); - l4TypeAliasMap.put("08", "L4_EGP"); - l4TypeAliasMap.put("09", "L4_IGRP"); - l4TypeAliasMap.put("0a", "L4_BBN"); - l4TypeAliasMap.put("0b", "L4_NVP"); - l4TypeAliasMap.put("0c", "L4_PUP"); - l4TypeAliasMap.put("0d", "L4_ARGUS"); - l4TypeAliasMap.put("0e", "L4_EMCON"); - l4TypeAliasMap.put("0f", "L4_XNET"); - l4TypeAliasMap.put("10", "L4_Chaos"); - l4TypeAliasMap.put("11", "L4_UDP"); - l4TypeAliasMap.put("12", "L4_TMux"); - l4TypeAliasMap.put("13", "L4_DCN"); - l4TypeAliasMap.put("14", "L4_HMP"); - l4TypeAliasMap.put("15", "L4_Packet_Radio"); - l4TypeAliasMap.put("16", "L4_XEROX_NS_IDP"); - l4TypeAliasMap.put("17", "L4_Trunk_1"); - l4TypeAliasMap.put("18", "L4_Trunk_2"); - l4TypeAliasMap.put("19", "L4_Leaf_1"); - l4TypeAliasMap.put("1a", "L4_Leaf_2"); - l4TypeAliasMap.put("1b", "L4_RDP"); - l4TypeAliasMap.put("1c", "L4_IRTP"); - l4TypeAliasMap.put("1d", "L4_ISO_TP4"); - l4TypeAliasMap.put("1e", "L4_NETBLT"); - l4TypeAliasMap.put("1f", "L4_MFE"); - l4TypeAliasMap.put("20", "L4_MERIT"); - l4TypeAliasMap.put("21", "L4_DCCP"); - l4TypeAliasMap.put("22", "L4_Third_Party_Connect"); - l4TypeAliasMap.put("23", "L4_IDPR"); - l4TypeAliasMap.put("24", "L4_XTP"); - l4TypeAliasMap.put("25", "L4_Datagram_Delivery"); - l4TypeAliasMap.put("26", "L4_IDPR"); - l4TypeAliasMap.put("27", "L4_TP"); - l4TypeAliasMap.put("28", "L4_ILTP"); - l4TypeAliasMap.put("29", "L4_IPv6_over_IPv4"); - l4TypeAliasMap.put("2a", "L4_SDRP"); - l4TypeAliasMap.put("2b", "L4_IPv6_RH"); - l4TypeAliasMap.put("2c", "L4_IPv6_FH"); - l4TypeAliasMap.put("2d", "L4_IDRP"); - l4TypeAliasMap.put("2e", "L4_RSVP"); - l4TypeAliasMap.put("2f", "L4_GRE"); - l4TypeAliasMap.put("30", "L4_DSR"); - l4TypeAliasMap.put("31", "L4_BNA"); - l4TypeAliasMap.put("32", "L4_ESP"); - l4TypeAliasMap.put("33", "L4_AH"); - l4TypeAliasMap.put("34", "L4_I_NLSP"); - l4TypeAliasMap.put("35", "L4_SWIPE"); - l4TypeAliasMap.put("36", "L4_NARP"); - l4TypeAliasMap.put("37", "L4_Minimal_Encapsulation"); - l4TypeAliasMap.put("38", "L4_TLSP"); - l4TypeAliasMap.put("39", "L4_SKIP"); - l4TypeAliasMap.put("3a", "L4_ICMPv6"); - l4TypeAliasMap.put("3b", "L4_IPv6_No_Next_Header"); - l4TypeAliasMap.put("3c", "L4_IPv6_Destination_Options"); - l4TypeAliasMap.put("3d", "L4_Any_host_IP"); - l4TypeAliasMap.put("3e", "L4_CFTP"); - l4TypeAliasMap.put("3f", "L4_Any_local"); - l4TypeAliasMap.put("40", "L4_SATNET"); - l4TypeAliasMap.put("41", "L4_Kryptolan"); - l4TypeAliasMap.put("42", "L4_MIT_RVDP"); - l4TypeAliasMap.put("43", "L4_Internet_Pluribus"); - l4TypeAliasMap.put("44", "L4_Distributed_FS"); - l4TypeAliasMap.put("45", "L4_SATNET"); - l4TypeAliasMap.put("46", "L4_VISA"); - l4TypeAliasMap.put("47", "L4_IP_Core"); - l4TypeAliasMap.put("4a", "L4_Wang_Span"); - l4TypeAliasMap.put("4b", "L4_Packet_Video"); - l4TypeAliasMap.put("4c", "L4_Backroom_SATNET"); - l4TypeAliasMap.put("4d", "L4_SUN_ND"); - l4TypeAliasMap.put("4e", "L4_WIDEBAND_Monitoring"); - l4TypeAliasMap.put("4f", "L4_WIDEBAND_EXPAK"); - l4TypeAliasMap.put("50", "L4_ISO_IP"); - l4TypeAliasMap.put("51", "L4_VMTP"); - l4TypeAliasMap.put("52", "L4_SECURE_VMTP"); - l4TypeAliasMap.put("53", "L4_VINES"); - l4TypeAliasMap.put("54", "L4_TTP"); - l4TypeAliasMap.put("55", "L4_NSFNET_IGP"); - l4TypeAliasMap.put("56", "L4_Dissimilar_GP"); - l4TypeAliasMap.put("57", "L4_TCF"); - l4TypeAliasMap.put("58", "L4_EIGRP"); - l4TypeAliasMap.put("59", "L4_OSPF"); - l4TypeAliasMap.put("5a", "L4_Sprite_RPC"); - l4TypeAliasMap.put("5b", "L4_Locus_ARP"); - l4TypeAliasMap.put("5c", "L4_MTP"); - l4TypeAliasMap.put("5d", "L4_AX"); - l4TypeAliasMap.put("5e", "L4_IP_within_IP"); - l4TypeAliasMap.put("5f", "L4_Mobile_ICP"); - l4TypeAliasMap.put("61", "L4_EtherIP"); - l4TypeAliasMap.put("62", "L4_Encapsulation_Header"); - l4TypeAliasMap.put("64", "L4_GMTP"); - l4TypeAliasMap.put("65", "L4_IFMP"); - l4TypeAliasMap.put("66", "L4_PNNI"); - l4TypeAliasMap.put("67", "L4_PIM"); - l4TypeAliasMap.put("68", "L4_ARIS"); - l4TypeAliasMap.put("69", "L4_SCPS"); - l4TypeAliasMap.put("6a", "L4_QNX"); - l4TypeAliasMap.put("6b", "L4_Active_Networks"); - l4TypeAliasMap.put("6c", "L4_IPPCP"); - l4TypeAliasMap.put("6d", "L4_SNP"); - l4TypeAliasMap.put("6e", "L4_Compaq_Peer_Protocol"); - l4TypeAliasMap.put("6f", "L4_IPX_in_IP"); - l4TypeAliasMap.put("70", "L4_VRRP"); - l4TypeAliasMap.put("71", "L4_PGM"); - l4TypeAliasMap.put("72", "L4_0_hop"); - l4TypeAliasMap.put("73", "L4_L2TP"); - l4TypeAliasMap.put("74", "L4_DDX"); - l4TypeAliasMap.put("75", "L4_IATP"); - l4TypeAliasMap.put("76", "L4_ST"); - l4TypeAliasMap.put("77", "L4_SRP"); - l4TypeAliasMap.put("78", "L4_UTI"); - l4TypeAliasMap.put("79", "L4_SMP"); - l4TypeAliasMap.put("7a", "L4_SM"); - l4TypeAliasMap.put("7b", "L4_PTP"); - l4TypeAliasMap.put("7c", "L4_ISIS"); - l4TypeAliasMap.put("7d", "L4_FIRE"); - l4TypeAliasMap.put("7e", "L4_CRTP"); - l4TypeAliasMap.put("7f", "L4_CRUDP"); - l4TypeAliasMap.put("80", "L4_SSCOPMCE"); - l4TypeAliasMap.put("81", "L4_IPLT"); - l4TypeAliasMap.put("82", "L4_SPS"); - l4TypeAliasMap.put("83", "L4_PIPE"); - l4TypeAliasMap.put("84", "L4_SCTP"); - l4TypeAliasMap.put("85", "L4_Fibre_Channel"); - l4TypeAliasMap.put("86", "L4_RSVP_E2E_IGNORE"); - l4TypeAliasMap.put("87", "L4_Mobility_Header"); - l4TypeAliasMap.put("88", "L4_UDP_Lite"); - l4TypeAliasMap.put("89", "L4_MPLS"); - l4TypeAliasMap.put("8a", "L4_MANET"); - l4TypeAliasMap.put("8b", "L4_HIP"); - l4TypeAliasMap.put("8c", "L4_Shim6"); - l4TypeAliasMap.put("8d", "L4_WESP"); - l4TypeAliasMap.put("8e", "L4_ROHC"); - } -} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java b/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java index 8da964aa2d4c203801de60af38a968aacd52ae30..f44ea7a17b06556cd60e360c254ba9c1e1003279 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java @@ -41,7 +41,7 @@ class CounterNode implements Iterable<DebugCounterImpl> { * root level and module level. */ private final DebugCounterImpl counter; - private final TreeMap<String,CounterNode> children = new TreeMap<>(); + private final TreeMap<String, CounterNode> children = new TreeMap<>(); /** * convert module name and counter hierarchy into list of @@ -50,22 +50,20 @@ class CounterNode implements Iterable<DebugCounterImpl> { * @param counterHierarchy * @return */ - static List<String> - getHierarchyElements(String moduleName, String counterHierarchy) { + static List<String> getHierarchyElements(String moduleName, String counterHierarchy) { DebugCounterServiceImpl.verifyModuleNameSanity(moduleName); List<String> ret = new ArrayList<>(); ret.add(moduleName); if (counterHierarchy == null || counterHierarchy.isEmpty()) { return ret; } - for (String element: counterHierarchy.split(QUOTED_SEP)) { + for (String element : counterHierarchy.split(QUOTED_SEP)) { ret.add(element); } return ret; } - private CounterNode(List<String> hierarchyElements, - DebugCounterImpl counter) { + private CounterNode(List<String> hierarchyElements, DebugCounterImpl counter) { super(); this.hierarchyElements = ImmutableList.copyOf(hierarchyElements); this.hierarchy = Joiner.on("/").join(hierarchyElements); @@ -83,14 +81,12 @@ class CounterNode implements Iterable<DebugCounterImpl> { /** verify that this node is the root */ private void verifyIsRoot() { if (hierarchyElements.size() != 0) { - throw new IllegalStateException("This not is not the root. Can " + throw new IllegalStateException("This is not the root. Can " + "only call addCounter() on the root node. Current node: " + hierarchy); } } - - /** * return the full hierarchy as string, including module name */ diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java index 2e2fe499f8ff592cfc9837091f0cd22fbe6be4b2..ae245deb872bdafa03f0b94a19091618ac76c4fc 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java @@ -12,11 +12,12 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.annotation.Nonnull; import javax.annotation.concurrent.GuardedBy; -import org.projectfloodlight.core.IShutdownListener; -import org.projectfloodlight.core.IShutdownService; +import net.floodlightcontroller.core.IShutdownListener; +import net.floodlightcontroller.core.IShutdownService; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -79,7 +80,12 @@ public class DebugCounterServiceImpl implements IFloodlightModule, IDebugCounter verifyModuleNameSanity(moduleName); verifyStringSanity(counterHierarchy, "counterHierarchy"); if (counterDescription == null) { - throw new Exception("counterDescription must not be null"); + try { + throw new Exception("counterDescription must not be null"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(e.getMessage()); + } } if (metaData == null) { // somebody passing in a null array. sigh. @@ -200,10 +206,9 @@ public class DebugCounterServiceImpl implements IFloodlightModule, IDebugCounter @Override public void floodlightIsShuttingDown() { for (DebugCounterResource counter: getAllCounterValues()) { - logger.info("Module {} counterHierarchy {} value {}", + logger.info("Module {} counterHierarchy {} value " + counter.getCounterValue(), counter.getModuleName(), - counter.getCounterHierarchy(), - counter.getCounterValue()); + counter.getCounterHierarchy()); } } } diff --git a/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java b/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java index 3540519639911602788f965e52d2793f27d0f737..36a19d548fe60bda68455064224fdb4574ad089d 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java @@ -7,10 +7,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.projectfloodlight.core.module.FloodlightModuleContext; -import org.projectfloodlight.core.module.FloodlightModuleException; -import org.projectfloodlight.core.module.IFloodlightModule; -import org.projectfloodlight.core.module.IFloodlightService; +import net.floodlightcontroller.core.module.FloodlightModuleContext; +import net.floodlightcontroller.core.module.FloodlightModuleException; +import net.floodlightcontroller.core.module.IFloodlightModule; +import net.floodlightcontroller.core.module.IFloodlightService; public class MockDebugCounterService implements IFloodlightModule, IDebugCounterService { diff --git a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResource.java b/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResource.java deleted file mode 100644 index 3dd35bc07502d4db5f9b16ebe4da8978379b5497..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResource.java +++ /dev/null @@ -1,382 +0,0 @@ -package net.floodlightcontroller.debugcounter.web; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.debugcounter.DebugCounter.DebugCounterInfo; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType; - -/** - * Web interface for Debug Counters - * - * @author Saurav - */ -public class DebugCounterResource extends DebugCounterResourceBase { - protected static Logger logger = - LoggerFactory.getLogger(DebugCounterResource.class); - - /** - * The output JSON model that contains the counter information - */ - public class DebugCounterInfoOutput { - protected class DCInfo { - private final Long counterValue; - private final CounterType counterType; - private final String counterDesc; - private final boolean enabled; - private final String counterHierarchy; - private final String moduleName; - private final String[] metaData; - - DCInfo(DebugCounterInfo dci) { - this.moduleName = dci.getCounterInfo().getModuleName(); - this.counterHierarchy = dci.getCounterInfo().getCounterHierarchy(); - this.counterDesc = dci.getCounterInfo().getCounterDesc(); - this.metaData = dci.getCounterInfo().getMetaData(); - this.enabled = dci.getCounterInfo().isEnabled(); - this.counterType = dci.getCounterInfo().getCtype(); - this.counterValue = dci.getCounterValue(); - } - - public Long getCounterValue() { - return counterValue; - } - public CounterType getCounterType() { - return counterType; - } - - public String getCounterDesc() { - return counterDesc; - } - - public boolean isEnabled() { - return enabled; - } - - public String getCounterHierarchy() { - return counterHierarchy; - } - - public String getModuleName() { - return moduleName; - } - - public String[] getMetaData() { - return metaData; - } - - } - // complete counter information - null if only names are requested or - // if an error occurs - public Map<String, DCInfo> counterMap; - // list of names could be just moduleNames or counter hierarchical names - // for a specific module - public List<String> names; - - public String error; - - DebugCounterInfoOutput(boolean getList) { - if (!getList) { - counterMap = new HashMap<String, DCInfo>(); - } - error = null; - } - public Map<String, DCInfo> getCounterMap() { - return counterMap; - } - - public String getError() { - return error; - } - - public List<String> getNames() { - return names; - } - - } - - public enum Option { - ALL, ONE_MODULE, MODULE_COUNTER_HIERARCHY, ERROR_BAD_MODULE_NAME, - ERROR_BAD_PARAM, - ERROR_BAD_MODULE_COUNTER_NAME - } - - public static class CounterPost { - public Boolean reset; - public Boolean enable; - - public Boolean getReset() { - return reset; - } - public void setReset(Boolean reset) { - this.reset = reset; - } - public Boolean getEnable() { - return enable; - } - public void setEnable(Boolean enable) { - this.enable = enable; - } - } - - public static class ResetOutput { - String error = null; - - public String getError() { - return error; - } - public void setError(String error) { - this.error = error; - } - } - - /** - * Reset or enable/disable counters - * - * If using curl: - * curl -X POST -d DATA -H "Content-Type: application/json" URL - * where DATA must be one of the following: - * {\"reset\":true} to reset counters - * {\"enable\":true} to enable counter - * {\"enable\":false} to disable counter - * and URL must be in one of the following forms: - * "http://{controller-hostname}:8080/wm/debugcounter/{param1}/{param2}/{param3}/{param4} - * - * {param1} can be null, 'all' or the name of a module {moduleName}. - * {param2}/{param3}/{param4} refer to hierarchical counter names. - * - * The Reset command will reset the counter specified as well as all counters - * in the hierarchical levels below. For example, if a counter hierarchy exists - * as switch/00:00:00:00:01:02:03:04/pktin/drops, then a reset command with just - * the moduleName (param1=switch) and counterHierarchy (param2=00:00:00:00:01:02:03:04) - * will reset all counters for that switch. Continuing the example - - * for a counterHierarchy (param2=00:00:00:00:01:02:03:04 and param3=pktin), the reset - * command will remove all pktin counters for that switch. - * - * The enable/disable command will ONLY disable a specific counter (and only if - * that counter is of CounterType.ON_DEMAND) - * It will not enable/disable counters at any other hierarchical level. - * - */ - @Post - public ResetOutput postHandler(CounterPost postData) { - ResetOutput output = new ResetOutput(); - Option choice = Option.ERROR_BAD_PARAM; - String param1 = (String)getRequestAttributes().get("param1"); - String param2 = (String)getRequestAttributes().get("param2"); - String param3 = (String)getRequestAttributes().get("param3"); - String param4 = (String)getRequestAttributes().get("param4"); - String moduleName = ""; - - if (param1 == null) { - moduleName = "all"; - choice = Option.ALL; - } else if (param1.equals("all")) { - moduleName = "all"; - choice = Option.ALL; - } else { - moduleName = param1; - } - - String counterHierarchy = ""; - if (param2 != null) { - counterHierarchy += param2; - if (param3 != null) { - counterHierarchy += "/" + param3; - if (param4 != null) { - counterHierarchy += "/" + param4; - } - } - } - - if (!moduleName.equals("all") && counterHierarchy.equals("")) { - // only module name specified - boolean isRegistered = debugCounter.containsModuleName(param1); - if (isRegistered) { - choice = Option.ONE_MODULE; - } else { - choice = Option.ERROR_BAD_MODULE_NAME; - } - } else if (!moduleName.equals("all") && !counterHierarchy.equals("")) { - // both module and counter names specified - boolean isRegistered = debugCounter. - containsModuleCounterHierarchy(moduleName, counterHierarchy); - if (isRegistered) { - choice = Option.MODULE_COUNTER_HIERARCHY; - } else { - choice = Option.ERROR_BAD_MODULE_COUNTER_NAME; - } - } - - boolean reset = false; - boolean turnOnOff = false; - if (postData.getReset() != null && postData.getReset()) { - reset = true; - } - if (postData.getEnable() != null) { - turnOnOff = true; - } - - switch (choice) { - case ALL: - if (reset) debugCounter.resetAllCounters(); - break; - case ONE_MODULE: - if (reset) debugCounter.resetAllModuleCounters(moduleName); - break; - case MODULE_COUNTER_HIERARCHY: - if (reset) - debugCounter.resetCounterHierarchy(moduleName, counterHierarchy); - else if (turnOnOff && postData.getEnable()) - debugCounter.enableCtrOnDemand(moduleName, counterHierarchy); - else if (turnOnOff && !postData.getEnable()) - debugCounter.disableCtrOnDemand(moduleName, counterHierarchy); - break; - case ERROR_BAD_MODULE_NAME: - output.error = "Module name has no corresponding registered counters"; - break; - case ERROR_BAD_MODULE_COUNTER_NAME: - output.error = "Counter not registered"; - break; - case ERROR_BAD_PARAM: - output.error = "Bad param"; - } - - return output; - } - - /** - * Return the debug counter data for the get rest-api call - * - * URI must be in one of the following forms: - * "http://{controller-hostname}:8080/wm/debugcounter/{param1}/{param2}/{param3}/{param4}" - * - * where {param1} must be one of (no quotes): - * null if nothing is given then by default all - * module names are returned for which counters - * have been registered - * "all" returns value/info on all counters. - * "{moduleName}" returns value/info on all counters for - * the specified module 'moduelName'. - * & {param2}/{param3}/{param4} refer to hierarchical counter names. - * eg. 00:00:00:00:01:02:03:04/pktin/drops - * where leaving out any of the params returns - * all counters in the hierarchical level below. - * So giving just the switch dpid will fetch - * all counters for that switch. - * A special case => if param2 is null, then - * all hierarchical counterNames are returned - * for the given moduleName (in param1) - */ - @Get - public DebugCounterInfoOutput handleCounterInfoQuery() { - DebugCounterInfoOutput output; - Option choice = Option.ERROR_BAD_PARAM; - String param1 = (String)getRequestAttributes().get("param1"); - String param2 = (String)getRequestAttributes().get("param2"); - String param3 = (String)getRequestAttributes().get("param3"); - String param4 = (String)getRequestAttributes().get("param4"); - - if (param1 == null) { - output = new DebugCounterInfoOutput(true); - return listCounters(output); - } else if (param1.equals("all")) { - output = new DebugCounterInfoOutput(false); - populateCounters(debugCounter.getAllCounterValues(), output); - return output; - } - - output = new DebugCounterInfoOutput(false); - String counterHierarchy = ""; - if (param2 == null) { - // param2 is null -- return list of counternames for param1 - boolean isRegistered = debugCounter.containsModuleName(param1); - output = new DebugCounterInfoOutput(true); - if (isRegistered) { - return listCounters(param1, output); - } else { - choice = Option.ERROR_BAD_MODULE_NAME; - } - } else if (param2.equals("all")) { - // get all counter info for a single module - boolean isRegistered = debugCounter.containsModuleName(param1); - if (isRegistered) { - choice = Option.ONE_MODULE; - } else { - choice = Option.ERROR_BAD_MODULE_NAME; - } - } else { - counterHierarchy += param2; - if (param3 != null) { - counterHierarchy += "/" + param3; - if (param4 != null) { - counterHierarchy += "/" + param4; - } - } - boolean isRegistered = debugCounter. - containsModuleCounterHierarchy(param1, counterHierarchy); - if (isRegistered) { - choice = Option.MODULE_COUNTER_HIERARCHY; - } else { - choice = Option.ERROR_BAD_MODULE_COUNTER_NAME; - } - } - - switch (choice) { - case ONE_MODULE: - populateCounters(debugCounter.getModuleCounterValues(param1), output); - break; - case MODULE_COUNTER_HIERARCHY: - populateCounters(debugCounter.getCounterHierarchy(param1, counterHierarchy), - output); - break; - case ERROR_BAD_MODULE_NAME: - output.error = "Module name is not registered for debug-counters"; - break; - case ERROR_BAD_MODULE_COUNTER_NAME: - output.error = "Counter not registered"; - break; - case ERROR_BAD_PARAM: - default: - output.error = "Bad param"; - } - - return output; - } - - private DebugCounterInfoOutput listCounters(String moduleName, - DebugCounterInfoOutput output) { - output.names = debugCounter.getModuleCounterList(moduleName); - return output; - } - - private DebugCounterInfoOutput listCounters(DebugCounterInfoOutput output) { - output.names = debugCounter.getModuleList(); - return output; - } - - private void populateSingleCounter(DebugCounterInfo debugCounterInfo, - DebugCounterInfoOutput output) { - if (debugCounterInfo != null) - output.counterMap.put(debugCounterInfo.getCounterInfo(). - getModuleCounterHierarchy(), - output.new DCInfo(debugCounterInfo)); - } - - private void populateCounters(List<DebugCounterInfo> counterValues, - DebugCounterInfoOutput output) { - for (DebugCounterInfo dci : counterValues) { - populateSingleCounter(dci, output); - } - } - - - -} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResourceBase.java b/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResourceBase.java deleted file mode 100644 index 48e469bc689b9c3cf44c2dcdd0c80caa428796b2..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResourceBase.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.floodlightcontroller.debugcounter.web; - -import net.floodlightcontroller.debugcounter.IDebugCounterService; - -import org.restlet.resource.ResourceException; -import org.restlet.resource.ServerResource; - -public class DebugCounterResourceBase extends ServerResource { - - protected IDebugCounterService debugCounter; - - @Override - protected void doInit() throws ResourceException { - super.doInit(); - debugCounter = (IDebugCounterService)getContext().getAttributes(). - get(IDebugCounterService.class.getCanonicalName()); - } -} diff --git a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterRoutable.java b/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterRoutable.java deleted file mode 100644 index 55ba5bacf95b0257556bd5483a561ca40fa0a8cb..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterRoutable.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.floodlightcontroller.debugcounter.web; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -import net.floodlightcontroller.restserver.RestletRoutable; - -public class DebugCounterRoutable implements RestletRoutable { - - @Override - public String basePath() { - return "/wm/debugcounter"; - } - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/{param1}/{param2}/{param3}/{param4}/", DebugCounterResource.class); - router.attach("/{param1}/{param2}/{param3}/{param4}", DebugCounterResource.class); - router.attach("/{param1}/{param2}/{param3}/", DebugCounterResource.class); - router.attach("/{param1}/{param2}/{param3}", DebugCounterResource.class); - router.attach("/{param1}/{param2}/", DebugCounterResource.class); - router.attach("/{param1}/{param2}", DebugCounterResource.class); - router.attach("/{param1}/", DebugCounterResource.class); - router.attach("/{param1}", DebugCounterResource.class); - router.attach("/", DebugCounterResource.class); - router.attach("", DebugCounterResource.class); - return router; - } -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java b/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java deleted file mode 100644 index f1a6db33dd37dfb69d3635855a774e3b14ae3e5b..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java +++ /dev/null @@ -1,95 +0,0 @@ -package net.floodlightcontroller.debugevent; - - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.concurrent.LinkedBlockingDeque; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CircularBuffer<T> implements Iterable<T>{ - protected static Logger log = LoggerFactory.getLogger(CircularBuffer.class); - private final LinkedBlockingDeque<T> buffer; - - public CircularBuffer(int capacity) { - this.buffer = new LinkedBlockingDeque<T>(capacity); - } - - /** - * Adding an element to the circular buffer implies adding the element to - * the tail of the deque. In doing so, if the capacity of the buffer has - * been exhausted, then the deque's head should be removed to preserve the - * circular nature of the buffer. A LinkedBlockingDeque is used because of its - * concurrent nature and the fact that adding to tail and removing from head are - * both O(1) operations. The removed head is returned to the caller for reuse. - * - * @param e the element to be added - * @return removed element (for reuse) or null - */ - public T add(T e) { - T oldE = null; - while (!buffer.offerLast(e)) { - oldE = buffer.poll(); - } - return oldE; - } - - /** - * The basic idea here is that an ArrayList has been passed in, which may or may not - * have a size bigger that the actual number of elements that are meant to - * be flushed to the Circular Buffer. Thus the 'uptoIndex' parameter specifies - * the number of elements that need to be flushed starting from index 0. - * Note that after flushing, the circular buffer may return a memory unit (of type T) - * for reuse in the list, if the circular buffer popped off memory to preserve - * its circular nature. Or it may just return null if nothing was popped off. - * Either way, the list that is returned by this method, is of the SAME SIZE - * as the list passed in, as ArrayLists can hold null elements. The only difference - * is that the list returned will have elements that reference old popped-off memory - * from the circular-buffer or null. - * - * @param elist the ArrayList to flush into the circular buffer. - * @param uptoIndex flush starting from index 0 upto but not including - * index 'uptoIndex'. - * @return the 'elist' passed in with members now pointing to - * to null or old-memory for reuse. The returned list - * if of the same size as 'elist'. - */ - public ArrayList<T> addAll(ArrayList<T> elist, int uptoIndex) { - if (uptoIndex > elist.size()) { - log.error("uptoIndex is greater than elist size .. aborting addAll"); - return elist; - } - for (int index=0; index < uptoIndex; index++) { - T e = elist.get(index); - if (e != null) { - elist.set(index, add(e)); - } - } - return elist; - } - - /** - * Returns an iterator over the elements in the circular buffer in proper sequence. - * The elements will be returned in order from most-recent to oldest. - * The returned Iterator is a "weakly consistent" iterator that will never - * throw ConcurrentModificationException, and guarantees to traverse elements - * as they existed upon construction of the iterator, and may (but is not - * guaranteed to) reflect any modifications subsequent to construction. - */ - @Override - public Iterator<T> iterator() { - return buffer.descendingIterator(); - } - - public int size() { - return buffer.size(); - } - - /** - * Atomically removes all elements in the circular buffer - */ - public void clear() { - buffer.clear(); - } -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java deleted file mode 100644 index 36e01d7c96ed549d593dc90ad1d5927d4d7d3a87..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java +++ /dev/null @@ -1,513 +0,0 @@ -package net.floodlightcontroller.debugevent; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.debugevent.web.DebugEventRoutable; -import net.floodlightcontroller.restserver.IRestApiService; - -import com.google.common.collect.Sets; -/** - * This class implements a central store for all events used for debugging the - * system. The basic idea is that given the functionality provided by this class, - * it should be unnecessary to resort to scraping through system DEBUG/TRACE logs - * to understand behavior in a running system. - * - * @author Saurav - */ -public class DebugEvent implements IFloodlightModule, IDebugEventService { - protected static Logger log = LoggerFactory.getLogger(DebugEvent.class); - - /** - * Every registered event type gets an event id, the value for which is obtained - * while holding the lock. - */ - protected int eventIdCounter = 0; - protected Object eventIdLock = new Object(); - - private static final long MIN_FLUSH_DELAY = 100; //ms - private static final int PCT_LOCAL_CAP = 10; // % of global capacity - private static final int MIN_LOCAL_CAPACITY = 10; //elements - - /** - * Event Information - */ - public class EventInfo { - int eventId; - boolean enabled; - int bufferCapacity; - EventType etype; - String eventDesc; - String eventName; - String moduleName; - String moduleEventName; - Class<?> eventClass; - String[] metaData; - - public EventInfo(int eventId, boolean enabled, int bufferCapacity, - EventType etype, Class<?> eventClass, String eventDesc, - String eventName, String moduleName, String... metaData) { - this.enabled = enabled; - this.eventId = eventId; - this.bufferCapacity = bufferCapacity; - this.etype = etype; - this.eventClass = eventClass; - this.eventDesc = eventDesc; - this.eventName = eventName; - this.moduleName = moduleName; - this.moduleEventName = moduleName + "/" + eventName; - this.metaData = metaData; - } - - public int getEventId() { return eventId; } - public boolean isEnabled() { return enabled; } - public int getBufferCapacity() { return bufferCapacity; } - public EventType getEtype() { return etype; } - public String getEventDesc() { return eventDesc; } - public String getEventName() { return eventName; } - public String getModuleName() { return moduleName; } - public String getModuleEventName() { return moduleEventName; } - public String[] getMetaData() { return metaData; } - } - - //****************** - // Global stores - //****************** - - /** - * Event history for a particular event-id is stored in a circular buffer - */ - protected class DebugEventHistory { - EventInfo einfo; - CircularBuffer<Event> eventBuffer; - - public DebugEventHistory(EventInfo einfo, int capacity) { - this.einfo = einfo; - this.eventBuffer = new CircularBuffer<Event>(capacity); - } - } - - /** - * Global storage for all event types and their corresponding event buffers. - * A particular event type is accessed by directly indexing into the array - * with the corresponding event-id. - */ - protected DebugEventHistory[] allEvents = - new DebugEventHistory[MAX_EVENTS]; - - /** - * Global storage for all event ids registered for a module. The map is indexed - * by the module name and event name and returns the event-ids that correspond to the - * event types registered by that module (for example module 'linkdiscovery' - * may register events that have ids 0 and 1 that correspond to link up/down - * events, and receiving malformed LLDP packets, respectively). - */ - protected ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>> - moduleEvents = new ConcurrentHashMap<String, - ConcurrentHashMap<String, Integer>>(); - - /** - * A collection of event ids that are currently enabled for logging - */ - protected Set<Integer> currentEvents = Collections.newSetFromMap( - new ConcurrentHashMap<Integer,Boolean>()); - - //****************** - // Thread local stores - //****************** - - /** - * Thread local storage for events - */ - protected class LocalEventHistory { - int nextIndex; - int maxCapacity; - boolean enabled; - ArrayList<Event> eventList; - long lastFlushTime; - boolean flushNow; - - public LocalEventHistory(boolean enabled, int maxCapacity, boolean flushNow) { - this.nextIndex = 0; - this.maxCapacity = maxCapacity; - this.enabled = enabled; - this.eventList = new ArrayList<Event>(); - this.flushNow = flushNow; - } - } - - /** - * Thread local event buffers used for maintaining event history local to - * a thread. Eventually this locally maintained information is flushed - * into the global event buffers. - */ - protected final ThreadLocal<LocalEventHistory[]> threadlocalEvents = - new ThreadLocal<LocalEventHistory[]>() { - @Override - protected LocalEventHistory[] initialValue() { - return new LocalEventHistory[MAX_EVENTS]; - } - }; - - /** - * Thread local cache for event-ids that are currently active. - */ - protected final ThreadLocal<Set<Integer>> threadlocalCurrentEvents = - new ThreadLocal<Set<Integer>>() { - @Override - protected Set<Integer> initialValue() { - return new HashSet<Integer>(); - } - }; - - //******************************* - // IEventUpdater - //******************************* - - protected class EventUpdaterImpl<T> implements IEventUpdater<T> { - private final int eventId; - - public EventUpdaterImpl(int evId) { - this.eventId = evId; - } - - @Override - public void updateEventNoFlush(Object event) { - if (!validEventId()) return; - updateEvent(eventId, false, event); - } - - @Override - public void updateEventWithFlush(Object event) { - if (!validEventId()) return; - updateEvent(eventId, true, event); - } - - private boolean validEventId() { - if (eventId < 0 || eventId >= MAX_EVENTS) { - throw new IllegalStateException(); - } - return true; - } - - } - - //******************************* - // IDebugEventService - //******************************* - - @Override - public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName, - String eventDescription, EventType et, - Class<T> eventClass, int bufferCapacity, - String... metaData) throws MaxEventsRegistered { - int eventId = -1; - synchronized (eventIdLock) { - eventId = Integer.valueOf(eventIdCounter++); - } - if (eventId > MAX_EVENTS-1) { - throw new MaxEventsRegistered(); - } - - // register event id for moduleName - if (!moduleEvents.containsKey(moduleName)) { - moduleEvents.put(moduleName, new ConcurrentHashMap<String, Integer>()); - } - if (!moduleEvents.get(moduleName).containsKey(eventName)) { - moduleEvents.get(moduleName).put(eventName, new Integer(eventId)); - } else { - int existingEventId = moduleEvents.get(moduleName).get(eventName); - log.error("Duplicate event registration for moduleName {} eventName {}", - moduleName, eventName); - return new EventUpdaterImpl<T>(existingEventId); - } - - // create storage for event-type - boolean enabled = (et == EventType.ALWAYS_LOG) ? true : false; - EventInfo ei = new EventInfo(eventId, enabled, bufferCapacity, - et, eventClass, eventDescription, eventName, - moduleName, metaData); - allEvents[eventId] = new DebugEventHistory(ei, bufferCapacity); - if (enabled) { - currentEvents.add(eventId); - } - - return new EventUpdaterImpl<T>(eventId); - } - - private void updateEvent(int eventId, boolean flushNow, Object eventData) { - if (eventId < 0 || eventId > MAX_EVENTS-1) return; - - LocalEventHistory[] thishist = this.threadlocalEvents.get(); - if (thishist[eventId] == null) { - // seeing this event for the first time in this thread - create local - // store by consulting global store - DebugEventHistory de = allEvents[eventId]; - if (de != null) { - boolean enabled = de.einfo.enabled; - int localCapacity = de.einfo.bufferCapacity * PCT_LOCAL_CAP/ 100; - if (localCapacity < 10) localCapacity = MIN_LOCAL_CAPACITY; - thishist[eventId] = new LocalEventHistory(enabled, localCapacity, - flushNow); - if (enabled) { - Set<Integer> thisset = this.threadlocalCurrentEvents.get(); - thisset.add(eventId); - } - } else { - log.error("updateEvent seen locally for event {} but no global" - + "storage exists for it yet .. not updating", eventId); - return; - } - } - - // update local store if enabled locally for updating - LocalEventHistory le = thishist[eventId]; - if (le.enabled) { - long timestamp = System.currentTimeMillis(); - long thisthread = Thread.currentThread().getId(); - String thisthreadname = Thread.currentThread().getName(); - if (le.nextIndex < le.eventList.size()) { - if (le.eventList.get(le.nextIndex) == null) { - le.eventList.set(le.nextIndex, new Event(timestamp, thisthread, - thisthreadname, - eventData)); - } else { - Event e = le.eventList.get(le.nextIndex); - e.timestamp = timestamp; - e.threadId = thisthread; - e.eventData = eventData; - } - } else { - le.eventList.add(new Event(timestamp, thisthread, thisthreadname, eventData)); - } - le.nextIndex++; - - if (le.nextIndex >= le.maxCapacity || le.flushNow) { - // flush this buffer now - DebugEventHistory de = allEvents[eventId]; - if (de.einfo.enabled) { - le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex); - } else { - // global buffer is disabled - don't flush, disable locally - le.enabled = false; - Set<Integer> thisset = this.threadlocalCurrentEvents.get(); - thisset.remove(eventId); - } - le.nextIndex = 0; - le.lastFlushTime = timestamp; - } - } - } - - @Override - public void flushEvents() { - LocalEventHistory[] thishist = this.threadlocalEvents.get(); - Set<Integer> thisset = this.threadlocalCurrentEvents.get(); - long timestamp = System.currentTimeMillis(); - ArrayList<Integer> temp = new ArrayList<Integer>(); - - for (int eventId : thisset) { - LocalEventHistory le = thishist[eventId]; - if (le != null && le.nextIndex > 0 && - (le.flushNow || (timestamp - le.lastFlushTime) > MIN_FLUSH_DELAY)) { - // flush this buffer now - DebugEventHistory de = allEvents[eventId]; - if (de.einfo.enabled) { - le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex); - } else { - // global buffer is disabled - don't flush, disable locally - le.enabled = false; - temp.add(eventId); - } - le.nextIndex = 0; - le.lastFlushTime = timestamp; - } - } - for (int eId : temp) - thisset.remove(eId); - - // sync thread local currently enabled set of eventIds with global set. - Sets.SetView<Integer> sv = Sets.difference(currentEvents, thisset); - for (int eventId : sv) { - if (thishist[eventId] != null) { - thishist[eventId].enabled = true; - thisset.add(eventId); - } - } - - } - - @Override - public boolean containsModuleEventName(String moduleName, String eventName) { - if (!moduleEvents.containsKey(moduleName)) return false; - if (moduleEvents.get(moduleName).containsKey(eventName)) return true; - return false; - } - - @Override - public boolean containsModuleName(String moduleName) { - return moduleEvents.containsKey(moduleName); - } - - @Override - public List<DebugEventInfo> getAllEventHistory() { - List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>(); - for (Map<String, Integer> modev : moduleEvents.values()) { - for (int eventId : modev.values()) { - DebugEventHistory de = allEvents[eventId]; - if (de != null) { - List<Map<String,String>> ret = new ArrayList<Map<String,String>>(); - for (Event e : de.eventBuffer) { - ret.add(e.getFormattedEvent(de.einfo.eventClass, - de.einfo.moduleEventName)); - } - moduleEventList.add(new DebugEventInfo(de.einfo, ret)); - } - } - } - return moduleEventList; - } - - @Override - public List<DebugEventInfo> getModuleEventHistory(String moduleName) { - if (!moduleEvents.containsKey(moduleName)) return Collections.emptyList(); - List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>(); - for (int eventId : moduleEvents.get(moduleName).values()) { - DebugEventHistory de = allEvents[eventId]; - if (de != null) { - List<Map<String,String>> ret = new ArrayList<Map<String,String>>(); - for (Event e : de.eventBuffer) { - ret.add(e.getFormattedEvent(de.einfo.eventClass, - de.einfo.moduleEventName)); - } - moduleEventList.add(new DebugEventInfo(de.einfo, ret)); - } - } - return moduleEventList; - } - - @Override - public DebugEventInfo getSingleEventHistory(String moduleName, String eventName, - int last) { - if (!moduleEvents.containsKey(moduleName)) return null; - Integer eventId = moduleEvents.get(moduleName).get(eventName); - if (eventId == null) return null; - DebugEventHistory de = allEvents[eventId]; - if (de != null) { - int num = 1; - List<Map<String,String>> ret = new ArrayList<Map<String,String>>(); - for (Event e : de.eventBuffer) { - if (num > last) - break; - Map<String, String> temp = e.getFormattedEvent(de.einfo.eventClass, - de.einfo.moduleEventName); - temp.put("#", String.valueOf(num++)); - ret.add(temp); - } - return new DebugEventInfo(de.einfo, ret); - } - return null; - } - - @Override - public void resetAllEvents() { - for (Map<String, Integer> eventMap : moduleEvents.values()) { - for (Integer evId : eventMap.values()) { - allEvents[evId].eventBuffer.clear(); - } - } - } - - @Override - public void resetAllModuleEvents(String moduleName) { - if (!moduleEvents.containsKey(moduleName)) return; - Map<String, Integer> modEvents = moduleEvents.get(moduleName); - for (Integer evId : modEvents.values()) { - allEvents[evId].eventBuffer.clear(); - } - } - - @Override - public void resetSingleEvent(String moduleName, String eventName) { - if (!moduleEvents.containsKey(moduleName)) return; - Integer eventId = moduleEvents.get(moduleName).get(eventName); - if (eventId == null) return; - DebugEventHistory de = allEvents[eventId]; - if (de != null) { - de.eventBuffer.clear(); - } - } - - @Override - public List<String> getModuleList() { - List<String> el = new ArrayList<String>(); - el.addAll(moduleEvents.keySet()); - return el; - } - - @Override - public List<String> getModuleEventList(String moduleName) { - if (!moduleEvents.containsKey(moduleName)) - return Collections.emptyList(); - List<String> el = new ArrayList<String>(); - el.addAll(moduleEvents.get(moduleName).keySet()); - return el; - } - - //******************************* - // IFloodlightModule - //******************************* - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IDebugEventService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - Map<Class<? extends IFloodlightService>, IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); - m.put(IDebugEventService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - ArrayList<Class<? extends IFloodlightService>> deps = - new ArrayList<Class<? extends IFloodlightService>>(); - deps.add(IRestApiService.class); - return deps; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - } - - @Override - public void startUp(FloodlightModuleContext context) - throws FloodlightModuleException { - IRestApiService restService = - context.getServiceImpl(IRestApiService.class); - restService.addRestletRoutable(new DebugEventRoutable()); - DebugEventAppender.setDebugEventServiceImpl(this); - } - -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java index 3429675d7b60829c0fa18b9e106ac1cd09b75534..ea44f9af18a800fde6e84742cf28965bb8878b89 100644 --- a/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java +++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java @@ -3,28 +3,32 @@ package net.floodlightcontroller.debugevent; import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType; import net.floodlightcontroller.debugevent.IDebugEventService.EventType; -import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered; + import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.UnsynchronizedAppenderBase; public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> { static IDebugEventService debugEvent; - static IEventUpdater<WarnErrorEvent> evWarnError; - static Thread debugEventRegistryTask = new Thread() { - @Override - public void run() { - while(DebugEventAppender.debugEvent == null) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - return; + static IEventCategory<WarnErrorEvent> evWarnError; + static final Thread debugEventRegistryTask; + static { + debugEventRegistryTask = new Thread() { + @Override + public void run() { + while (DebugEventAppender.debugEvent == null) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + return; + } } + // safe to register debugEvent + registerDebugEventQueue(); } - //safe to register debugEvent - registerDebugEventQueue(); - } - }; + }; + debugEventRegistryTask.setDaemon(true); + } @Override public void start() { @@ -32,16 +36,17 @@ public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> { super.start(); } - public static void setDebugEventServiceImpl(IDebugEventService debugEvent) { + public static void + setDebugEventServiceImpl(IDebugEventService debugEvent) { DebugEventAppender.debugEvent = debugEvent; // It is now ok to register an event Q - but letting this thread go // since it was called from a startUp() routine } /** - * The logging system calls append for every log message. This method filters - * out the WARN and ERROR message and adds to a debug event queue that can - * be accessed via cli or rest-api or gui. + * The logging system calls append for every log message. This method + * filters out the WARN and ERROR message and adds to a debug event queue + * that can be accessed via cli or rest-api or gui. */ @Override protected void append(E eventObject) { @@ -50,24 +55,26 @@ public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> { } if (evWarnError != null) { ILoggingEvent ev = ((ILoggingEvent) eventObject); - if (ev.getLevel().equals(Level.ERROR) || ev.getLevel().equals(Level.WARN)) { - evWarnError.updateEventWithFlush( - new WarnErrorEvent(ev.getFormattedMessage(), ev.getLevel(), - ev.getThreadName(), ev.getLoggerName())); + if (ev.getLevel().equals(Level.ERROR) + || ev.getLevel().equals(Level.WARN)) { + evWarnError + .newEventWithFlush(new WarnErrorEvent(ev.getFormattedMessage(), + ev.getLevel(), + ev.getThreadName(), + ev.getLoggerName())); } } } private static void registerDebugEventQueue() { - try { - evWarnError = debugEvent.registerEvent("net.floodlightcontroller.core", - "warn-error-queue", - "all WARN and ERROR logs", - EventType.ALWAYS_LOG, WarnErrorEvent.class, - 100); - } catch (MaxEventsRegistered e) { - e.printStackTrace(); - } + evWarnError = debugEvent.buildEvent(WarnErrorEvent.class) + .setModuleName("net.floodlightcontroller.core") + .setEventName("warn-error-queue") + .setEventDescription("all WARN and ERROR logs") + .setEventType(EventType.ALWAYS_LOG) + .setBufferCapacity(100) + .setAckable(false) + .register(); } @@ -78,14 +85,15 @@ public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> { @EventColumn(name = "level", description = EventFieldType.OBJECT) Level level; - @EventColumn(name = "threadName", description = EventFieldType.STRING) + @EventColumn(name = "threadName", + description = EventFieldType.STRING) String threadName; @EventColumn(name = "logger", description = EventFieldType.OBJECT) String logger; - public WarnErrorEvent(String message, Level level, String threadName, - String logger) { + public WarnErrorEvent(String message, Level level, + String threadName, String logger) { this.message = message; this.level = level; this.threadName = threadName; diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java index 7e71d5490faacbd4710d4d9b8411fedc9bc5c9eb..ff93c405e9d1ab1c274701de11bbadd3c3d21b1e 100644 --- a/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java +++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java @@ -4,9 +4,8 @@ import java.util.List; import javax.annotation.concurrent.Immutable; -import org.projectfloodlight.db.data.annotation.DBProperty; -import org.projectfloodlight.debugevent.DebugEventService.EventInfo; -import org.projectfloodlight.debugevent.IDebugEventService.EventType; +import net.floodlightcontroller.debugevent.DebugEventService.EventInfo; +import net.floodlightcontroller.debugevent.IDebugEventService.EventType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,52 +60,42 @@ public class DebugEventResource { this.events = ImmutableList.copyOf(events); } - @DBProperty(value = "enabled") public boolean isEnabled() { return enabled; } - @DBProperty(value = "buffer-capacity") public int getBufferCapacity() { return bufferCapacity; } - @DBProperty(value = "etype") public EventType getEtype() { return etype; } - @DBProperty(value = "event-desc") public String getEventDesc() { return eventDesc; } - @DBProperty(value = "event-name") public String getEventName() { return eventName; } - @DBProperty(value = "module-name") public String getModuleName() { return moduleName; } - @DBProperty(value = "num-of-events") public int getNumOfEvents() { return numOfEvents; } - @DBProperty(value = "ackable") public boolean isAckable() { return ackable; } - @DBProperty(value = "event") public List<EventResource> getEvents() { return events; } - @DBProperty(value = "event-id") public int getEventId() { return eventId; } diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java index 113a42002ffdd43a35c903a029024e599d302bf4..47a4ad77bd3358f24f574056c080ddc7b7ea2139 100644 --- a/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java +++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java @@ -14,12 +14,13 @@ import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import org.projectfloodlight.core.IShutdownListener; -import org.projectfloodlight.core.IShutdownService; -import org.projectfloodlight.core.module.FloodlightModuleContext; -import org.projectfloodlight.core.module.IFloodlightModule; -import org.projectfloodlight.core.module.IFloodlightService; -import org.projectfloodlight.debugevent.DebugEventResource.EventInfoResource; +import net.floodlightcontroller.core.IShutdownListener; +import net.floodlightcontroller.core.IShutdownService; +import net.floodlightcontroller.core.module.FloodlightModuleContext; +import net.floodlightcontroller.core.module.IFloodlightModule; +import net.floodlightcontroller.core.module.IFloodlightService; +import net.floodlightcontroller.debugevent.DebugEventResource.EventInfoResource; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/net/floodlightcontroller/debugevent/Event.java b/src/main/java/net/floodlightcontroller/debugevent/Event.java index 1eb76a1a80b0b1227e1867d27f2bb07849358ae7..d3a0cc2d4041e12a45025f4f503041aa4ef9d258 100644 --- a/src/main/java/net/floodlightcontroller/debugevent/Event.java +++ b/src/main/java/net/floodlightcontroller/debugevent/Event.java @@ -1,221 +1,122 @@ package net.floodlightcontroller.debugevent; -import java.lang.ref.SoftReference; import java.lang.reflect.Field; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import net.floodlightcontroller.debugevent.DebugEventService.EventCategory; +import net.floodlightcontroller.debugevent.EventResource.EventResourceBuilder; +import net.floodlightcontroller.debugevent.EventResource.Metadata; import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.packet.IPv4; - -import org.projectfloodlight.openflow.protocol.OFFlowMod; -import org.projectfloodlight.openflow.protocol.OFFlowModFlags; -import org.projectfloodlight.openflow.protocol.OFFlowModify; -import org.projectfloodlight.openflow.util.HexString; +/** + * Generic Event class used to store different categories of events. + * DebugEventService uses this class to store each Event instance. + * Each {@link EventCategory} has a different object of type <b>EventClass</b>. + * This is used internally for all DebugEvent processing. For display via REST + * and CLI, it is transformed to {@link EventResource} object. + */ public class Event { - long timestamp; - long threadId; - String threadName; - Object eventData; - private Map<String, String> returnMap; - public Event(long timestamp, long threadId, String threadName, Object eventData) { - super(); - this.timestamp = timestamp; + private final long eventInstanceId; + private volatile boolean acked; + private final long timeMs; + private final long threadId; + private final String threadName; + private final Object eventData; + + public Event(long timeMs, long threadId, String threadName, + Object eventData, long eventInstanceId) { + this.timeMs = timeMs; this.threadId = threadId; this.threadName = threadName; this.eventData = eventData; + this.eventInstanceId = eventInstanceId; + this.acked = false; } - public long getTimestamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; + public long getTimeMs() { + return timeMs; } public long getThreadId() { return threadId; } - public void setThreadId(long threadId) { - this.threadId = threadId; - } - public String getThreadName() { return threadName; } - public void setThreadName(String threadName) { - this.threadName = threadName; - } - public Object geteventData() { return eventData; } - public void seteventData(Object eventData) { - this.eventData = eventData; + public long getEventInstanceId() { + return eventInstanceId; + } + + public boolean isAcked() { + return acked; + } + + public void setAcked(boolean acked) { + this.acked = acked; } @Override public String toString() { - return "Event [timestamp=" + timestamp + ", threadId=" + threadId - + ", eventData=" + eventData.toString() + "]"; + return "Event [eventInstanceId=" + eventInstanceId + ", acked=" + + acked + ", timeMs=" + timeMs + ", threadId=" + threadId + + ", threadName=" + threadName + ", eventData=" + eventData + + "]"; } - public Map<String, String> getFormattedEvent(Class<?> eventClass, String moduleEventName) { + public EventResource getFormattedEvent(Class<?> eventClass, + String moduleEventName) { if (eventClass == null || !eventClass.equals(eventData.getClass())) { - returnMap = new HashMap<String, String>(); - returnMap.put("Error", "null event data or event-class does not match event-data"); - return returnMap; + EventResourceBuilder edb = new EventResourceBuilder(); + edb.dataFields.add(new Metadata("Error", + "null event data or event-class does not match event-data")); + return edb.build(); } - // return cached value if there is one - if (returnMap != null) - return returnMap; - - returnMap = new HashMap<String, String>(); - returnMap.put("Timestamp", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") - .format(timestamp)); - returnMap.put("Thread Id", String.valueOf(threadId)); - returnMap.put("Thread Name", String.valueOf(threadName)); - customFormat(eventClass, eventData, returnMap); - return returnMap; + + EventResourceBuilder edb = new EventResourceBuilder(); + edb.setTimeStamp(timeMs); + edb.setThreadId(threadId); + edb.setThreadName(threadName); + edb.setModuleEventName(moduleEventName); + edb.setEventInstanceId(eventInstanceId); + edb.setAcked(acked); + customFormat(eventClass, eventData, edb); + return edb.build(); } + @SuppressWarnings("unchecked") private void customFormat(Class<?> clazz, Object eventData, - Map<String, String> retMap) { + EventResourceBuilder eventDataBuilder) { for (Field f : clazz.getDeclaredFields()) { EventColumn ec = f.getAnnotation(EventColumn.class); if (ec == null) continue; f.setAccessible(true); try { - Object obj = f.get(eventData); - - switch(ec.description()) { - case DPID: - retMap.put(ec.name(), HexString.toHexString((Long) obj)); - break; - case MAC: - retMap.put(ec.name(), HexString.toHexString((Long) obj, 6)); - break; - case IPv4: - retMap.put(ec.name(), IPv4.fromIPv4Address((Integer) obj)); - break; - case FLOW_MOD_FLAGS: - int flags = (Integer)obj; - StringBuilder builder = new StringBuilder(); - if (flags == 0) { - builder.append("None"); - } - else { //towirevalue - if ((flags & OFFlowModFlags.SEND_FLOW_REM.) != 0) { - builder.append("SEND_FLOW_REM "); - } - if ((flags & OFFlowMod.OFPFF_CHECK_OVERLAP) != 0) { - builder.append("CHECK_OVERLAP "); - } - if ((flags & OFFlowMod.OFPFF_EMERG) != 0) { - builder.append("EMERG "); - } - } - retMap.put(ec.name(), builder.toString()); - break; - case LIST_IPV4: - @SuppressWarnings("unchecked") - List<Integer> ipv4Addresses = (List<Integer>)obj; - StringBuilder ipv4AddressesStr = new StringBuilder(); - if (ipv4Addresses.size() == 0) { - ipv4AddressesStr.append("--"); - } else { - for (Integer ipv4Addr : ipv4Addresses) { - ipv4AddressesStr.append(IPv4.fromIPv4Address(ipv4Addr.intValue())); - ipv4AddressesStr.append(" "); - } - } - retMap.put(ec.name(), ipv4AddressesStr.toString()); - break; - case LIST_ATTACHMENT_POINT: - @SuppressWarnings("unchecked") - List<SwitchPort> aps = (List<SwitchPort>)obj; - StringBuilder apsStr = new StringBuilder(); - if (aps.size() == 0) { - apsStr.append("--"); - } else { - for (SwitchPort ap : aps) { - apsStr.append(HexString.toHexString(ap.getSwitchDPID())); - apsStr.append("/"); - apsStr.append(ap.getPort()); - apsStr.append(" "); - } - } - retMap.put(ec.name(), apsStr.toString()); - break; - case LIST_OBJECT: - @SuppressWarnings("unchecked") - List<Object> obl = (List<Object>)obj; - StringBuilder sbldr = new StringBuilder(); - if (obl.size() == 0) { - sbldr.append("--"); - } else { - for (Object o : obl) { - sbldr.append(o.toString()); - sbldr.append(" "); - } - } - retMap.put(ec.name(), sbldr.toString()); - break; - case SREF_LIST_OBJECT: - @SuppressWarnings("unchecked") - SoftReference<List<Object>> srefListObj = - (SoftReference<List<Object>>)obj; - List<Object> ol = srefListObj.get(); - if (ol != null) { - StringBuilder sb = new StringBuilder(); - if (ol.size() == 0) { - sb.append("--"); - } else { - for (Object o : ol) { - sb.append(o.toString()); - sb.append(" "); - } - } - retMap.put(ec.name(), sb.toString()); - } else { - retMap.put(ec.name(), "-- reference not available --"); - } - break; - case SREF_OBJECT: - @SuppressWarnings("unchecked") - SoftReference<Object> srefObj = (SoftReference<Object>)obj; - if (srefObj == null) { - retMap.put(ec.name(), "--"); - } else { - Object o = srefObj.get(); - if (o != null) { - retMap.put(ec.name(), o.toString()); - } else { - retMap.put(ec.name(), - "-- reference not available --"); - } - } - break; - case STRING: - case OBJECT: - case PRIMITIVE: - default: - retMap.put(ec.name(), obj.toString()); + Object obj = f.get(eventData); + @SuppressWarnings("rawtypes") + CustomFormatter cf = DebugEventService.customFormatter.get(ec.description()); + + if (cf == null) { + throw new IllegalArgumentException( + "CustomFormatter for " + + ec.description() + + " does not exist."); + } else { + cf.customFormat(obj, ec.name(), eventDataBuilder); } } catch (ClassCastException e) { - retMap.put("Error", e.getMessage()); + eventDataBuilder.dataFields.add(new Metadata("Error", + e.getMessage())); } catch (IllegalArgumentException e) { - retMap.put("Error", e.getMessage()); + eventDataBuilder.dataFields.add(new Metadata("Error", + e.getMessage())); } catch (IllegalAccessException e) { - retMap.put("Error", e.getMessage()); + eventDataBuilder.dataFields.add(new Metadata("Error", + e.getMessage())); } } } diff --git a/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java b/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java deleted file mode 100644 index 00cea123269b5aadef0d5438889ffaf00b24c2fb..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.floodlightcontroller.debugevent; - -/** - * EventCategory is used to log events for pre-registered events. - */ -public interface IEventCategory<T> { - - /** - * Logs the instance of the event thread-locally. Flushing to the global - * circular buffer for this event is delayed resulting in better - * performance. This method should typically be used by those events that - * happen in the packet processing pipeline - * - * @param event - * an instance of the user-defined event of type T - */ - public void newEventNoFlush(T event); - - /** - * Logs the instance of the event thread-locally and immediated flushes to - * the global circular buffer for this event. This method should typically - * be used by those events that happen outside the packet processing - * pipeline - * - * @param event - * an instance of the user-defined event of type T - */ - public void newEventWithFlush(T event); - -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java b/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java deleted file mode 100644 index 7aec38f44aa1b7637c00a180226761ecc30511a7..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.floodlightcontroller.debugevent; - -/** - * eventUPdater is used to log events for pre-registered events. - */ -public interface IEventUpdater<T> { - - /** - * Logs the instance of the event thread-locally. Flushing to the global - * circular buffer for this event is delayed resulting in better performance. - * This method should typically be used by those events that happen in the - * packet processing pipeline - * - * @param event an instance of the user-defined event of type T - */ - public void updateEventNoFlush(T event); - - /** - * Logs the instance of the event thread-locally and immediated flushes - * to the global circular buffer for this event. - * This method should typically be used by those events that happen - * outside the packet processing pipeline - * - * @param event an instance of the user-defined event of type T - */ - public void updateEventWithFlush(T event); - - - -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java index 7f0676a556f37be26f259dfd883e8191c932b5a6..cf43d81469f2369c48f68cae97fa9a5d3b37339d 100644 --- a/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java +++ b/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java @@ -124,5 +124,4 @@ public class MockDebugEventService implements IFloodlightModule, IDebugEventServ throws FloodlightModuleException { } - } diff --git a/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java deleted file mode 100644 index 7d479ea6df9242691e7b23e9dcfc72cab8b9a340..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java +++ /dev/null @@ -1,135 +0,0 @@ -package net.floodlightcontroller.debugevent; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; - -public class NullDebugEvent implements IFloodlightModule, IDebugEventService { - - - @Override - public void flushEvents() { - - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleServices() { - Collection<Class<? extends IFloodlightService>> services = - new ArrayList<Class<? extends IFloodlightService>>(1); - services.add(IDebugEventService.class); - return services; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(IDebugEventService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - - } - - @Override - public void startUp(FloodlightModuleContext context) - throws FloodlightModuleException { - - } - - @Override - public boolean containsModuleEventName(String moduleName, String eventName) { - return false; - } - - @Override - public boolean containsModuleName(String moduleName) { - return false; - } - - @Override - public List<DebugEventInfo> getAllEventHistory() { - return Collections.emptyList(); - } - - @Override - public List<DebugEventInfo> getModuleEventHistory(String param) { - return Collections.emptyList(); - } - - @Override - public DebugEventInfo getSingleEventHistory(String moduleName, String eventName, - int last) { - return null; - } - - @Override - public void resetAllEvents() { - - } - - @Override - public void resetAllModuleEvents(String moduleName) { - - } - - @Override - public void resetSingleEvent(String moduleName, String eventName) { - - } - - @Override - public <T> IEventUpdater<T> - registerEvent(String moduleName, String eventName, - String eventDescription, EventType eventType, - Class<T> eventClass, int bufferCapacity, - String... metaData) throws MaxEventsRegistered { - return new NullEventImpl<T>(); - } - - public class NullEventImpl<T> implements IEventUpdater<T> { - - @Override - public void updateEventNoFlush(Object event) { - - } - - @Override - public void updateEventWithFlush(Object event) { - - } - - } - - @Override - public List<String> getModuleList() { - return Collections.emptyList(); - } - - @Override - public List<String> getModuleEventList(String moduleName) { - return Collections.emptyList(); - } - -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java deleted file mode 100644 index a3f06ceaf3f7ab615ae062d9e4d35d02117eb4e9..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java +++ /dev/null @@ -1,322 +0,0 @@ -package net.floodlightcontroller.debugevent.web; - - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.debugevent.IDebugEventService.DebugEventInfo; -import net.floodlightcontroller.debugevent.IDebugEventService.EventType; - -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Web interface for Debug Events - * - * @author Saurav - */ -public class DebugEventResource extends DebugEventResourceBase { - protected static Logger logger = - LoggerFactory.getLogger(DebugEventResource.class); - - /** - * The output JSON model that contains the counter information - */ - public static class DebugEventInfoOutput { - protected class DEInfo { - private final boolean enabled; - private final int bufferCapacity; - private final EventType eventType; - private final String eventDesc; - private final String eventName; - private final String moduleName; - private final String[] metaData; - private final List<Map<String,String>> eventHistory; - - DEInfo(DebugEventInfo dei) { - this.moduleName = dei.getEventInfo().getModuleName(); - this.eventName = dei.getEventInfo().getEventName(); - this.eventDesc = dei.getEventInfo().getEventDesc(); - this.metaData = dei.getEventInfo().getMetaData(); - this.enabled = dei.getEventInfo().isEnabled(); - this.eventType = dei.getEventInfo().getEtype(); - this.bufferCapacity = dei.getEventInfo().getBufferCapacity(); - this.eventHistory = dei.getEvents(); - } - public boolean isEnabled() { - return enabled; - } - public int getBufferCapacity() { - return bufferCapacity; - } - public String getEventDesc() { - return eventDesc; - } - public String getEventName() { - return eventName; - } - public String getModuleName() { - return moduleName; - } - public String[] getMetaData() { - return metaData; - } - public EventType getEventType() { - return eventType; - } - public List<Map<String,String>> getEventHistory() { - return eventHistory; - } - - } - - public Map<String, DEInfo> eventMap = null; - public List<String> names = null; - public String error = null; - - DebugEventInfoOutput(boolean getList) { - if (!getList) { - eventMap = new HashMap<String, DEInfo>(); - } - } - public Map<String, DEInfo> getEventMap() { - return eventMap; - } - public List<String> getNames() { - return names; - } - public String getError() { - return error; - } - - } - - public enum Option { - ALL, ONE_MODULE, ONE_MODULE_EVENT, ERROR_BAD_MODULE_NAME, ERROR_BAD_PARAM, - ERROR_BAD_MODULE_EVENT_NAME - } - - public static class DebugEventPost { - public Boolean reset; - - public Boolean getReset() { - return reset; - } - public void setReset(Boolean reset) { - this.reset = reset; - } - } - - public static class ResetOutput { - String error = null; - - public String getError() { - return error; - } - public void setError(String error) { - this.error = error; - } - } - - /** - * Reset events - * - * If using curl: - * curl -X POST -d {\"reset\":true} -H "Content-Type: application/json" URL - * where URL must be in one of the following forms for resetting registered events: - * "http://{controller-hostname}:8080/wm/debugevent/ - * "http://{controller-hostname}:8080/wm/debugevent/{param1} - * "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2} - * - * Not giving {param1} will reset all events - * {param1} can be 'all' or the name of a module. The former case will reset - * all events, while the latter will reset all events for the moduleName (if - * param2 is null).{param2} must be an eventName for the given moduleName to - * reset a specific event. - */ - @Post - public ResetOutput postHandler(DebugEventPost postData) { - ResetOutput output = new ResetOutput(); - String param1 = (String)getRequestAttributes().get("param1"); - String param2 = (String)getRequestAttributes().get("param2"); - - if (postData.getReset() != null && postData.getReset()) { - Option choice = Option.ERROR_BAD_PARAM; - - if (param1 == null) { - param1 = "all"; - choice = Option.ALL; - } else if (param1.equals("all")) { - choice = Option.ALL; - } else if (param2 == null) { - boolean isRegistered = debugEvent.containsModuleName(param1); - if (isRegistered) { - choice = Option.ONE_MODULE; - } else { - choice = Option.ERROR_BAD_MODULE_NAME; - } - } else { - // differentiate between disabled and non-existing events - boolean isRegistered = debugEvent.containsModuleEventName(param1, param2); - if (isRegistered) { - choice = Option.ONE_MODULE_EVENT; - } else { - choice = Option.ERROR_BAD_MODULE_EVENT_NAME; - } - } - - switch (choice) { - case ALL: - debugEvent.resetAllEvents(); - break; - case ONE_MODULE: - debugEvent.resetAllModuleEvents(param1); - break; - case ONE_MODULE_EVENT: - debugEvent.resetSingleEvent(param1, param2); - break; - case ERROR_BAD_MODULE_NAME: - output.error = "Module name has no corresponding registered events"; - break; - case ERROR_BAD_MODULE_EVENT_NAME: - output.error = "Event not registered"; - break; - case ERROR_BAD_PARAM: - output.error = "Bad param"; - } - } - - return output; - - } - - /** - * Return the debug event data for the get rest-api call - * - * URL must be in one of the following forms for retrieving a list - * moduleNames "http://{controller-hostname}:8080/wm/debugevent/ - * counterNames "http://{controller-hostname}:8080/wm/debugevent/{moduleName} - * - * URL must be in one of the following forms for retrieving event data: - * "http://{controller-hostname}:8080/wm/debugevent/{param1} - * "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2} - * - * where {param1} must be one of (no quotes): - * null if nothing is given then by default the list - * of all moduleNames is returned for which - * events have been registered - * "all" can return value/info on all active events - * but is currently disallowed - * "{moduleName}" returns value/info on events for the specified module - * depending on the value of param2 - * and {param2} must be one of (no quotes): - * null returns all eventNames registered for the - * given moduleName (in param1) - * "{eventName}" returns value/info for specific event if it is active. - * - */ - @Get("json") - public DebugEventInfoOutput handleEventInfoQuery() { - Option choice = Option.ERROR_BAD_PARAM; - DebugEventInfoOutput output; - String laststr = getQueryValue("last"); - int last = Integer.MAX_VALUE; - try { - if (laststr != null) - last = Integer.valueOf(laststr); - if (last < 1) last = Integer.MAX_VALUE; - } catch (NumberFormatException e) { - output = new DebugEventInfoOutput(false); - output.error = "Expected an integer requesting last X events;" + - " received " + laststr; - return output; - } - String param1 = (String)getRequestAttributes().get("param1"); - String param2 = (String)getRequestAttributes().get("param2"); - - if (param1 == null) { - output = new DebugEventInfoOutput(true); - return listEvents(output); - } else if (param1.equals("all")) { - output = new DebugEventInfoOutput(false); - //populateEvents(debugEvent.getAllEventHistory(), output); - output.error = "Cannot retrieve all events - please select a specific event"; - return output; - } - - if (param2 == null) { - output = new DebugEventInfoOutput(true); - boolean isRegistered = debugEvent.containsModuleName(param1); - if (isRegistered) { - return listEvents(param1, output); - } else { - choice = Option.ERROR_BAD_MODULE_NAME; - } - } else if (param2.equals("all")) { - output = new DebugEventInfoOutput(false); - //choice = Option.ONE_MODULE; - output.error = "Cannot retrieve all events - please select a specific event"; - return output; - } else { - // differentiate between disabled and non-existing events - boolean isRegistered = debugEvent.containsModuleEventName(param1, param2); - if (isRegistered) { - choice = Option.ONE_MODULE_EVENT; - } else { - choice = Option.ERROR_BAD_MODULE_EVENT_NAME; - } - } - - output = new DebugEventInfoOutput(false); - switch (choice) { - case ONE_MODULE: - populateEvents(debugEvent.getModuleEventHistory(param1), output); - break; - case ONE_MODULE_EVENT: - populateSingleEvent(debugEvent.getSingleEventHistory(param1, param2, last), - output); - break; - case ERROR_BAD_MODULE_NAME: - output.error = "Module name has no corresponding registered events"; - break; - case ERROR_BAD_MODULE_EVENT_NAME: - output.error = "Event not registered"; - break; - case ERROR_BAD_PARAM: - default: - output.error = "Bad param"; - } - - return output; - } - - private DebugEventInfoOutput listEvents(DebugEventInfoOutput output) { - output.names = debugEvent.getModuleList(); - return output; - } - - private DebugEventInfoOutput listEvents(String moduleName, - DebugEventInfoOutput output) { - output.names = debugEvent.getModuleEventList(moduleName); - return output; - } - - private void populateSingleEvent(DebugEventInfo singleEventHistory, - DebugEventInfoOutput output) { - if (singleEventHistory != null) { - output.eventMap.put(singleEventHistory.getEventInfo().getModuleEventName(), - output.new DEInfo(singleEventHistory)); - } - } - - private void populateEvents(List<DebugEventInfo> eventHistory, - DebugEventInfoOutput output) { - if (eventHistory != null) { - for (DebugEventInfo de : eventHistory) - populateSingleEvent(de, output); - } - } -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java deleted file mode 100644 index 964deeb7467bf70d1b8e6e3578743ded26415558..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.floodlightcontroller.debugevent.web; - - -import net.floodlightcontroller.debugevent.IDebugEventService; - -import org.restlet.resource.ResourceException; -import org.restlet.resource.ServerResource; - -public class DebugEventResourceBase extends ServerResource{ - protected IDebugEventService debugEvent; - - @Override - protected void doInit() throws ResourceException { - super.doInit(); - debugEvent = (IDebugEventService)getContext().getAttributes(). - get(IDebugEventService.class.getCanonicalName()); - } -} diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java deleted file mode 100644 index d4ee7c6fd1b21ccaf63ad588c16993fcb91f6ed0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.floodlightcontroller.debugevent.web; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -import net.floodlightcontroller.restserver.RestletRoutable; - -public class DebugEventRoutable implements RestletRoutable { - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/{param1}/{param2}/", DebugEventResource.class); - router.attach("/{param1}/{param2}", DebugEventResource.class); - router.attach("/{param1}/", DebugEventResource.class); - router.attach("/{param1}", DebugEventResource.class); - router.attach("/", DebugEventResource.class); - return router; - } - - @Override - public String basePath() { - return "/wm/debugevent"; - } - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java deleted file mode 100644 index 4d5ba9be6d5d5ef7f31a4316cb92d2303a62502f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java +++ /dev/null @@ -1,107 +0,0 @@ -/** -* 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.devicemanager; - -import java.util.Date; - -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.VlanVid; - - -/** - * Represents an independent device on the network. A device consists of a - * set of entities, and all the information known about a given device comes - * only from merging all associated entities for that device. - * @author readams - */ -public interface IDevice { - /** - * Get the primary key for this device. - * @return the primary key - */ - public Long getDeviceKey(); - - /** - * Get the MAC address of the device as a Long value. - * @return the MAC address for the device - */ - public MacAddress getMACAddress(); - - /** - * Get the MAC address of the device as a String value. - * @return the MAC address for the device - */ - public String getMACAddressString(); - - /** - * Get all unique VLAN IDs for the device. If the device has untagged - * entities, then the value -1 will be returned. - * @return an array containing all unique VLAN IDs for the device. - */ - public VlanVid[] getVlanId(); - - /** - * Get all unique IPv4 addresses associated with the device. - * @return an array containing the unique IPv4 addresses for the device. - */ - public IPv4Address[] getIPv4Addresses(); - - /** - * 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 - */ - public SwitchPort[] getOldAP(); - - /** - * Get all unique attachment points associated with the device. - * @param includeError whether to include blocked attachment points. - * Blocked attachment points should not be used for forwarding, but - * could be useful to show to a user - * @return an array containing all unique attachment points for the device - */ - public SwitchPort[] getAttachmentPoints(boolean includeError); - - /** - * Returns all unique VLAN IDs for the device that were observed on - * the given switch port - * @param swp the switch port to query - * @return an array containing the unique VLAN IDs - */ - public VlanVid[] getSwitchPortVlanIds(SwitchPort swp); - - /** - * Get the most recent timestamp for this device - * @return the last seen timestamp - */ - public Date getLastSeen(); - - /** - * Get the entity class for the device. - * @return the entity class - * @see IEntityClassifierService - */ - public IEntityClass getEntityClass(); - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java deleted file mode 100644 index 1221e66887666765574bc543cd57a049e839f616..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/** -* Copyright 2011, Big Switch Networks, Inc. -* Originally created by David Erickson, Stanford University -* -* Licensed under the Apache License, Version 2.0 (the "License"); you may -* not use this file except in compliance with the License. You may obtain -* a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -**/ - -package net.floodlightcontroller.devicemanager; - -import net.floodlightcontroller.core.IListener; - -/** - * Implementors of this interface can receive updates from DeviceManager about - * the state of devices under its control. - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public interface IDeviceListener extends IListener<String> { - /** - * Called when a new Device is found - * @param device the device that changed - */ - public void deviceAdded(IDevice device); - - /** - * Called when a Device is removed, this typically occurs when the port the - * Device is attached to goes down, or the switch it is attached to is - * removed. - * @param device the device that changed - */ - public void deviceRemoved(IDevice device); - - /** - * Called when a Device has moved to a new location on the network. Note - * that either the switch or the port or both has changed. - * - * @param device the device that changed - */ - public void deviceMoved(IDevice device); - - /** - * Called when a network address has been added or remove from a device - * - * @param device the device that changed - */ - public void deviceIPV4AddrChanged(IDevice device); - - /** - * Called when a VLAN tag for the device has been added or removed - * @param device the device that changed - */ - public void deviceVlanChanged(IDevice device); -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java deleted file mode 100755 index 40d729f6894149d9a1e3142c618bc606c0753a4b..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java +++ /dev/null @@ -1,222 +0,0 @@ -/** -* 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.devicemanager; - -import java.util.Collection; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.Set; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.VlanVid; -import org.projectfloodlight.openflow.types.OFPort; - -import net.floodlightcontroller.core.FloodlightContextStore; -import net.floodlightcontroller.core.module.IFloodlightService; - -/** - * Device manager allows interacting with devices on the network. Note - * that under normal circumstances, {@link Device} objects should be retrieved - * from the {@link FloodlightContext} rather than from {@link IDeviceManager}. - */ -public interface IDeviceService extends IFloodlightService { - - /** - * Fields used in devices for indexes and querying - * @see IDeviceService#addIndex - */ - enum DeviceField { - MAC, IPV4, VLAN, SWITCH, PORT - } - - /** - * The source device for the current packet-in, if applicable. - */ - public static final String CONTEXT_SRC_DEVICE = - "net.floodlightcontroller.devicemanager.srcDevice"; - - /** - * The destination device for the current packet-in, if applicable. - */ - public static final String CONTEXT_DST_DEVICE = - "net.floodlightcontroller.devicemanager.dstDevice"; - - /** - * The original destination device for the current packet-in - */ - public static final String CONTEXT_ORIG_DST_DEVICE = - "net.floodlightcontroller.devicemanager.origDstDevice"; - - /** - * A FloodlightContextStore object that can be used to interact with the - * FloodlightContext information created by BVS manager. - */ - public static final FloodlightContextStore<IDevice> fcStore = - new FloodlightContextStore<IDevice>(); - - /** - * Get the device with the given device key. - * - * @param deviceKey the key to search for - * @return the device associated with the key, or null if no such device - * @see IDevice#getDeviceKey() - */ - public IDevice getDevice(Long deviceKey); - - /** - * Search for a device exactly matching the provided device fields. This - * 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. - * - *{@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 - * @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) - throws IllegalArgumentException; - - /** - * Get a destination device using entity fields that corresponds with - * the given source device. The source device is important since - * there could be ambiguity in the destination device without the - * attachment point information. - * Search for a device in a given entity class. This is the same as - * the lookup process for destination devices. - * - * Only the key fields as defined by the reference entity class will - * 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. - * @return an {@link IDevice} or null if no device is found. - * @see IDeviceService#findDevice(long, Short, Integer, Long, - * Integer) - * @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) - throws IllegalArgumentException; - - /** - * Get an unmodifiable collection view over all devices currently known. - * @return the collection of all devices - */ - public Collection<? extends IDevice> getAllDevices(); - - /** - * Create an index over a set of fields. This allows efficient lookup - * of devices when querying using the indexed set of specified fields. - * The index must be registered before any device learning takes place, - * or it may be incomplete. It's OK if this is called multiple times with - * the same fields; only one index will be created for each unique set of - * fields. - * - * @param perClass set to true if the index should be maintained for each - * entity class separately. - * @param keyFields the set of fields on which to index - */ - public void addIndex(boolean perClass, - EnumSet<DeviceField> keyFields); - - /** - * Find devices that match the provided query. Any fields that are - * null will not be included in the query. If there is an index for - * 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 - * @return an iterator over a set of devices matching the query - * @see IDeviceService#queryClassDevices(IEntityClass, Long, - * Short, Integer, Long, Integer) - */ - public Iterator<? extends IDevice> queryDevices(MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort); - - /** - * Find devices that match the provided query. Only the index for - * the specified class will be searched. - * Any fields that are null will not be included in the query. If - * there is an index for the query, then it will be performed - * efficiently using the index. Otherwise, there will be a full scan - * 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) - */ - public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass, - MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort); - - /** - * Adds a listener to listen for IDeviceManagerServices notifications - * - * @param listener The listener that wants the notifications - * @param type The type of the listener - */ - public void addListener(IDeviceListener listener); - - /** - * Specify points in the network where attachment points are not to - * be learned. - * @param sw - * @param port - */ - public void addSuppressAPs(DatapathId swId, OFPort port); - - public void removeSuppressAPs(DatapathId swId, OFPort port); - - public Set<SwitchPort> getSuppressAPs(); - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClass.java b/src/main/java/net/floodlightcontroller/devicemanager/IEntityClass.java deleted file mode 100644 index bb077f116ce3094151fdd543af680aa8c9828c42..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClass.java +++ /dev/null @@ -1,59 +0,0 @@ -/** -* 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.devicemanager; - -import java.util.EnumSet; - -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.internal.Device; - -/** - * Entities within an entity class are grouped into {@link Device} objects - * based on the {@link IEntityClass}, and the key fields specified by the entity - * class. A set of entities are considered to be the same device if and only - * if they belong to the same entity class and they match on all key fields - * for that entity class. A field is effectively wildcarded by not including - * it in the list of key fields returned by {@link IEntityClassifierService} and/or - * {@link IEntityClass}. - * - * Note that if you're not using static objects, you'll need to override - * {@link Object#equals(Object)} and {@link Object#hashCode()}. - * - * @author readams - * - */ -public interface IEntityClass { - /** - * Return the set of key fields for this entity class. Entities - * belonging to this class that differ in fields not included in - * this collection will be considered the same device. The key - * fields for an entity class must not change unless associated - * with a flush of that entity class. - * - * @return a set containing the fields that should not - * be wildcarded. May be null to indicate that all fields are key fields. - */ - EnumSet<DeviceField> getKeyFields(); - - /** - * Returns a user-friendly, unique name for this EntityClass - * @return the name of the entity class - */ - String getName(); -} - diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassListener.java b/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassListener.java deleted file mode 100644 index 1b53550f6fe5f047db8160e4399e005c85e08dda..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassListener.java +++ /dev/null @@ -1,35 +0,0 @@ -/** -* Copyright 2011, Big Switch Networks, Inc. -* Originally created by David Erickson, Stanford University -* -* Licensed under the Apache License, Version 2.0 (the "License"); you may -* not use this file except in compliance with the License. You may obtain -* a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -**/ - -package net.floodlightcontroller.devicemanager; - -import java.util.Set; - -/** - * Implementors of this interface can receive updates from the Entity Classifier about - * the changes to entity Classes. - * - * @author Ananth Suryanarayana (Ananth.Suryanarayana@bigswitch.com) - */ -public interface IEntityClassListener { - - /** - * Process entity classes change event. - * @param entityClassNames Set of entity classes changed - */ - public void entityClassChanged(Set<String> entityClassNames); -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java b/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java deleted file mode 100644 index 2569a7df54ed892464810ca415b12a52d1ea76a7..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java +++ /dev/null @@ -1,108 +0,0 @@ -/** -* 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.devicemanager; - -import java.util.Collection; -import java.util.EnumSet; - -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.internal.Entity; - -/** - * A component that wishes to participate in entity classification needs to - * implement the IEntityClassifier interface, and register with the Device - * Manager as an entity classifier. An entity is classified by the classifier - * into an {@link IEntityClass} - * - * @author readams - */ -public interface IEntityClassifierService extends IFloodlightService { - /** - * Classify the given entity into an IEntityClass. It is important - * that the key fields returned by {@link IEntityClassifierService#getKeyFields()} - * be sufficient for classifying entities. That is, if two entities are - * identical except for a field that is not a key field, they must be - * assigned the same class. Furthermore, entity classification must be - * transitive: For all entities x, y, z, if x and y belong to a class c, and - * y and z belong class c, then x and z must belong to class c. - * - * @param entity the entity to classify - * @return the IEntityClass resulting from the classification. - * @see IEntityClassifierService#getKeyFields() - */ - IEntityClass classifyEntity(Entity entity); - - /** - * Return the most general list of fields that should be used as key - * fields. If devices differ in any fields not listed here, they can - * never be considered a different device by any {@link IEntityClass} - * returned by {@link IEntityClassifierService#classifyEntity}. The key fields - * for an entity classifier must not change unless associated with a - * flush of all entity state. The list of key fields must be the union - * of all key fields that could be returned by - * {@link IEntityClass#getKeyFields()}. - * - * @return a set containing the fields that should not be - * wildcarded. May be null to indicate that all fields are key fields. - * @see {@link IEntityClass#getKeyFields()} - * @see {@link IEntityClassifierService#classifyEntity} - */ - EnumSet<DeviceField> getKeyFields(); - - /** - * Reclassify the given entity into a class. When reclassifying entities, - * it can be helpful to take into account the current classification either - * as an optimization or to allow flushing any cached state tied to the key - * for that device. The entity will be assigned to a new device with a new - * object if the entity class returned is different from the entity class for - * curDevice. - * - * <p>Note that you must take steps to ensure you always return classes - * in some consistent ordering. - - * @param curDevice the device currently associated with the entity - * @param entity the entity to reclassify - * @return the IEntityClass resulting from the classification - */ - IEntityClass reclassifyEntity(IDevice curDevice, - Entity entity); - - /** - * Once reclassification is complete for a device, this method will be - * called. If any entities within the device changed their classification, - * it will split into one or more new devices for each of the entities. If - * two devices are merged because of a reclassification, then this will be - * called on each of the devices, with the same device in the newDevices - * collection. - * - * @param oldDevice the original device object - * @param newDevices all the new devices derived from the entities of the - * old device. If null, the old device was unchanged. - */ - void deviceUpdate(IDevice oldDevice, - Collection<? extends IDevice> newDevices); - - /** - * Adds a listener to listen for IEntityClassifierServices notifications - * - * @param listener The listener that wants the notifications - */ - public void addListener(IEntityClassListener listener); -} - diff --git a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java deleted file mode 100644 index d057f9c4a353f0501631f6cf7725fd00d4be5b4e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java +++ /dev/null @@ -1,140 +0,0 @@ -/** -* Copyright 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.devicemanager; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -import net.floodlightcontroller.core.web.serializers.DPIDSerializer; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; - -/** - * A simple switch DPID/port pair - * This class is immutable - * @author readams - * - */ -public class SwitchPort { - @JsonSerialize(using=ToStringSerializer.class) - public enum ErrorStatus { - DUPLICATE_DEVICE("duplicate-device"); - - private String value; - ErrorStatus(String v) { - value = v; - } - - @Override - public String toString() { - return value; - } - - public static ErrorStatus fromString(String str) { - for (ErrorStatus m : ErrorStatus.values()) { - if (m.value.equals(str)) { - return m; - } - } - return null; - } - } - - private final DatapathId switchDPID; - private final OFPort port; - private final ErrorStatus errorStatus; - - /** - * Simple constructor - * @param switchDPID the dpid - * @param port the port - * @param errorStatus any error status for the switch port - */ - public SwitchPort(DatapathId switchDPID, OFPort port, ErrorStatus errorStatus) { - super(); - this.switchDPID = switchDPID; - this.port = port; - this.errorStatus = errorStatus; - } - - /** - * Simple constructor - * @param switchDPID the dpid - * @param port the port - */ - public SwitchPort(DatapathId switchDPID, OFPort port) { - super(); - this.switchDPID = switchDPID; - this.port = port; - this.errorStatus = null; - } - - // *************** - // Getters/Setters - // *************** - - @JsonSerialize(using=DPIDSerializer.class) - public DatapathId getSwitchDPID() { - return switchDPID; - } - - public OFPort getPort() { - return port; - } - - public ErrorStatus getErrorStatus() { - return errorStatus; - } - - // ****** - // Object - // ****** - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((errorStatus == null) - ? 0 - : errorStatus.hashCode()); - result = prime * result + port.getPortNumber(); - result = prime * result + (int) (switchDPID.getLong() ^ (switchDPID.getLong() >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - SwitchPort other = (SwitchPort) obj; - if (errorStatus != other.errorStatus) return false; - if (port != other.port) return false; - if (switchDPID != other.switchDPID) return false; - return true; - } - - @Override - public String toString() { - return "SwitchPort [switchDPID=" + switchDPID.toString() + - ", port=" + port + ", errorStatus=" + errorStatus + "]"; - } - -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java deleted file mode 100644 index 46c2408faef824cb4ccf74c9dd69515037f70f3a..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * 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. - **/ - -/** - * @author Srini - */ - -package net.floodlightcontroller.devicemanager.internal; - -import java.util.Date; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -public class AttachmentPoint { - DatapathId sw; - OFPort port; - Date activeSince; - Date lastSeen; - - // Timeout for moving attachment points from OF/broadcast - // domain to another. - public static final long INACTIVITY_INTERVAL = 30000; // 30 seconds - public static final long EXTERNAL_TO_EXTERNAL_TIMEOUT = 5000; // 5 seconds - public static final long OPENFLOW_TO_EXTERNAL_TIMEOUT = 30000; // 30 seconds - public static final long CONSISTENT_TIMEOUT = 30000; // 30 seconds - - public AttachmentPoint(DatapathId sw, OFPort port, Date activeSince, - Date lastSeen) { - this.sw = sw; - this.port = port; - this.activeSince = activeSince; - this.lastSeen = lastSeen; - } - - public AttachmentPoint(DatapathId sw, OFPort port, Date lastSeen) { - this.sw = sw; - this.port = port; - this.lastSeen = lastSeen; - this.activeSince = lastSeen; - } - - public AttachmentPoint(AttachmentPoint ap) { - this.sw = ap.sw; - this.port = ap.port; - this.activeSince = ap.activeSince; - this.lastSeen = ap.lastSeen; - } - - public DatapathId getSw() { - return sw; - } - public void setSw(DatapathId sw) { - this.sw = sw; - } - public OFPort getPort() { - return port; - } - public void setPort(OFPort port) { - this.port = port; - } - public Date getActiveSince() { - return activeSince; - } - public void setActiveSince(Date activeSince) { - this.activeSince = activeSince; - } - public Date getLastSeen() { - return lastSeen; - } - public void setLastSeen(Date lastSeen) { - if (this.lastSeen.getTime() + INACTIVITY_INTERVAL < lastSeen.getTime()) - this.activeSince = lastSeen; - if (this.lastSeen.before(lastSeen)) - this.lastSeen = lastSeen; - } - - /** - * Hash is generated using only switch and port - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + port.getPortNumber(); - result = prime * result + (int) (sw.getLong() ^ (sw.getLong() >>> 32)); - return result; - } - - /** - * Compares only the switch and port - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - AttachmentPoint other = (AttachmentPoint) obj; - if (port != other.port) - return false; - if (sw != other.sw) - return false; - return true; - } - - @Override - public String toString() { - return "AttachmentPoint [sw=" + sw + ", port=" + port - + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen.toString() - + "]"; - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java deleted file mode 100644 index faed0d4016147080ce254122b02fa6b8f5c4975f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java +++ /dev/null @@ -1,138 +0,0 @@ -/** -* 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.devicemanager.internal; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IEntityClassListener; -import net.floodlightcontroller.devicemanager.IEntityClassifierService; - -/** - * This is a default entity classifier that simply classifies all - * entities into a fixed entity class, with key fields of MAC and VLAN. - * @author readams - */ -public class DefaultEntityClassifier implements - IEntityClassifierService, - IFloodlightModule -{ - /** - * A default fixed entity class - */ - protected static class DefaultEntityClass implements IEntityClass { - String name; - - public DefaultEntityClass(String name) { - this.name = name; - } - - @Override - public EnumSet<IDeviceService.DeviceField> getKeyFields() { - return keyFields; - } - - @Override - public String getName() { - return name; - } - } - - protected static EnumSet<DeviceField> keyFields; - static { - keyFields = EnumSet.of(DeviceField.MAC, DeviceField.VLAN); - } - protected static DefaultEntityClass entityClass = - new DefaultEntityClass("DefaultEntityClass"); - - @Override - public IEntityClass classifyEntity(Entity entity) { - return entityClass; - } - - @Override - public IEntityClass reclassifyEntity(IDevice curDevice, - Entity entity) { - return entityClass; - } - - @Override - public void deviceUpdate(IDevice oldDevice, - Collection<? extends IDevice> newDevices) { - // no-op - } - - @Override - public EnumSet<DeviceField> getKeyFields() { - return keyFields; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IEntityClassifierService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - // We are the class that implements the service - m.put(IEntityClassifierService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - // No dependencies - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - // no-op - } - - @Override - public void startUp(FloodlightModuleContext context) { - // no-op - } - - @Override - public void addListener(IEntityClassListener listener) { - // no-op - - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java deleted file mode 100755 index 07e5b77bfbacf879ce6b749fe7cbe811d1c90f85..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java +++ /dev/null @@ -1,799 +0,0 @@ -/** - * 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.devicemanager.internal; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeSet; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.VlanVid; -import org.projectfloodlight.openflow.util.HexString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.web.DeviceSerializer; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.topology.ITopologyService; - -/** - * Concrete implementation of {@link IDevice} - * @author readams - */ -@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 = - HexString.toHexString(entity.getMacAddress(), 6); - 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(); - short port = entity.getSwitchPort().shortValue(); - - if (deviceManager.isValidAttachmentPoint(sw, port)) { - AttachmentPoint ap; - ap = new AttachmentPoint(sw, port, - entity.getLastSeenTimestamp().getTime()); - - 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 = - HexString.toHexString(this.entities[0].getMacAddress(), 6); - 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<Long, 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<Long, AttachmentPoint> apMap = new HashMap<Long, 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; - - long 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<Long, 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) { - long 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<Long, 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<Long, 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; - } - - long 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 > 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(long sw, short port) { - AttachmentPoint ap = new AttachmentPoint(sw, port, 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(long 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() == 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() == 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<Long, 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 long getMACAddress() { - // we assume only one MAC per device for now. - return entities[0].getMacAddress(); - } - - @Override - public String getMACAddressString() { - return macAddressString; - } - - @Override - public Short[] getVlanId() { - return Arrays.copyOf(vlanIds, vlanIds.length); - } - - static final EnumSet<DeviceField> ipv4Fields = EnumSet.of(DeviceField.IPV4); - - @Override - public Integer[] getIPv4Addresses() { - // XXX - TODO we can cache this result. Let's find out if this - // is really a performance bottleneck first though. - - TreeSet<Integer> vals = new TreeSet<Integer>(); - 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 Integer[vals.size()]); - } - - @Override - public Short[] getSwitchPortVlanIds(SwitchPort swp) { - TreeSet<Short> vals = new TreeSet<Short>(); - for (Entity e : entities) { - if (e.switchDPID == swp.getSwitchDPID() - && e.switchPort == swp.getPort()) { - if (e.getVlan() == null) - vals.add(Ethernet.VLAN_UNTAGGED); - else - vals.add(e.getVlan()); - } - } - return vals.toArray(new Short[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; - result = prime * result + Arrays.hashCode(entities); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Device other = (Device) obj; - if (!deviceKey.equals(other.deviceKey)) return false; - if (!Arrays.equals(entities, other.entities)) return false; - 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 (Integer ip: getIPv4Addresses()) { - if (!isFirst) - builder.append(", "); - isFirst = false; - builder.append(IPv4.fromIPv4Address(ip)); - } - 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 deleted file mode 100644 index 0d8ea75dd42466600e9abf24637903750479985c..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java +++ /dev/null @@ -1,116 +0,0 @@ -/** -* Copyright 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.devicemanager.internal; - -import java.util.Collection; -import java.util.EnumSet; -import java.util.Iterator; - -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; - -/** - * An index that maps key fields of an entity to device keys - */ -public abstract class DeviceIndex { - /** - * The key fields for this index - */ - protected EnumSet<DeviceField> keyFields; - - /** - * Construct a new device index using the provided key fields - * @param keyFields the key fields to use - */ - public DeviceIndex(EnumSet<DeviceField> keyFields) { - super(); - this.keyFields = keyFields; - } - - /** - * Find all device keys in the index that match the given entity - * on all the key fields for this index - * @param e the entity to search for - * @return an iterator over device keys - */ - public abstract Iterator<Long> queryByEntity(Entity entity); - - /** - * Get all device keys in the index. If certain devices exist - * multiple times, then these devices may be returned multiple times - * @return an iterator over device keys - */ - public abstract Iterator<Long> getAll(); - - /** - * Attempt to update an index with the entities in the provided - * {@link Device}. If the update fails because of a concurrent update, - * will return false. - * @param device the device to update - * @param deviceKey the device key for the device - * @return true if the update succeeded, false otherwise. - */ - public abstract boolean updateIndex(Device device, Long deviceKey); - - /** - * Add a mapping from the given entity to the given device key. This - * update will not fail because of a concurrent update - * @param device the device to update - * @param deviceKey the device key for the device - */ - public abstract void updateIndex(Entity entity, Long deviceKey); - - /** - * Remove the entry for the given entity - * @param entity the entity to remove - */ - public abstract void removeEntity(Entity entity); - - /** - * Remove the given device key from the index for the given entity - * @param entity the entity to search for - * @param deviceKey the key to remove - */ - public abstract void removeEntity(Entity entity, Long deviceKey); - - /** - * Remove the give device from the index only if this the collection - * of others does not contain an entity that is identical on all the key - * fields for this index. - * @param entity the entity to search for - * @param deviceKey the key to remove - * @param others the others against which to check - */ - public void removeEntityIfNeeded(Entity entity, Long deviceKey, - Collection<Entity> others) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - for (Entity o : others) { - IndexedEntity oio = new IndexedEntity(keyFields, o); - if (oio.equals(ie)) return; - } - - Iterator<Long> keyiter = this.queryByEntity(entity); - while (keyiter.hasNext()) { - Long key = keyiter.next(); - if (key.equals(deviceKey)) { - removeEntity(entity, deviceKey); - break; - } - } - } - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java deleted file mode 100644 index 2015bbe60d648d86c33a582d2c9bae9b5274e5c8..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndexInterator.java +++ /dev/null @@ -1,59 +0,0 @@ -/** -* Copyright 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.devicemanager.internal; - -import java.util.Iterator; - -/** - * An iterator for handling device index queries - */ -public class DeviceIndexInterator implements Iterator<Device> { - private DeviceManagerImpl deviceManager; - private Iterator<Long> subIterator; - - /** - * Construct a new device index iterator referring to a device manager - * instance and an iterator over device keys - * - * @param deviceManager the device manager - * @param subIterator an iterator over device keys - */ - public DeviceIndexInterator(DeviceManagerImpl deviceManager, - Iterator<Long> subIterator) { - super(); - this.deviceManager = deviceManager; - this.subIterator = subIterator; - } - - @Override - public boolean hasNext() { - return subIterator.hasNext(); - } - - @Override - public Device next() { - Long next = subIterator.next(); - return deviceManager.deviceMap.get(next); - } - - @Override - public void remove() { - subIterator.remove(); - } - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java deleted file mode 100644 index d9a7a4532284bc30bc74bd2f8017ecca854bee89..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java +++ /dev/null @@ -1,123 +0,0 @@ -/** -* Copyright 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.devicemanager.internal; - -import java.util.Arrays; -import java.util.Iterator; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.VlanVid; - -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.util.FilterIterator; - -/** - * An iterator for handling device queries - */ -public class DeviceIterator extends FilterIterator<Device> { - private IEntityClass[] entityClasses; - - private MacAddress macAddress; - private VlanVid vlan; - private IPv4Address ipv4Address; - private DatapathId switchDPID; - private OFPort switchPort; - - /** - * Construct a new device iterator over the key fields - * @param subIterator an iterator over the full data structure to scan - * @param entityClasses the entity classes to search for - * @param macAddress The MAC address - * @param vlan the VLAN - * @param ipv4Address the ipv4 address - * @param switchDPID the switch DPID - * @param switchPort the switch port - */ - public DeviceIterator(Iterator<Device> subIterator, - IEntityClass[] entityClasses, - MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { - super(subIterator); - this.entityClasses = entityClasses; - this.subIterator = subIterator; - this.macAddress = macAddress; - this.vlan = vlan; - this.ipv4Address = ipv4Address; - this.switchDPID = switchDPID; - this.switchPort = switchPort; - } - - @Override - protected boolean matches(Device value) { - boolean match; - if (entityClasses != null) { - IEntityClass clazz = value.getEntityClass(); - if (clazz == null) return false; - - match = false; - for (IEntityClass entityClass : entityClasses) { - if (clazz.equals(entityClass)) { - match = true; - break; - } - } - if (!match) return false; - } - if (macAddress != null) { - if (macAddress.getLong() != value.getMACAddress()) - return false; - } - if (vlan != null) { - Short[] vlans = value.getVlanId(); - if (Arrays.binarySearch(vlans, vlan) < 0) - return false; - } - if (ipv4Address != null) { - Integer[] ipv4Addresses = value.getIPv4Addresses(); - if (Arrays.binarySearch(ipv4Addresses, ipv4Address) < 0) - return false; - } - if (switchDPID != null || switchPort != null) { - SwitchPort[] sps = value.getAttachmentPoints(); - if (sps == null) return false; - - match = false; - for (SwitchPort sp : sps) { - if (switchDPID != null) { - if (switchDPID.getLong() != sp.getSwitchDPID().getLong()) - return false; - } - if (switchPort != null) { - if (switchPort.getPortNumber() != sp.getPort().getPortNumber()) - return false; - } - match = true; - break; - } - if (!match) return false; - } - return true; - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java deleted file mode 100755 index 7d34fc3f6d789dfdd9bb1c3ecd42369ab85a1244..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ /dev/null @@ -1,2629 +0,0 @@ -/** - * 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.devicemanager.internal; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.HAListenerTypeMarker; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IHAListener; -import net.floodlightcontroller.core.IInfoProvider; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.HARole; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.ListenerDispatcher; -import net.floodlightcontroller.core.util.SingletonTask; -import net.floodlightcontroller.debugcounter.IDebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException; -import net.floodlightcontroller.debugcounter.NullDebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType; -import net.floodlightcontroller.debugevent.IDebugEventService; -import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; -import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType; -import net.floodlightcontroller.debugevent.IDebugEventService.EventType; -import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered; -import net.floodlightcontroller.debugevent.IEventUpdater; -import net.floodlightcontroller.debugevent.NullDebugEvent; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IEntityClassListener; -import net.floodlightcontroller.devicemanager.IEntityClassifierService; -import net.floodlightcontroller.devicemanager.IDeviceListener; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.devicemanager.internal.DeviceSyncRepresentation.SyncEntity; -import net.floodlightcontroller.devicemanager.web.DeviceRoutable; -import net.floodlightcontroller.flowcache.IFlowReconcileEngineService; -import net.floodlightcontroller.flowcache.IFlowReconcileListener; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.flowcache.OFMatchReconcile; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; -import net.floodlightcontroller.packet.ARP; -import net.floodlightcontroller.packet.DHCP; -import net.floodlightcontroller.packet.DHCPOption; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.packet.DHCP.DHCPOptionCode; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyListener; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.util.MultiIterator; -import static net.floodlightcontroller.devicemanager.internal. -DeviceManagerImpl.DeviceUpdate.Change.*; - -import org.projectfloodlight.openflow.protocol.OFMatchWithSwDpid; -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.VlanVid; -import org.projectfloodlight.openflow.protocol.OFType; -import org.sdnplatform.sync.IClosableIterator; -import org.sdnplatform.sync.IStoreClient; -import org.sdnplatform.sync.ISyncService; -import org.sdnplatform.sync.ISyncService.Scope; -import org.sdnplatform.sync.Versioned; -import org.sdnplatform.sync.error.ObsoleteVersionException; -import org.sdnplatform.sync.error.SyncException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * DeviceManager creates Devices based upon MAC addresses seen in the network. - * It tracks any network addresses mapped to the Device, and its location - * within the network. - * @author readams - */ -public class DeviceManagerImpl implements -IDeviceService, IOFMessageListener, ITopologyListener, -IFloodlightModule, IEntityClassListener, -IFlowReconcileListener, IInfoProvider { - protected static Logger logger = - LoggerFactory.getLogger(DeviceManagerImpl.class); - - - protected IFloodlightProviderService floodlightProvider; - protected ITopologyService topology; - protected IStorageSourceService storageSource; - protected IRestApiService restApi; - protected IThreadPoolService threadPool; - protected IFlowReconcileService flowReconcileMgr; - protected IFlowReconcileEngineService flowReconcileEngine; - protected IDebugCounterService debugCounters; - private ISyncService syncService; - private IStoreClient<String,DeviceSyncRepresentation> storeClient; - private DeviceSyncManager deviceSyncManager; - - /** - * Debug Counters - */ - public static final String MODULE_NAME = "devicemanager"; - public static final String PACKAGE = DeviceManagerImpl.class.getPackage().getName(); - public IDebugCounter cntIncoming; - public IDebugCounter cntReconcileRequest; - public IDebugCounter cntReconcileNoSource; - public IDebugCounter cntReconcileNoDest; - public IDebugCounter cntInvalidSource; - public IDebugCounter cntInvalidDest; - public IDebugCounter cntNoSource; - public IDebugCounter cntNoDest; - public IDebugCounter cntDhcpClientNameSnooped; - public IDebugCounter cntDeviceOnInternalPortNotLearned; - public IDebugCounter cntPacketNotAllowed; - public IDebugCounter cntNewDevice; - public IDebugCounter cntPacketOnInternalPortForKnownDevice; - public IDebugCounter cntNewEntity; - public IDebugCounter cntDeviceChanged; - public IDebugCounter cntDeviceMoved; - public IDebugCounter cntCleanupEntitiesRuns; - public IDebugCounter cntEntityRemovedTimeout; - public IDebugCounter cntDeviceDeleted; - public IDebugCounter cntDeviceReclassifyDelete; - public IDebugCounter cntDeviceStrored; - public IDebugCounter cntDeviceStoreThrottled; - public IDebugCounter cntDeviceRemovedFromStore; - public IDebugCounter cntSyncException; - public IDebugCounter cntDevicesFromStore; - public IDebugCounter cntConsolidateStoreRuns; - public IDebugCounter cntConsolidateStoreDevicesRemoved; - public IDebugCounter cntTransitionToMaster; - - /** - * Debug Events - */ - private IDebugEventService debugEvents; - private IEventUpdater<DeviceEvent> evDevice; - - private boolean isMaster = false; - - static final String DEVICE_SYNC_STORE_NAME = - DeviceManagerImpl.class.getCanonicalName() + ".stateStore"; - - /** - * Time interval between writes of entries for the same device to - * the sync store. - */ - static final int DEFAULT_SYNC_STORE_WRITE_INTERVAL_MS = - 5*60*1000; // 5 min - private int syncStoreWriteIntervalMs = DEFAULT_SYNC_STORE_WRITE_INTERVAL_MS; - - /** - * Time after SLAVE->MASTER until we run the consolidate store - * code. - */ - static final int DEFAULT_INITIAL_SYNC_STORE_CONSOLIDATE_MS = - 15*1000; // 15 sec - private int initialSyncStoreConsolidateMs = - DEFAULT_INITIAL_SYNC_STORE_CONSOLIDATE_MS; - - /** - * Time interval between consolidate store runs. - */ - static final int DEFAULT_SYNC_STORE_CONSOLIDATE_INTERVAL_MS = - 75*60*1000; // 75 min - private final int syncStoreConsolidateIntervalMs = - DEFAULT_SYNC_STORE_CONSOLIDATE_INTERVAL_MS; - - /** - * Time in milliseconds before entities will expire - */ - protected static final int ENTITY_TIMEOUT = 60*60*1000; - - /** - * Time in seconds between cleaning up old entities/devices - */ - protected static final int ENTITY_CLEANUP_INTERVAL = 60*60; - - /** - * This is the master device map that maps device IDs to {@link Device} - * objects. - */ - protected ConcurrentHashMap<Long, Device> deviceMap; - - /** - * Counter used to generate device keys - */ - protected AtomicLong deviceKeyCounter = new AtomicLong(0); - - /** - * This is the primary entity index that contains all entities - */ - protected DeviceUniqueIndex primaryIndex; - - /** - * This stores secondary indices over the fields in the devices - */ - protected Map<EnumSet<DeviceField>, DeviceIndex> secondaryIndexMap; - - /** - * This map contains state for each of the {@ref IEntityClass} - * that exist - */ - protected ConcurrentHashMap<String, ClassState> classStateMap; - - /** - * This is the list of indices we want on a per-class basis - */ - protected Set<EnumSet<DeviceField>> perClassIndices; - - /** - * The entity classifier currently in use - */ - protected IEntityClassifierService entityClassifier; - - /** - * Used to cache state about specific entity classes - */ - protected class ClassState { - - /** - * The class index - */ - protected DeviceUniqueIndex classIndex; - - /** - * This stores secondary indices over the fields in the device for the - * class - */ - protected Map<EnumSet<DeviceField>, DeviceIndex> secondaryIndexMap; - - /** - * Allocate a new {@link ClassState} object for the class - * @param clazz the class to use for the state - */ - public ClassState(IEntityClass clazz) { - EnumSet<DeviceField> keyFields = clazz.getKeyFields(); - EnumSet<DeviceField> primaryKeyFields = - entityClassifier.getKeyFields(); - boolean keyFieldsMatchPrimary = - primaryKeyFields.equals(keyFields); - - if (!keyFieldsMatchPrimary) - classIndex = new DeviceUniqueIndex(keyFields); - - secondaryIndexMap = - new HashMap<EnumSet<DeviceField>, DeviceIndex>(); - for (EnumSet<DeviceField> fields : perClassIndices) { - secondaryIndexMap.put(fields, - new DeviceMultiIndex(fields)); - } - } - } - - /** - * Device manager event listeners - * reclassifyDeviceListeners are notified first before reconcileDeviceListeners. - * This is to make sure devices are correctly reclassified before reconciliation. - */ - protected ListenerDispatcher<String,IDeviceListener> deviceListeners; - - /** - * A device update event to be dispatched - */ - protected static class DeviceUpdate { - public enum Change { - ADD, DELETE, CHANGE; - } - - /** - * The affected device - */ - protected Device device; - - /** - * The change that was made - */ - protected Change change; - - /** - * If not added, then this is the list of fields changed - */ - protected EnumSet<DeviceField> fieldsChanged; - - public DeviceUpdate(Device device, Change change, - EnumSet<DeviceField> fieldsChanged) { - super(); - this.device = device; - this.change = change; - this.fieldsChanged = fieldsChanged; - } - - @Override - public String toString() { - String devIdStr = device.getEntityClass().getName() + "::" + - device.getMACAddressString(); - return "DeviceUpdate [device=" + devIdStr + ", change=" + change - + ", fieldsChanged=" + fieldsChanged + "]"; - } - - } - - /** - * AttachmentPointComparator - * - * Compares two attachment points and returns the latest one. - * It is assumed that the two attachment points are in the same - * L2 domain. - * - * @author srini - */ - protected class AttachmentPointComparator - implements Comparator<AttachmentPoint> { - public AttachmentPointComparator() { - super(); - } - - @Override - public int compare(AttachmentPoint oldAP, AttachmentPoint newAP) { - //First compare based on L2 domain ID; - - DatapathId oldSw = oldAP.getSw(); - OFPort oldPort = oldAP.getPort(); - DatapathId oldDomain = topology.getL2DomainId(oldSw); - boolean oldBD = topology.isBroadcastDomainPort(oldSw, oldPort); - - DatapathId newSw = newAP.getSw(); - OFPort newPort = newAP.getPort(); - DatapathId newDomain = topology.getL2DomainId(newSw); - boolean newBD = topology.isBroadcastDomainPort(newSw, newPort); - - 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) { - return -1; - } else if (oldPort == OFPort.LOCAL && - newPort != OFPort.LOCAL) { - return 1; - } - - // 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())) - return -compare(newAP, oldAP); - - long activeOffset = 0; - if (!topology.isConsistent(oldSw, oldPort, newSw, newPort)) { - if (!newBD && oldBD) { - return -1; - } - if (newBD && oldBD) { - activeOffset = AttachmentPoint.EXTERNAL_TO_EXTERNAL_TIMEOUT; - } - else if (newBD && !oldBD){ - activeOffset = AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT; - } - - } else { - // The attachment point is consistent. - activeOffset = AttachmentPoint.CONSISTENT_TIMEOUT; - } - - - if ((newAP.getActiveSince().getTime() > oldAP.getLastSeen().getTime() + activeOffset) || - (newAP.getLastSeen().getTime() > oldAP.getLastSeen().getTime() + - AttachmentPoint.INACTIVITY_INTERVAL)) { - return -1; - } - return 1; - } - } - /** - * Comparator for sorting by cluster ID - */ - public AttachmentPointComparator apComparator; - - /** - * Switch ports where attachment points shouldn't be learned - */ - private Set<SwitchPort> suppressAPs; - - /** - * Periodic task to clean up expired entities - */ - public SingletonTask entityCleanupTask; - - - /** - * Periodic task to consolidate entries in the store. I.e., delete - * entries in the store that are not known to DeviceManager - */ - private SingletonTask storeConsolidateTask; - - /** - * Listens for HA notifications - */ - protected HAListenerDelegate haListenerDelegate; - - - // ********************* - // IDeviceManagerService - // ********************* - - @Override - public IDevice getDevice(Long deviceKey) { - return deviceMap.get(deviceKey); - } - - @Override - public IDevice findDevice(MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, DatapathId switchDPID, - 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 (!allKeyFieldsPresent(e, entityClassifier.getKeyFields())) { - throw new IllegalArgumentException("Not all key fields specified." - + " Required fields: " + entityClassifier.getKeyFields()); - } - return findDeviceByEntity(e); - } - - @Override - public IDevice findClassDevice(IEntityClass entityClass, MacAddress macAddress, - VlanVid vlan, IPv4Address ipv4Address) - 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())) { - throw new IllegalArgumentException("Not all key fields and/or " - + " no source device specified. Required fields: " + - entityClassifier.getKeyFields()); - } - return findDestByEntity(entityClass, e); - } - - @Override - public Collection<? extends IDevice> getAllDevices() { - return Collections.unmodifiableCollection(deviceMap.values()); - } - - @Override - public void addIndex(boolean perClass, - EnumSet<DeviceField> keyFields) { - if (perClass) { - perClassIndices.add(keyFields); - } else { - secondaryIndexMap.put(keyFields, - new DeviceMultiIndex(keyFields)); - } - } - - @Override - public Iterator<? extends IDevice> queryDevices(MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { - DeviceIndex index = null; - if (secondaryIndexMap.size() > 0) { - EnumSet<DeviceField> keys = - getEntityKeys(macAddress, vlan, ipv4Address, - switchDPID, switchPort); - index = secondaryIndexMap.get(keys); - } - - Iterator<Device> deviceIterator = null; - if (index == null) { - // Do a full table scan - deviceIterator = deviceMap.values().iterator(); - } else { - // index lookup - Entity entity = new Entity(macAddress, - vlan, - ipv4Address, - switchDPID, - switchPort, - null); - deviceIterator = - new DeviceIndexInterator(this, index.queryByEntity(entity)); - } - - DeviceIterator di = - new DeviceIterator(deviceIterator, - null, - macAddress, - vlan, - ipv4Address, - switchDPID, - switchPort); - return di; - } - - @Override - public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass, - MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { - ArrayList<Iterator<Device>> iterators = - new ArrayList<Iterator<Device>>(); - ClassState classState = getClassState(entityClass); - - DeviceIndex index = null; - if (classState.secondaryIndexMap.size() > 0) { - EnumSet<DeviceField> keys = - getEntityKeys(macAddress, vlan, ipv4Address, - switchDPID, switchPort); - index = classState.secondaryIndexMap.get(keys); - } - - Iterator<Device> iter; - if (index == null) { - index = classState.classIndex; - if (index == null) { - // scan all devices - return new DeviceIterator(deviceMap.values().iterator(), - new IEntityClass[] { entityClass }, - macAddress, vlan, ipv4Address, - switchDPID, switchPort); - } else { - // scan the entire class - iter = new DeviceIndexInterator(this, index.getAll()); - } - } else { - // index lookup - Entity entity = - new Entity(macAddress, - vlan, - ipv4Address, - switchDPID, - switchPort, - null); - iter = new DeviceIndexInterator(this, - index.queryByEntity(entity)); - } - iterators.add(iter); - - return new MultiIterator<Device>(iterators.iterator()); - } - - protected Iterator<Device> getDeviceIteratorForQuery(MacAddress macAddress, - VlanVid vlan, - IPv4Address ipv4Address, - DatapathId switchDPID, - OFPort switchPort) { - DeviceIndex index = null; - if (secondaryIndexMap.size() > 0) { - EnumSet<DeviceField> keys = - getEntityKeys(macAddress, vlan, ipv4Address, - switchDPID, switchPort); - index = secondaryIndexMap.get(keys); - } - - Iterator<Device> deviceIterator = null; - if (index == null) { - // Do a full table scan - deviceIterator = deviceMap.values().iterator(); - } else { - // index lookup - Entity entity = new Entity(macAddress, - vlan, - ipv4Address, - switchDPID, - switchPort, - null); - deviceIterator = - new DeviceIndexInterator(this, index.queryByEntity(entity)); - } - - DeviceIterator di = - new DeviceIterator(deviceIterator, - null, - macAddress, - vlan, - ipv4Address, - switchDPID, - switchPort); - return di; - } - - @Override - public void addListener(IDeviceListener listener) { - deviceListeners.addListener("device", listener); - logListeners(); - } - - @Override - public void addSuppressAPs(DatapathId swId, OFPort port) { - suppressAPs.add(new SwitchPort(swId, port)); - } - - @Override - public void removeSuppressAPs(DatapathId swId, OFPort port) { - suppressAPs.remove(new SwitchPort(swId, port)); - } - - @Override - public Set<SwitchPort> getSuppressAPs() { - return Collections.unmodifiableSet(suppressAPs); - } - - private void logListeners() { - List<IDeviceListener> listeners = deviceListeners.getOrderedListeners(); - if (listeners != null) { - StringBuffer sb = new StringBuffer(); - sb.append("DeviceListeners: "); - for (IDeviceListener l : listeners) { - sb.append(l.getName()); - sb.append(","); - } - logger.debug(sb.toString()); - } - } - - // *************** - // IDeviceListener - // *************** - private class DeviceDebugEventLogger implements IDeviceListener { - @Override - public String getName() { - return "deviceDebugEventLogger"; - } - - @Override - public boolean isCallbackOrderingPrereq(String type, String name) { - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(String type, String name) { - return false; - } - - @Override - public void deviceAdded(IDevice device) { - generateDeviceEvent(device, "host-added"); - } - - @Override - public void deviceRemoved(IDevice device) { - generateDeviceEvent(device, "host-removed"); - } - - @Override - public void deviceMoved(IDevice device) { - generateDeviceEvent(device, "host-moved"); - } - - @Override - public void deviceIPV4AddrChanged(IDevice device) { - generateDeviceEvent(device, "host-ipv4-addr-changed"); - } - - @Override - public void deviceVlanChanged(IDevice device) { - generateDeviceEvent(device, "host-vlan-changed"); - } - - private void generateDeviceEvent(IDevice device, String reason) { - List<IPv4Address> ipv4Addresses = - new ArrayList<IPv4Address>(Arrays.asList(device.getIPv4Addresses())); - List<SwitchPort> oldAps = - new ArrayList<SwitchPort>(Arrays.asList(device.getOldAP())); - List<SwitchPort> currentAps = - new ArrayList<SwitchPort>(Arrays.asList(device.getAttachmentPoints())); - List<VlanVid> vlanIds = - new ArrayList<VlanVid>(Arrays.asList(device.getVlanId())); - - evDevice.updateEventNoFlush( - new DeviceEvent(device.getMACAddress(), - ipv4Addresses, - oldAps, - currentAps, - vlanIds, reason)); - } - } - - // ************* - // IInfoProvider - // ************* - - @Override - public Map<String, Object> getInfo(String type) { - if (!"summary".equals(type)) - return null; - - Map<String, Object> info = new HashMap<String, Object>(); - info.put("# hosts", deviceMap.size()); - return info; - } - - // ****************** - // IOFMessageListener - // ****************** - - @Override - public String getName() { - return MODULE_NAME; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return ((type == OFType.PACKET_IN || type == OFType.FLOW_MOD) - && name.equals("topology")); - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return false; - } - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, - FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - cntIncoming.increment(); - return this.processPacketInMessage(sw, - (OFPacketIn) msg, cntx); - default: - break; - } - return Command.CONTINUE; - } - - // *************** - // IFlowReconcileListener - // *************** - @Override - public Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) { - ListIterator<OFMatchReconcile> iter = ofmRcList.listIterator(); - while (iter.hasNext()) { - OFMatchReconcile ofm = iter.next(); - - // Remove the STOPPed flow. - if (Command.STOP == reconcileFlow(ofm)) { - iter.remove(); - } - } - - if (ofmRcList.size() > 0) { - return Command.CONTINUE; - } else { - return Command.STOP; - } - } - - protected Command reconcileFlow(OFMatchReconcile ofm) { - cntReconcileRequest.increment(); - // Extract source entity information - Entity srcEntity = - getEntityFromFlowMod(ofm.ofmWithSwDpid, true); - if (srcEntity == null) { - cntReconcileNoSource.increment(); - return Command.STOP; - } - - // Find the device by source entity - Device srcDevice = findDeviceByEntity(srcEntity); - if (srcDevice == null) { - cntReconcileNoSource.increment(); - return Command.STOP; - } - // Store the source device in the context - fcStore.put(ofm.cntx, CONTEXT_SRC_DEVICE, srcDevice); - - // Find the device matching the destination from the entity - // classes of the source. - Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false); - Device dstDevice = null; - if (dstEntity != null) { - dstDevice = findDestByEntity(srcDevice.getEntityClass(), dstEntity); - if (dstDevice != null) - fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice); - else - cntReconcileNoDest.increment(); - } else { - cntReconcileNoDest.increment(); - } - if (logger.isTraceEnabled()) { - logger.trace("Reconciling flow: match={}, srcEntity={}, srcDev={}, " - + "dstEntity={}, dstDev={}", - new Object[] {ofm.ofmWithSwDpid.getOfMatch(), - srcEntity, srcDevice, - dstEntity, dstDevice } ); - } - return Command.CONTINUE; - } - - // ***************** - // IFloodlightModule - // ***************** - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IDeviceService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - // We are the class that implements the service - m.put(IDeviceService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IStorageSourceService.class); - l.add(ITopologyService.class); - l.add(IRestApiService.class); - l.add(IThreadPoolService.class); - l.add(IFlowReconcileService.class); - l.add(IEntityClassifierService.class); - l.add(ISyncService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext fmc) throws FloodlightModuleException { - this.perClassIndices = - new HashSet<EnumSet<DeviceField>>(); - addIndex(true, EnumSet.of(DeviceField.IPV4)); - - this.deviceListeners = new ListenerDispatcher<String, IDeviceListener>(); - this.suppressAPs = Collections.newSetFromMap( - new ConcurrentHashMap<SwitchPort, Boolean>()); - - this.floodlightProvider = - fmc.getServiceImpl(IFloodlightProviderService.class); - this.storageSource = - fmc.getServiceImpl(IStorageSourceService.class); - this.topology = - fmc.getServiceImpl(ITopologyService.class); - this.restApi = fmc.getServiceImpl(IRestApiService.class); - this.threadPool = fmc.getServiceImpl(IThreadPoolService.class); - this.flowReconcileMgr = fmc.getServiceImpl(IFlowReconcileService.class); - this.flowReconcileEngine = fmc.getServiceImpl(IFlowReconcileEngineService.class); - this.entityClassifier = fmc.getServiceImpl(IEntityClassifierService.class); - this.debugCounters = fmc.getServiceImpl(IDebugCounterService.class); - this.debugEvents = fmc.getServiceImpl(IDebugEventService.class); - this.syncService = fmc.getServiceImpl(ISyncService.class); - this.deviceSyncManager = new DeviceSyncManager(); - this.haListenerDelegate = new HAListenerDelegate(); - registerDeviceManagerDebugCounters(); - registerDeviceManagerDebugEvents(); - this.addListener(new DeviceDebugEventLogger()); - } - - private void registerDeviceManagerDebugEvents() throws FloodlightModuleException { - if (debugEvents == null) { - debugEvents = new NullDebugEvent(); - } - try { - evDevice = - debugEvents.registerEvent(PACKAGE, "hostevent", - "Host added, removed, updated, or moved", - EventType.ALWAYS_LOG, DeviceEvent.class, 500); - } catch (MaxEventsRegistered e) { - throw new FloodlightModuleException("Max events registered", e); - } - } - - @Override - public void startUp(FloodlightModuleContext fmc) - throws FloodlightModuleException { - isMaster = (floodlightProvider.getRole() == Role.MASTER); - primaryIndex = new DeviceUniqueIndex(entityClassifier.getKeyFields()); - secondaryIndexMap = new HashMap<EnumSet<DeviceField>, DeviceIndex>(); - - deviceMap = new ConcurrentHashMap<Long, Device>(); - classStateMap = - new ConcurrentHashMap<String, ClassState>(); - apComparator = new AttachmentPointComparator(); - - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - floodlightProvider.addHAListener(this.haListenerDelegate); - if (topology != null) - topology.addListener(this); - flowReconcileMgr.addFlowReconcileListener(this); - entityClassifier.addListener(this); - - ScheduledExecutorService ses = threadPool.getScheduledExecutor(); - Runnable ecr = new Runnable() { - @Override - public void run() { - cleanupEntities(); - entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL, - TimeUnit.SECONDS); - } - }; - entityCleanupTask = new SingletonTask(ses, ecr); - entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL, - TimeUnit.SECONDS); - - Runnable consolidateStoreRunner = new Runnable() { - @Override - public void run() { - deviceSyncManager.consolidateStore(); - storeConsolidateTask.reschedule(syncStoreConsolidateIntervalMs, - TimeUnit.MILLISECONDS); - } - }; - storeConsolidateTask = new SingletonTask(ses, consolidateStoreRunner); - if (isMaster) - storeConsolidateTask.reschedule(syncStoreConsolidateIntervalMs, - TimeUnit.MILLISECONDS); - - - if (restApi != null) { - restApi.addRestletRoutable(new DeviceRoutable()); - } else { - logger.debug("Could not instantiate REST API"); - } - - try { - this.syncService.registerStore(DEVICE_SYNC_STORE_NAME, Scope.LOCAL); - this.storeClient = this.syncService - .getStoreClient(DEVICE_SYNC_STORE_NAME, - String.class, - DeviceSyncRepresentation.class); - } catch (SyncException e) { - throw new FloodlightModuleException("Error while setting up sync service", e); - } - floodlightProvider.addInfoProvider("summary", this); - } - - private void registerDeviceManagerDebugCounters() throws FloodlightModuleException { - if (debugCounters == null) { - logger.error("Debug Counter Service not found."); - debugCounters = new NullDebugCounter(); - } - try { - cntIncoming = debugCounters.registerCounter(PACKAGE, "incoming", - "All incoming packets seen by this module", CounterType.ALWAYS_COUNT); - cntReconcileRequest = debugCounters.registerCounter(PACKAGE, - "reconcile-request", - "Number of flows that have been received for reconciliation by " + - "this module", - CounterType.ALWAYS_COUNT); - cntReconcileNoSource = debugCounters.registerCounter(PACKAGE, - "reconcile-no-source-device", - "Number of flow reconcile events that failed because no source " + - "device could be identified", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing - cntReconcileNoDest = debugCounters.registerCounter(PACKAGE, - "reconcile-no-dest-device", - "Number of flow reconcile events that failed because no " + - "destination device could be identified", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing - cntInvalidSource = debugCounters.registerCounter(PACKAGE, - "invalid-source", - "Number of packetIns that were discarded because the source " + - "MAC was invalid (broadcast, multicast, or zero)", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); - cntNoSource = debugCounters.registerCounter(PACKAGE, "no-source-device", - "Number of packetIns that were discarded because the " + - "could not identify a source device. This can happen if a " + - "packet is not allowed, appears on an illegal port, does not " + - "have a valid address space, etc.", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); - cntInvalidDest = debugCounters.registerCounter(PACKAGE, - "invalid-dest", - "Number of packetIns that were discarded because the dest " + - "MAC was invalid (zero)", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); - cntNoDest = debugCounters.registerCounter(PACKAGE, "no-dest-device", - "Number of packetIns that did not have an associated " + - "destination device. E.g., because the destination MAC is " + - "broadcast/multicast or is not yet known to the controller.", - CounterType.ALWAYS_COUNT); - cntDhcpClientNameSnooped = debugCounters.registerCounter(PACKAGE, - "dhcp-client-name-snooped", - "Number of times a DHCP client name was snooped from a " + - "packetIn.", - CounterType.ALWAYS_COUNT); - cntDeviceOnInternalPortNotLearned = debugCounters.registerCounter( - PACKAGE, - "device-on-internal-port-not-learned", - "Number of times packetIn was received on an internal port and" + - "no source device is known for the source MAC. The packetIn is " + - "discarded.", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); - cntPacketNotAllowed = debugCounters.registerCounter(PACKAGE, - "packet-not-allowed", - "Number of times a packetIn was not allowed due to spoofing " + - "protection configuration.", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing? - cntNewDevice = debugCounters.registerCounter(PACKAGE, "new-device", - "Number of times a new device was learned", - CounterType.ALWAYS_COUNT); - cntPacketOnInternalPortForKnownDevice = debugCounters.registerCounter( - PACKAGE, - "packet-on-internal-port-for-known-device", - "Number of times a packetIn was received on an internal port " + - "for a known device.", - CounterType.ALWAYS_COUNT); - cntNewEntity = debugCounters.registerCounter(PACKAGE, "new-entity", - "Number of times a new entity was learned for an existing device", - CounterType.ALWAYS_COUNT); - cntDeviceChanged = debugCounters.registerCounter(PACKAGE, "device-changed", - "Number of times device properties have changed", - CounterType.ALWAYS_COUNT); - cntDeviceMoved = debugCounters.registerCounter(PACKAGE, "device-moved", - "Number of times devices have moved", - CounterType.ALWAYS_COUNT); - cntCleanupEntitiesRuns = debugCounters.registerCounter(PACKAGE, - "cleanup-entities-runs", - "Number of times the entity cleanup task has been run", - CounterType.ALWAYS_COUNT); - cntEntityRemovedTimeout = debugCounters.registerCounter(PACKAGE, - "entity-removed-timeout", - "Number of times entities have been removed due to timeout " + - "(entity has been inactive for " + ENTITY_TIMEOUT/1000 + "s)", - CounterType.ALWAYS_COUNT); - cntDeviceDeleted = debugCounters.registerCounter(PACKAGE, "device-deleted", - "Number of devices that have been removed due to inactivity", - CounterType.ALWAYS_COUNT); - cntDeviceReclassifyDelete = debugCounters.registerCounter(PACKAGE, - "device-reclassify-delete", - "Number of devices that required reclassification and have been " + - "temporarily delete for reclassification", - CounterType.ALWAYS_COUNT); - cntDeviceStrored = debugCounters.registerCounter(PACKAGE, "device-stored", - "Number of device entries written or updated to the sync store", - CounterType.ALWAYS_COUNT); - cntDeviceStoreThrottled = debugCounters.registerCounter(PACKAGE, - "device-store-throttled", - "Number of times a device update to the sync store was " + - "requested but not performed because the same device entities " + - "have recently been updated already", - CounterType.ALWAYS_COUNT); - cntDeviceRemovedFromStore = debugCounters.registerCounter(PACKAGE, - "device-removed-from-store", - "Number of devices that were removed from the sync store " + - "because the local controller removed the device due to " + - "inactivity", - CounterType.ALWAYS_COUNT); - cntSyncException = debugCounters.registerCounter(PACKAGE, "sync-exception", - "Number of times an operation on the sync store resulted in " + - "sync exception", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // it this an error? - cntDevicesFromStore = debugCounters.registerCounter(PACKAGE, - "devices-from-store", - "Number of devices that were read from the sync store after " + - "the local controller transitioned from SLAVE to MASTER", - CounterType.ALWAYS_COUNT); - cntConsolidateStoreRuns = debugCounters.registerCounter(PACKAGE, - "consolidate-store-runs", - "Number of times the task to consolidate entries in the " + - "store witch live known devices has been run", - CounterType.ALWAYS_COUNT); - cntConsolidateStoreDevicesRemoved = debugCounters.registerCounter(PACKAGE, - "consolidate-store-devices-removed", - "Number of times a device has been removed from the sync " + - "store because no corresponding live device is known. " + - "This indicates a remote controller still writing device " + - "entries despite the local controller being MASTER or an " + - "incosistent store update from the local controller.", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); - cntTransitionToMaster = debugCounters.registerCounter(PACKAGE, - "transition-to-master", - "Number of times this controller has transitioned from SLAVE " + - "to MASTER role. Will be 0 or 1.", - CounterType.ALWAYS_COUNT); - } catch (CounterException e) { - throw new FloodlightModuleException(e.getMessage()); - } - } - - // *************** - // IHAListener - // *************** - - protected class HAListenerDelegate implements IHAListener { - @Override - public void transitionToMaster() { - DeviceManagerImpl.this.isMaster = true; - DeviceManagerImpl.this.deviceSyncManager.goToMaster(); - } - - @Override - public void controllerNodeIPsChanged( - Map<String, String> curControllerNodeIPs, - Map<String, String> addedControllerNodeIPs, - Map<String, String> removedControllerNodeIPs) { - // no-op - } - - @Override - public String getName() { - return DeviceManagerImpl.this.getName(); - } - - @Override - public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type, - String name) { - return ("topology".equals(name) || - "bvsmanager".equals(name)); - } - - @Override - public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type, - String name) { - // TODO Auto-generated method stub - return false; - } - } - - - // **************** - // Internal methods - // **************** - - protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, - FloodlightContext cntx) { - Ethernet eth = - IFloodlightProviderService.bcStore. - get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - // Extract source entity information - Entity srcEntity = - getSourceEntityFromPacket(eth, sw.getId(), pi.getInPort()); - if (srcEntity == null) { - cntInvalidSource.increment(); - return Command.STOP; - } - - // Learn from ARP packet for special VRRP settings. - // In VRRP settings, the source MAC address and sender MAC - // addresses can be different. In such cases, we need to learn - // the IP to MAC mapping of the VRRP IP address. The source - // entity will not have that information. Hence, a separate call - // to learn devices in such cases. - learnDeviceFromArpResponseData(eth, sw.getId(), pi.getInPort()); - - // Learn/lookup device information - Device srcDevice = learnDeviceByEntity(srcEntity); - if (srcDevice == null) { - cntNoSource.increment(); - return Command.STOP; - } - - // Store the source device in the context - fcStore.put(cntx, CONTEXT_SRC_DEVICE, srcDevice); - - // Find the device matching the destination from the entity - // classes of the source. - if (eth.getDestinationMAC().toLong() == 0) { - cntInvalidDest.increment(); - return Command.STOP; - } - Entity dstEntity = getDestEntityFromPacket(eth); - Device dstDevice = null; - if (dstEntity != null) { - dstDevice = - findDestByEntity(srcDevice.getEntityClass(), dstEntity); - if (dstDevice != null) - fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice); - else - cntNoDest.increment(); - } else { - cntNoDest.increment(); - } - - if (logger.isTraceEnabled()) { - logger.trace("Received PI: {} on switch {}, port {} *** eth={}" + - " *** srcDev={} *** dstDev={} *** ", - new Object[] { pi, sw.getStringId(), pi.getInPort(), eth, - srcDevice, dstDevice }); - } - - snoopDHCPClientName(eth, srcDevice); - - return Command.CONTINUE; - } - - /** - * Snoop and record client-provided host name from DHCP requests - * @param eth - * @param srcDevice - */ - private void snoopDHCPClientName(Ethernet eth, Device srcDevice) { - if (! (eth.getPayload() instanceof IPv4) ) - return; - IPv4 ipv4 = (IPv4) eth.getPayload(); - if (! (ipv4.getPayload() instanceof UDP) ) - return; - UDP udp = (UDP) ipv4.getPayload(); - if (!(udp.getPayload() instanceof DHCP)) - return; - DHCP dhcp = (DHCP) udp.getPayload(); - byte opcode = dhcp.getOpCode(); - if (opcode == DHCP.OPCODE_REQUEST) { - DHCPOption dhcpOption = dhcp.getOption( - DHCPOptionCode.OptionCode_Hostname); - if (dhcpOption != null) { - cntDhcpClientNameSnooped.increment(); - srcDevice.dhcpClientName = new String(dhcpOption.getData()); - } - } - } - - /** - * Check whether the given attachment point is valid given the current - * topology - * @param switchDPID the DPID - * @param switchPort the port - * @return true if it's a valid attachment point - */ - public boolean isValidAttachmentPoint(long switchDPID, - int switchPort) { - if (topology.isAttachmentPointPort(switchDPID, - (short)switchPort) == false) - return false; - - if (suppressAPs.contains(new SwitchPort(switchDPID, switchPort))) - return false; - - return true; - } - - /** - * Get sender IP 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 int getSrcNwAddr(Ethernet eth, long dlAddr) { - if (eth.getPayload() instanceof ARP) { - ARP arp = (ARP) eth.getPayload(); - if ((arp.getProtocolType() == ARP.PROTO_TYPE_IP) && - (Ethernet.toLong(arp.getSenderHardwareAddress()) == dlAddr)) { - return IPv4.toIPv4Address(arp.getSenderProtocolAddress()); - } - } - return 0; - } - - /** - * Parse an entity from an {@link Ethernet} packet. - * @param eth the packet to parse - * @param sw the switch on which the packet arrived - * @param pi the original packetin - * @return the entity from the packet - */ - protected Entity getSourceEntityFromPacket(Ethernet eth, - DatapathId swdpid, - OFPort port) { - MacAddress dlAddr = MacAddress.of(eth.getSourceMACAddress()); - - // Ignore broadcast/multicast source - if (dlAddr.isBroadcast() || dlAddr.isMulticast()) - return null; - // Ignore 0 source mac - if (dlAddr.getLong() == 0) - return null; - - VlanVid vlan = VlanVid.ofVlan(eth.getVlanID()); - IPv4Address nwSrc = getSrcNwAddr(eth, dlAddr); - return new Entity(dlAddr, - vlan, - nwSrc, - swdpid, - port, - new Date()); - } - - /** - * Learn device from ARP data in scenarios where the - * Ethernet source MAC is different from the sender hardware - * address in ARP data. - */ - protected void learnDeviceFromArpResponseData(Ethernet eth, - DatapathId swdpid, - OFPort port) { - - if (!(eth.getPayload() instanceof ARP)) return; - ARP arp = (ARP) eth.getPayload(); - - byte[] dlAddrArr = eth.getSourceMACAddress(); - long dlAddr = Ethernet.toLong(dlAddrArr); - - byte[] senderHardwareAddr = arp.getSenderHardwareAddress(); - long senderAddr = Ethernet.toLong(senderHardwareAddr); - - if (dlAddr == senderAddr) return; - - // Ignore broadcast/multicast source - if ((senderHardwareAddr[0] & 0x1) != 0) - return; - // Ignore zero sender mac - if (senderAddr == 0) - return; - - short vlan = eth.getVlanID(); - int nwSrc = IPv4.toIPv4Address(arp.getSenderProtocolAddress()); - - Entity e = new Entity(senderAddr, - ((vlan >= 0) ? vlan : null), - ((nwSrc != 0) ? nwSrc : null), - swdpid, - port, - new Date()); - - learnDeviceByEntity(e); - } - - /** - * Get a (partial) entity for the destination from the packet. - * @param eth - * @return - */ - protected Entity getDestEntityFromPacket(Ethernet eth) { - byte[] dlAddrArr = eth.getDestinationMACAddress(); - long dlAddr = Ethernet.toLong(dlAddrArr); - short vlan = eth.getVlanID(); - int nwDst = 0; - - // Ignore broadcast/multicast destination - if ((dlAddrArr[0] & 0x1) != 0) - return null; - // Ignore zero dest mac - if (dlAddr == 0) - return null; - - if (eth.getPayload() instanceof IPv4) { - IPv4 ipv4 = (IPv4) eth.getPayload(); - nwDst = ipv4.getDestinationAddress(); - } - - return new Entity(dlAddr, - ((vlan >= 0) ? vlan : null), - ((nwDst != 0) ? nwDst : null), - null, - null, - null); - } - - /** - * Parse an entity from an OFMatchWithSwDpid. - * @param ofmWithSwDpid - * @return the entity from the packet - */ - private Entity getEntityFromFlowMod(OFMatchWithSwDpid ofmWithSwDpid, - boolean isSource) { - byte[] dlAddrArr = ofmWithSwDpid.getOfMatch().getDataLayerSource(); - int nwSrc = ofmWithSwDpid.getOfMatch().getNetworkSource(); - if (!isSource) { - dlAddrArr = ofmWithSwDpid.getOfMatch().getDataLayerDestination(); - nwSrc = ofmWithSwDpid.getOfMatch().getNetworkDestination(); - } - - long dlAddr = Ethernet.toLong(dlAddrArr); - - // Ignore broadcast/multicast source - if ((dlAddrArr[0] & 0x1) != 0) - return null; - - Long swDpid = null; - Short inPort = null; - - if (isSource) { - swDpid = ofmWithSwDpid.getSwitchDataPathId(); - inPort = ofmWithSwDpid.getOfMatch().getInputPort(); - } - - /**for the new flow cache design, the flow mods retrived are not always - * from the source, learn AP should be disabled --meiyang*/ - boolean learnap = false; - /** - * if (swDpid == null || - inPort == null || - !isValidAttachmentPoint(swDpid, inPort)) { - // If this is an internal port or we otherwise don't want - // to learn on these ports. In the future, we should - // handle this case by labeling flows with something that - // will give us the entity class. For now, we'll do our - // best assuming attachment point information isn't used - // as a key field. - learnap = false; - } - */ - - short vlan = ofmWithSwDpid.getOfMatch().getDataLayerVirtualLan(); - return new Entity(dlAddr, - ((vlan >= 0) ? vlan : null), - ((nwSrc != 0) ? nwSrc : null), - (learnap ? swDpid : null), - (learnap ? (int)inPort : null), - new Date()); - } - - /** - * Look up a {@link Device} based on the provided {@link Entity}. We first - * check the primary index. If we do not find an entry there we classify - * the device into its IEntityClass and query the classIndex. - * This implies that all key field of the current IEntityClassifier must - * be present in the entity for the lookup to succeed! - * @param entity the entity to search for - * @return The {@link Device} object if found - */ - protected Device findDeviceByEntity(Entity entity) { - // Look up the fully-qualified entity to see if it already - // exists in the primary entity index. - Long deviceKey = primaryIndex.findByEntity(entity); - IEntityClass entityClass = null; - - if (deviceKey == null) { - // If the entity does not exist in the primary entity index, - // use the entity classifier for find the classes for the - // entity. Look up the entity in the returned class' - // class entity index. - entityClass = entityClassifier.classifyEntity(entity); - if (entityClass == null) { - return null; - } - ClassState classState = getClassState(entityClass); - - if (classState.classIndex != null) { - deviceKey = - classState.classIndex.findByEntity(entity); - } - } - if (deviceKey == null) return null; - return deviceMap.get(deviceKey); - } - - /** - * Get a destination device using entity fields that corresponds with - * the given source device. The source device is important since - * there could be ambiguity in the destination device without the - * attachment point information. - * @param reference the source device's entity class. - * The returned destination will be - * in the same entity class as the source. - * @param dstEntity the entity to look up - * @return an {@link Device} or null if no device is found. - */ - protected Device findDestByEntity(IEntityClass reference, - Entity dstEntity) { - - // Look up the fully-qualified entity to see if it - // exists in the primary entity index - Long deviceKey = primaryIndex.findByEntity(dstEntity); - - if (deviceKey == null) { - // This could happen because: - // 1) no destination known, or a broadcast destination - // 2) if we have attachment point key fields since - // attachment point information isn't available for - // destination devices. - // For the second case, we'll need to match up the - // destination device with the class of the source - // device. - ClassState classState = getClassState(reference); - if (classState.classIndex == null) { - return null; - } - deviceKey = classState.classIndex.findByEntity(dstEntity); - } - if (deviceKey == null) return null; - return deviceMap.get(deviceKey); - } - - /** - * Look up a {@link Device} within a particular entity class based on - * the provided {@link Entity}. - * @param clazz the entity class to search for the entity - * @param entity the entity to search for - * @return The {@link Device} object if found - private Device findDeviceInClassByEntity(IEntityClass clazz, - Entity entity) { - // XXX - TODO - throw new UnsupportedOperationException(); - } - */ - - /** - * Look up a {@link Device} based on the provided {@link Entity}. Also - * learns based on the new entity, and will update existing devices as - * required. - * - * @param entity the {@link Entity} - * @return The {@link Device} object if found - */ - protected Device learnDeviceByEntity(Entity entity) { - ArrayList<Long> deleteQueue = null; - LinkedList<DeviceUpdate> deviceUpdates = null; - Device device = null; - - // we may need to restart the learning process if we detect - // concurrent modification. Note that we ensure that at least - // one thread should always succeed so we don't get into infinite - // starvation loops - while (true) { - deviceUpdates = null; - - // Look up the fully-qualified entity to see if it already - // exists in the primary entity index. - Long deviceKey = primaryIndex.findByEntity(entity); - IEntityClass entityClass = null; - - if (deviceKey == null) { - // If the entity does not exist in the primary entity index, - // use the entity classifier for find the classes for the - // entity. Look up the entity in the returned class' - // class entity index. - entityClass = entityClassifier.classifyEntity(entity); - if (entityClass == null) { - // could not classify entity. No device - device = null; - break; - } - ClassState classState = getClassState(entityClass); - - if (classState.classIndex != null) { - deviceKey = - classState.classIndex.findByEntity(entity); - } - } - if (deviceKey != null) { - // If the primary or secondary index contains the entity - // use resulting device key to look up the device in the - // device map, and use the referenced Device below. - device = deviceMap.get(deviceKey); - if (device == null) { - // This can happen due to concurrent modification - if (logger.isDebugEnabled()) { - logger.debug("No device for deviceKey {} while " - + "while processing entity {}", - deviceKey, entity); - } - // if so, then try again till we don't even get the device key - // and so we recreate the device - continue; - } - } else { - // If the secondary index does not contain the entity, - // create a new Device object containing the entity, and - // generate a new device ID if the the entity is on an - // attachment point port. Otherwise ignore. - if (entity.hasSwitchPort() && - !topology.isAttachmentPointPort(entity.getSwitchDPID(), - entity.getSwitchPort())) { - cntDeviceOnInternalPortNotLearned.increment(); - if (logger.isDebugEnabled()) { - logger.debug("Not learning new device on internal" - + " link: {}", entity); - } - device = null; - break; - } - // Before we create the new device also check if - // the entity is allowed (e.g., for spoofing protection) - if (!isEntityAllowed(entity, entityClass)) { - cntPacketNotAllowed.increment(); - if (logger.isDebugEnabled()) { - logger.debug("PacketIn is not allowed {} {}", - entityClass.getName(), entity); - } - device = null; - break; - } - deviceKey = deviceKeyCounter.getAndIncrement(); - device = allocateDevice(deviceKey, entity, entityClass); - - - // Add the new device to the primary map with a simple put - deviceMap.put(deviceKey, device); - - // update indices - if (!updateIndices(device, deviceKey)) { - if (deleteQueue == null) - deleteQueue = new ArrayList<Long>(); - deleteQueue.add(deviceKey); - continue; - } - - updateSecondaryIndices(entity, entityClass, deviceKey); - - // We need to count and log here. If we log earlier we could - // hit a concurrent modification and restart the dev creation - // and potentially count the device twice. - cntNewDevice.increment(); - if (logger.isDebugEnabled()) { - logger.debug("New device created: {} deviceKey={}, entity={}", - new Object[]{device, deviceKey, entity}); - } - // generate new device update - deviceUpdates = - updateUpdates(deviceUpdates, - new DeviceUpdate(device, ADD, null)); - - break; - } - // if it gets here, we have a pre-existing Device for this Entity - if (!isEntityAllowed(entity, device.getEntityClass())) { - cntPacketNotAllowed.increment(); - if (logger.isDebugEnabled()) { - logger.info("PacketIn is not allowed {} {}", - device.getEntityClass().getName(), entity); - } - return null; - } - // If this is not an attachment point port we don't learn the new entity - // and don't update indexes. But we do allow the device to continue up - // the chain. - if (entity.hasSwitchPort() && - !topology.isAttachmentPointPort(entity.getSwitchDPID(), - entity.getSwitchPort())) { - 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) { - lastSeen = new Date(); - entity.setLastSeenTimestamp(lastSeen); - } - device.entities[entityindex].setLastSeenTimestamp(lastSeen); - // we break the loop after checking for changes to the AP - } else { - // New entity for this device - // compute the insertion point for the entity. - // see Arrays.binarySearch() - entityindex = -(entityindex + 1); - Device newDevice = allocateDevice(device, entity, entityindex); - - // generate updates - EnumSet<DeviceField> changedFields = - findChangedFields(device, entity); - - // update the device map with a replace call - boolean res = deviceMap.replace(deviceKey, device, newDevice); - // If replace returns false, restart the process from the - // beginning (this implies another thread concurrently - // modified this Device). - if (!res) - continue; - - device = newDevice; - // update indices - if (!updateIndices(device, deviceKey)) { - continue; - } - updateSecondaryIndices(entity, - device.getEntityClass(), - deviceKey); - - // We need to count here after all the possible "continue" - // statements in this branch - cntNewEntity.increment(); - if (changedFields.size() > 0) { - cntDeviceChanged.increment(); - deviceUpdates = - updateUpdates(deviceUpdates, - new DeviceUpdate(newDevice, CHANGE, - changedFields)); - } - // we break the loop after checking for changed AP - } - // Update attachment point (will only be hit if the device - // already existed and no concurrent modification) - if (entity.hasSwitchPort()) { - 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); - if (logger.isTraceEnabled()) { - logger.trace("Device moved: attachment points {}," + - "entities {}", device.attachmentPoints, - device.entities); - } - } else { - if (logger.isTraceEnabled()) { - logger.trace("Device attachment point updated: " + - "attachment points {}," + - "entities {}", device.attachmentPoints, - device.entities); - } - } - } - break; - } - - if (deleteQueue != null) { - for (Long l : deleteQueue) { - Device dev = deviceMap.get(l); - this.deleteDevice(dev); - } - } - - processUpdates(deviceUpdates); - deviceSyncManager.storeDeviceThrottled(device); - - return device; - } - - protected boolean isEntityAllowed(Entity entity, IEntityClass entityClass) { - return true; - } - - - - - - protected EnumSet<DeviceField> findChangedFields(Device device, - Entity newEntity) { - EnumSet<DeviceField> changedFields = - EnumSet.of(DeviceField.IPV4, - DeviceField.VLAN, - DeviceField.SWITCH); - - if (newEntity.getIpv4Address() == null) - changedFields.remove(DeviceField.IPV4); - if (newEntity.getVlan() == null) - changedFields.remove(DeviceField.VLAN); - if (newEntity.getSwitchDPID() == null || - newEntity.getSwitchPort() == null) - changedFields.remove(DeviceField.SWITCH); - - 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()))) - changedFields.remove(DeviceField.VLAN); - if (newEntity.getSwitchDPID() == null || - newEntity.getSwitchPort() == null || - (entity.getSwitchDPID() != null && - entity.getSwitchPort() != null && - entity.getSwitchDPID().equals(newEntity.getSwitchDPID()) && - entity.getSwitchPort().equals(newEntity.getSwitchPort()))) - changedFields.remove(DeviceField.SWITCH); - } - - return changedFields; - } - - /** - * Send update notifications to listeners - * @param updates the updates to process. - */ - protected void processUpdates(Queue<DeviceUpdate> updates) { - if (updates == null) return; - DeviceUpdate update = null; - while (null != (update = updates.poll())) { - if (logger.isTraceEnabled()) { - logger.trace("Dispatching device update: {}", update); - } - if (update.change == DeviceUpdate.Change.DELETE) - deviceSyncManager.removeDevice(update.device); - else - deviceSyncManager.storeDevice(update.device); - List<IDeviceListener> listeners = deviceListeners.getOrderedListeners(); - notifyListeners(listeners, update); - } - } - - protected void notifyListeners(List<IDeviceListener> listeners, DeviceUpdate update) { - if (listeners == null) { - return; - } - for (IDeviceListener listener : listeners) { - switch (update.change) { - case ADD: - listener.deviceAdded(update.device); - break; - case DELETE: - listener.deviceRemoved(update.device); - break; - case CHANGE: - for (DeviceField field : update.fieldsChanged) { - switch (field) { - case IPV4: - listener.deviceIPV4AddrChanged(update.device); - break; - case SWITCH: - case PORT: - //listener.deviceMoved(update.device); - break; - case VLAN: - listener.deviceVlanChanged(update.device); - break; - default: - logger.debug("Unknown device field changed {}", - update.fieldsChanged.toString()); - break; - } - } - break; - } - } - } - - /** - * Check if the entity e has all the keyFields set. Returns false if not - * @param e entity to check - * @param keyFields the key fields to check e against - * @return - */ - protected boolean allKeyFieldsPresent(Entity e, EnumSet<DeviceField> keyFields) { - for (DeviceField f : keyFields) { - switch (f) { - case MAC: - // MAC address is always present - break; - case IPV4: - if (e.ipv4Address == null) return false; - break; - case SWITCH: - if (e.switchDPID == null) return false; - break; - case PORT: - if (e.switchPort == null) return false; - break; - case VLAN: - // FIXME: vlan==null is ambiguous: it can mean: not present - // or untagged - //if (e.vlan == null) return false; - break; - default: - // we should never get here. unless somebody extended - // DeviceFields - throw new IllegalStateException(); - } - } - return true; - } - - private LinkedList<DeviceUpdate> - updateUpdates(LinkedList<DeviceUpdate> list, DeviceUpdate update) { - if (update == null) return list; - if (list == null) - list = new LinkedList<DeviceUpdate>(); - list.add(update); - - return list; - } - - /** - * Get the secondary index for a class. Will return null if the - * secondary index was created concurrently in another thread. - * @param clazz the class for the index - * @return - */ - private ClassState getClassState(IEntityClass clazz) { - ClassState classState = classStateMap.get(clazz.getName()); - if (classState != null) return classState; - - classState = new ClassState(clazz); - ClassState r = classStateMap.putIfAbsent(clazz.getName(), classState); - if (r != null) { - // concurrent add - return r; - } - return classState; - } - - /** - * Update both the primary and class indices for the provided device. - * If the update fails because of an concurrent update, will return false. - * @param device the device to update - * @param deviceKey the device key for the device - * @return true if the update succeeded, false otherwise. - */ - private boolean updateIndices(Device device, Long deviceKey) { - if (!primaryIndex.updateIndex(device, deviceKey)) { - return false; - } - IEntityClass entityClass = device.getEntityClass(); - ClassState classState = getClassState(entityClass); - - if (classState.classIndex != null) { - if (!classState.classIndex.updateIndex(device, - deviceKey)) - return false; - } - return true; - } - - /** - * Update the secondary indices for the given entity and associated - * entity classes - * @param entity the entity to update - * @param entityClass the entity class for the entity - * @param deviceKey the device key to set up - */ - private void updateSecondaryIndices(Entity entity, - IEntityClass entityClass, - Long deviceKey) { - for (DeviceIndex index : secondaryIndexMap.values()) { - index.updateIndex(entity, deviceKey); - } - ClassState state = getClassState(entityClass); - for (DeviceIndex index : state.secondaryIndexMap.values()) { - index.updateIndex(entity, deviceKey); - } - } - - /** - * Clean up expired entities/devices - */ - protected void cleanupEntities () { - cntCleanupEntitiesRuns.increment(); - - Calendar c = Calendar.getInstance(); - c.add(Calendar.MILLISECOND, -ENTITY_TIMEOUT); - Date cutoff = c.getTime(); - - ArrayList<Entity> toRemove = new ArrayList<Entity>(); - ArrayList<Entity> toKeep = new ArrayList<Entity>(); - - Iterator<Device> diter = deviceMap.values().iterator(); - LinkedList<DeviceUpdate> deviceUpdates = - new LinkedList<DeviceUpdate>(); - - while (diter.hasNext()) { - Device d = diter.next(); - - while (true) { - deviceUpdates.clear(); - toRemove.clear(); - toKeep.clear(); - for (Entity e : d.getEntities()) { - if (e.getLastSeenTimestamp() != null && - 0 > e.getLastSeenTimestamp().compareTo(cutoff)) { - // individual entity needs to be removed - toRemove.add(e); - } else { - toKeep.add(e); - } - } - if (toRemove.size() == 0) { - break; - } - - cntEntityRemovedTimeout.increment(); - for (Entity e : toRemove) { - removeEntity(e, d.getEntityClass(), d.getDeviceKey(), toKeep); - } - - if (toKeep.size() > 0) { - Device newDevice = allocateDevice(d.getDeviceKey(), - d.getDHCPClientName(), - d.oldAPs, - d.attachmentPoints, - toKeep, - d.getEntityClass()); - - EnumSet<DeviceField> changedFields = - EnumSet.noneOf(DeviceField.class); - for (Entity e : toRemove) { - changedFields.addAll(findChangedFields(newDevice, e)); - } - DeviceUpdate update = null; - if (changedFields.size() > 0) { - update = new DeviceUpdate(d, CHANGE, changedFields); - } - - if (!deviceMap.replace(newDevice.getDeviceKey(), - d, - newDevice)) { - // concurrent modification; try again - // need to use device that is the map now for the next - // iteration - d = deviceMap.get(d.getDeviceKey()); - if (null != d) - continue; - } - if (update != null) { - // need to count after all possibly continue stmts in - // this branch - cntDeviceChanged.increment(); - deviceUpdates.add(update); - } - } else { - DeviceUpdate update = new DeviceUpdate(d, DELETE, null); - if (!deviceMap.remove(d.getDeviceKey(), d)) { - // concurrent modification; try again - // need to use device that is the map now for the next - // iteration - d = deviceMap.get(d.getDeviceKey()); - if (null != d) - continue; - cntDeviceDeleted.increment(); - } - deviceUpdates.add(update); - } - processUpdates(deviceUpdates); - break; - } - } - // Since cleanupEntities() is not called in the packet-in pipeline, - // debugEvents need to be flushed explicitly - debugEvents.flushEvents(); - } - - protected void removeEntity(Entity removed, - IEntityClass entityClass, - Long deviceKey, - Collection<Entity> others) { - // Don't count in this method. This method CAN BE called to clean-up - // after concurrent device adds/updates and thus counting here - // is misleading - for (DeviceIndex index : secondaryIndexMap.values()) { - index.removeEntityIfNeeded(removed, deviceKey, others); - } - ClassState classState = getClassState(entityClass); - for (DeviceIndex index : classState.secondaryIndexMap.values()) { - index.removeEntityIfNeeded(removed, deviceKey, others); - } - - primaryIndex.removeEntityIfNeeded(removed, deviceKey, others); - - if (classState.classIndex != null) { - classState.classIndex.removeEntityIfNeeded(removed, - deviceKey, - others); - } - } - - /** - * method to delete a given device, remove all entities first and then - * finally delete the device itself. - * @param device - */ - protected void deleteDevice(Device device) { - // Don't count in this method. This method CAN BE called to clean-up - // after concurrent device adds/updates and thus counting here - // is misleading - ArrayList<Entity> emptyToKeep = new ArrayList<Entity>(); - for (Entity entity : device.getEntities()) { - this.removeEntity(entity, device.getEntityClass(), - device.getDeviceKey(), emptyToKeep); - } - if (!deviceMap.remove(device.getDeviceKey(), device)) { - if (logger.isDebugEnabled()) - logger.debug("device map does not have this device -" + - device.toString()); - } - } - - 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. - 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); - return keys; - } - - protected Iterator<Device> queryClassByEntity(IEntityClass clazz, - EnumSet<DeviceField> keyFields, - Entity entity) { - ClassState classState = getClassState(clazz); - DeviceIndex index = classState.secondaryIndexMap.get(keyFields); - if (index == null) return Collections.<Device>emptySet().iterator(); - return new DeviceIndexInterator(this, index.queryByEntity(entity)); - } - - protected Device allocateDevice(Long deviceKey, - Entity entity, - IEntityClass entityClass) { - return new Device(this, deviceKey, entity, entityClass); - } - - // TODO: FIX THIS. - protected Device allocateDevice(Long deviceKey, - String dhcpClientName, - List<AttachmentPoint> aps, - List<AttachmentPoint> trueAPs, - Collection<Entity> entities, - IEntityClass entityClass) { - return new Device(this, deviceKey, dhcpClientName, aps, trueAPs, - entities, entityClass); - } - - protected Device allocateDevice(Device device, - Entity entity, - int insertionpoint) { - return new Device(device, entity, insertionpoint); - } - - //not used - protected Device allocateDevice(Device device, Set <Entity> entities) { - List <AttachmentPoint> newPossibleAPs = - new ArrayList<AttachmentPoint>(); - List <AttachmentPoint> newAPs = - new ArrayList<AttachmentPoint>(); - for (Entity entity : entities) { - if (entity.switchDPID != null && entity.switchPort != null) { - AttachmentPoint aP = - new AttachmentPoint(entity.switchDPID, - entity.switchPort, new Date(0)); - newPossibleAPs.add(aP); - } - } - if (device.attachmentPoints != null) { - for (AttachmentPoint oldAP : device.attachmentPoints) { - if (newPossibleAPs.contains(oldAP)) { - newAPs.add(oldAP); - } - } - } - if (newAPs.isEmpty()) - newAPs = null; - Device d = new Device(this, device.getDeviceKey(), - device.getDHCPClientName(), newAPs, null, - entities, device.getEntityClass()); - d.updateAttachmentPoint(); - return d; - } - - // ********************* - // ITopologyListener - // ********************* - - /** - * Topology listener method. - */ - @Override - public void topologyChanged(List<LDUpdate> updateList) { - Iterator<Device> diter = deviceMap.values().iterator(); - if (updateList != null) { - if (logger.isTraceEnabled()) { - for(LDUpdate update: updateList) { - logger.trace("Topo update: {}", update); - } - } - } - - while (diter.hasNext()) { - Device d = diter.next(); - if (d.updateAttachmentPoint()) { - if (logger.isDebugEnabled()) { - logger.debug("Attachment point changed for device: {}", d); - } - sendDeviceMovedNotification(d); - } - } - // Since topologyChanged() does not occur in the packet-in pipeline, - // debugEvents need to be flushed explicitly - debugEvents.flushEvents(); - } - - /** - * Send update notifications to listeners - * @param updates the updates to process. - */ - protected void sendDeviceMovedNotification(Device d) { - cntDeviceMoved.increment(); - deviceSyncManager.storeDevice(d); - List<IDeviceListener> listeners = deviceListeners.getOrderedListeners(); - if (listeners != null) { - for (IDeviceListener listener : listeners) { - listener.deviceMoved(d); - } - } - } - - // ********************* - // IEntityClassListener - // ********************* - - @Override - public void entityClassChanged (Set<String> entityClassNames) { - /* iterate through the devices, reclassify the devices that belong - * to these entity class names - */ - Iterator<Device> diter = deviceMap.values().iterator(); - while (diter.hasNext()) { - Device d = diter.next(); - if (d.getEntityClass() == null || - entityClassNames.contains(d.getEntityClass().getName())) - reclassifyDevice(d); - } - } - - /** - * this method will reclassify and reconcile a device - possibilities - * are - create new device(s), remove entities from this device. If the - * device entity class did not change then it returns false else true. - * @param device - */ - protected boolean reclassifyDevice(Device device) - { - // first classify all entities of this device - if (device == null) { - logger.debug("In reclassify for null device"); - return false; - } - boolean needToReclassify = false; - for (Entity entity : device.entities) { - IEntityClass entityClass = - this.entityClassifier.classifyEntity(entity); - if (entityClass == null || device.getEntityClass() == null) { - needToReclassify = true; - break; - } - if (!entityClass.getName(). - equals(device.getEntityClass().getName())) { - needToReclassify = true; - break; - } - } - if (needToReclassify == false) { - return false; - } - - cntDeviceReclassifyDelete.increment(); - LinkedList<DeviceUpdate> deviceUpdates = - new LinkedList<DeviceUpdate>(); - // delete this device and then re-learn all the entities - this.deleteDevice(device); - deviceUpdates.add(new DeviceUpdate(device, - DeviceUpdate.Change.DELETE, null)); - if (!deviceUpdates.isEmpty()) - processUpdates(deviceUpdates); - for (Entity entity: device.entities ) { - this.learnDeviceByEntity(entity); - } - // Since reclassifyDevices() is not called in the packet-in pipeline, - // debugEvents need to be flushed explicitly - debugEvents.flushEvents(); - return true; - } - - /** - * For testing: sets the interval between writes of the same device - * to the device store. - * @param intervalMs - */ - void setSyncStoreWriteInterval(int intervalMs) { - this.syncStoreWriteIntervalMs = intervalMs; - } - - /** - * For testing: sets the time between transition to MASTER and - * consolidate store - * @param intervalMs - */ - void setInitialSyncStoreConsolidateMs(int intervalMs) { - this.initialSyncStoreConsolidateMs = intervalMs; - } - - /** - * For testing: consolidate the store NOW - */ - void scheduleConsolidateStoreNow() { - this.storeConsolidateTask.reschedule(0, TimeUnit.MILLISECONDS); - } - - private class DeviceSyncManager { - // maps (opaque) deviceKey to the time in System.nanoTime() when we - // last wrote the device to the sync store - private final ConcurrentMap<Long, Long> lastWriteTimes = - new ConcurrentHashMap<Long, Long>(); - - /** - * Write the given device to storage if we are MASTER. - * Use this method if the device has significantly changed (e.g., - * new AP, new IP, entities removed). - * @param d the device to store - */ - public void storeDevice(Device d) { - if (!isMaster) - return; - if (d == null) - return; - long now = System.nanoTime(); - writeUpdatedDeviceToStorage(d); - lastWriteTimes.put(d.getDeviceKey(), now); - } - - /** - * Write the given device to storage if we are MASTER and if the - * last write for the device was more than this.syncStoreIntervalNs - * time ago. - * Use this method to updated last active times in the store. - * @param d the device to store - */ - public void storeDeviceThrottled(Device d) { - long intervalNs = syncStoreWriteIntervalMs*1000L*1000L; - if (!isMaster) - return; - if (d == null) - return; - long now = System.nanoTime(); - Long last = lastWriteTimes.get(d.getDeviceKey()); - if (last == null || - now - last > intervalNs) { - writeUpdatedDeviceToStorage(d); - lastWriteTimes.put(d.getDeviceKey(), now); - } else { - cntDeviceStoreThrottled.increment(); - } - } - - /** - * Remove the given device from the store. If only some entities have - * been removed the updated device should be written using - * {@link #storeDevice(Device)} - * @param d - */ - public void removeDevice(Device d) { - if (!isMaster) - return; - // FIXME: could we have a problem with concurrent put to the - // hashMap? I.e., we write a stale entry to the map after the - // delete and now are left with an entry we'll never clean up - lastWriteTimes.remove(d.getDeviceKey()); - try { - // TODO: should probably do versioned delete. OTOH, even - // if we accidentally delete, we'll write it again after - // the next entity .... - cntDeviceRemovedFromStore.increment(); - storeClient.delete(DeviceSyncRepresentation.computeKey(d)); - } catch(ObsoleteVersionException e) { - // FIXME - } catch (SyncException e) { - cntSyncException.increment(); - logger.error("Could not remove device " + d + " from store", e); - } - } - - /** - * Remove the given Versioned device from the store. If the device - * was locally modified ignore the delete request. - * @param syncedDeviceKey - */ - private void removeDevice(Versioned<DeviceSyncRepresentation> dev) { - try { - cntDeviceRemovedFromStore.increment(); - storeClient.delete(dev.getValue().getKey(), - dev.getVersion()); - } catch(ObsoleteVersionException e) { - // Key was locally modified by another thread. - // Do not delete and ignore. - } catch(SyncException e) { - cntSyncException.increment(); - logger.error("Failed to remove device entry for " + - dev.toString() + " from store.", e); - } - } - - /** - * Synchronously transition from SLAVE to MASTER. By iterating through - * the store and learning all devices from the store - */ - private void goToMaster() { - if (logger.isDebugEnabled()) { - logger.debug("Transitioning to MASTER role"); - } - cntTransitionToMaster.increment(); - IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>> - iter = null; - try { - iter = storeClient.entries(); - } catch (SyncException e) { - cntSyncException.increment(); - logger.error("Failed to read devices from sync store", e); - return; - } - try { - while(iter.hasNext()) { - Versioned<DeviceSyncRepresentation> versionedDevice = - iter.next().getValue(); - DeviceSyncRepresentation storedDevice = - versionedDevice.getValue(); - if (storedDevice == null) - continue; - cntDevicesFromStore.increment(); - for(SyncEntity se: storedDevice.getEntities()) { - learnDeviceByEntity(se.asEntity()); - } - } - } finally { - if (iter != null) - iter.close(); - } - storeConsolidateTask.reschedule(initialSyncStoreConsolidateMs, - TimeUnit.MILLISECONDS); - } - - /** - * Actually perform the write of the device to the store - * FIXME: concurrent modification behavior - * @param device The device to write - */ - private void writeUpdatedDeviceToStorage(Device device) { - try { - cntDeviceStrored.increment(); - // FIXME: use a versioned put - DeviceSyncRepresentation storeDevice = - new DeviceSyncRepresentation(device); - storeClient.put(storeDevice.getKey(), storeDevice); - } catch (ObsoleteVersionException e) { - // FIXME: what's the right behavior here. Can the store client - // even throw this error? - } catch (SyncException e) { - cntSyncException.increment(); - logger.error("Could not write device " + device + - " to sync store:", e); - } - } - - /** - * Iterate through all entries in the sync store. For each device - * in the store check if any stored entity matches a live device. If - * no entities match a live device we remove the entry from the store. - * - * Note: we do not check if all devices known to device manager are - * in the store. We rely on regular packetIns for that. - * Note: it's possible that multiple entries in the store map to the - * same device. We don't check or handle this case. - * - * We need to perform this check after a SLAVE->MASTER transition to - * get rid of all entries the old master might have written to the - * store after we took over. We also run it regularly in MASTER - * state to ensure we don't have stale entries in the store - */ - private void consolidateStore() { - if (!isMaster) - return; - cntConsolidateStoreRuns.increment(); - if (logger.isDebugEnabled()) { - logger.debug("Running consolidateStore."); - } - IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>> - iter = null; - try { - iter = storeClient.entries(); - } catch (SyncException e) { - cntSyncException.increment(); - logger.error("Failed to read devices from sync store", e); - return; - } - try { - while(iter.hasNext()) { - boolean found = false; - Versioned<DeviceSyncRepresentation> versionedDevice = - iter.next().getValue(); - DeviceSyncRepresentation storedDevice = - versionedDevice.getValue(); - if (storedDevice == null) - continue; - for(SyncEntity se: storedDevice.getEntities()) { - try { - // Do we have a device for this entity?? - IDevice d = findDevice(se.macAddress, se.vlan, - se.ipv4Address, - se.switchDPID, - se.switchPort); - if (d != null) { - found = true; - break; - } - } catch (IllegalArgumentException e) { - // not all key fields provided. Skip entity - } - } - if (!found) { - // We currently DO NOT have a live device that - // matches the current device from the store. - // Delete device from store. - if (logger.isDebugEnabled()) { - logger.debug("Removing device {} from store. No " - + "corresponding live device", - storedDevice.getKey()); - } - cntConsolidateStoreDevicesRemoved.increment(); - removeDevice(versionedDevice); - } - } - } finally { - if (iter != null) - iter.close(); - } - } - } - - - /** - * For testing. Sets the syncService. Only call after init but before - * startUp. Used by MockDeviceManager - * @param syncService - */ - protected void setSyncServiceIfNotSet(ISyncService syncService) { - if (this.syncService == null) - this.syncService = syncService; - } - - /** - * For testing. - * @return - */ - IHAListener getHAListener() { - return this.haListenerDelegate; - } - - /** - * Device Event Class used to log Device related events - */ - private class DeviceEvent { - @EventColumn(name = "MAC", description = EventFieldType.MAC) - private final MacAddress macAddress; - @EventColumn(name = "IPs", description = EventFieldType.IPv4) - private final List<IPv4Address> ipv4Addresses; - @EventColumn(name = "Old Attachment Points", - description = EventFieldType.COLLECTION_ATTACHMENT_POINT) - private final List<SwitchPort> oldAttachmentPoints; - @EventColumn(name = "Current Attachment Points", - description = EventFieldType.COLLECTION_ATTACHMENT_POINT) - private final List<SwitchPort> currentAttachmentPoints; - @EventColumn(name = "VLAN IDs", description = EventFieldType.COLLECTION_OBJECT) - private final List<VlanVid> vlanIds; - @EventColumn(name = "Reason", description = EventFieldType.STRING) - private final String reason; - - public DeviceEvent(MacAddress macAddress, List<IPv4Address> ipv4Addresses, - List<SwitchPort> oldAttachmentPoints, - List<SwitchPort> currentAttachmentPoints, - List<VlanVid> vlanIds, String reason) { - super(); - this.macAddress = macAddress; - this.ipv4Addresses = ipv4Addresses; - this.oldAttachmentPoints = oldAttachmentPoints; - this.currentAttachmentPoints = currentAttachmentPoints; - this.vlanIds = vlanIds; - this.reason = reason; - } - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java deleted file mode 100644 index c6aa9808e78a598c350ad388a7f5c06711ee8436..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java +++ /dev/null @@ -1,108 +0,0 @@ -/** -* Copyright 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.devicemanager.internal; - -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.util.IterableIterator; - -/** - * An index that maps key fields of an entity to device keys, with multiple - * device keys allowed per entity - */ -public class DeviceMultiIndex extends DeviceIndex { - /** - * The index - */ - private ConcurrentHashMap<IndexedEntity, Collection<Long>> index; - - /** - * @param keyFields - */ - public DeviceMultiIndex(EnumSet<DeviceField> keyFields) { - super(keyFields); - index = new ConcurrentHashMap<IndexedEntity, Collection<Long>>(); - } - - // *********** - // DeviceIndex - // *********** - - @Override - public Iterator<Long> queryByEntity(Entity entity) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - Collection<Long> devices = index.get(ie); - if (devices != null) - return devices.iterator(); - - return Collections.<Long>emptySet().iterator(); - } - - @Override - public Iterator<Long> getAll() { - Iterator<Collection<Long>> iter = index.values().iterator(); - return new IterableIterator<Long>(iter); - } - - @Override - public boolean updateIndex(Device device, Long deviceKey) { - for (Entity e : device.entities) { - updateIndex(e, deviceKey); - } - return true; - } - - @Override - public void updateIndex(Entity entity, Long deviceKey) { - Collection<Long> devices = null; - - IndexedEntity ie = new IndexedEntity(keyFields, entity); - if (!ie.hasNonNullKeys()) return; - - devices = index.get(ie); - if (devices == null) { - Map<Long,Boolean> chm = new ConcurrentHashMap<Long,Boolean>(); - devices = Collections.newSetFromMap(chm); - Collection<Long> r = index.putIfAbsent(ie, devices); - if (r != null) - devices = r; - } - - devices.add(deviceKey); - } - - @Override - public void removeEntity(Entity entity) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - index.remove(ie); - } - - @Override - public void removeEntity(Entity entity, Long deviceKey) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - Collection<Long> devices = index.get(ie); - if (devices != null) - devices.remove(deviceKey); - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java deleted file mode 100644 index b1c395d4c9664553550685125f686bdf87508283..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java +++ /dev/null @@ -1,166 +0,0 @@ -package net.floodlightcontroller.devicemanager.internal; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.List; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.VlanVid; - -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.SwitchPort; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class DeviceSyncRepresentation { - public static class SyncEntity implements Comparable<SyncEntity> { - @JsonProperty - public MacAddress macAddress; - @JsonProperty - public IPv4Address ipv4Address; - @JsonProperty - public VlanVid vlan; - @JsonProperty - public DatapathId switchDPID; - @JsonProperty - public OFPort switchPort; - @JsonProperty - public Date lastSeenTimestamp; - @JsonProperty - public Date activeSince; - - public SyncEntity() { - // do nothing; - } - - public SyncEntity(Entity e) { - this.macAddress = e.getMacAddress(); - this.ipv4Address = e.getIpv4Address(); - this.vlan = e.getVlan(); - this.switchDPID = e.getSwitchDPID(); - this.switchPort = e.getSwitchPort(); - 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, vlan, ipv4Address, switchDPID, - 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; - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java deleted file mode 100644 index 4811013e77258654c9577b0271a51f72c31bfd8d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java +++ /dev/null @@ -1,116 +0,0 @@ -/** -* Copyright 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.devicemanager.internal; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; - -/** - * An index that maps key fields of an entity uniquely to a device key - */ -public class DeviceUniqueIndex extends DeviceIndex { - /** - * The index - */ - private final ConcurrentHashMap<IndexedEntity, Long> index; - - /** - * Construct a new device index using the provided key fields - * @param keyFields the key fields to use - */ - public DeviceUniqueIndex(EnumSet<DeviceField> keyFields) { - super(keyFields); - index = new ConcurrentHashMap<IndexedEntity, Long>(); - } - - // *********** - // DeviceIndex - // *********** - - @Override - public Iterator<Long> queryByEntity(Entity entity) { - final Long deviceKey = findByEntity(entity); - if (deviceKey != null) - return Collections.<Long>singleton(deviceKey).iterator(); - - return Collections.<Long>emptySet().iterator(); - } - - @Override - public Iterator<Long> getAll() { - return index.values().iterator(); - } - - @Override - public boolean updateIndex(Device device, Long deviceKey) { - for (Entity e : device.entities) { - IndexedEntity ie = new IndexedEntity(keyFields, e); - if (!ie.hasNonNullKeys()) continue; - - Long ret = index.putIfAbsent(ie, deviceKey); - if (ret != null && !ret.equals(deviceKey)) { - // If the return value is non-null, then fail the insert - // (this implies that a device using this entity has - // already been created in another thread). - return false; - } - } - return true; - } - - @Override - public void updateIndex(Entity entity, Long deviceKey) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - if (!ie.hasNonNullKeys()) return; - index.put(ie, deviceKey); - } - - @Override - public void removeEntity(Entity entity) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - index.remove(ie); - } - - @Override - public void removeEntity(Entity entity, Long deviceKey) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - index.remove(ie, deviceKey); - } - - // ************** - // Public Methods - // ************** - - /** - * Look up a {@link Device} based on the provided {@link Entity}. - * @param entity the entity to search for - * @return The key for the {@link Device} object if found - */ - public Long findByEntity(Entity entity) { - IndexedEntity ie = new IndexedEntity(keyFields, entity); - Long deviceKey = index.get(ie); - if (deviceKey == null) - return null; - return deviceKey; - } - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java deleted file mode 100644 index 39a8d79cd7c67b8e08522943bc97055b1d45745d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java +++ /dev/null @@ -1,288 +0,0 @@ -/** -* 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.devicemanager.internal; - -import java.util.Date; - -import net.floodlightcontroller.core.web.serializers.IPv4Serializer; -import net.floodlightcontroller.core.web.serializers.MACSerializer; -import net.floodlightcontroller.core.web.serializers.DPIDSerializer; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.VlanVid; - -/** - * An entity on the network is a visible trace of a device that corresponds - * to a packet received from a particular interface on the edge of a network, - * with a particular VLAN tag, and a particular MAC address, along with any - * other packet characteristics we might want to consider as helpful for - * disambiguating devices. - * - * Entities are the most basic element of devices; devices consist of one or - * more entities. Entities are immutable once created, except for the last - * seen timestamp. - * - * @author readams - * - */ -public class Entity implements Comparable<Entity> { - /** - * Timeout for computing {@link Entity#activeSince}. - * @see {@link Entity#activeSince} - */ - protected static int ACTIVITY_TIMEOUT = 30000; - - /** - * The MAC address associated with this entity - */ - protected MacAddress macAddress; - - /** - * The IP address associated with this entity, or null if no IP learned - * from the network observation associated with this entity - */ - protected IPv4Address ipv4Address; - - /** - * The VLAN tag on this entity, or null if untagged - */ - protected VlanVid vlan; - - /** - * The DPID of the switch for the ingress point for this entity, - * or null if not present - */ - protected DatapathId switchDPID; - - /** - * The port number of the switch for the ingress point for this entity, - * or null if not present - */ - protected OFPort switchPort; - - /** - * The last time we observed this entity on the network - */ - protected Date lastSeenTimestamp; - - /** - * The time between {@link Entity#activeSince} and - * {@link Entity#lastSeenTimestamp} is a period of activity for this - * entity where it was observed repeatedly. If, when the entity is - * observed, the is longer ago than the activity timeout, - * {@link Entity#lastSeenTimestamp} and {@link Entity#activeSince} will - * be set to the current time. - */ - protected Date activeSince; - - private int hashCode = 0; - - // ************ - // Constructors - // ************ - - /** - * Create a new entity - * - * @param macAddress - * @param vlan - * @param ipv4Address - * @param switchDPID - * @param switchPort - * @param lastSeenTimestamp - */ - public Entity(MacAddress macAddress, VlanVid vlan, - IPv4Address ipv4Address, DatapathId switchDPID, OFPort switchPort, - Date lastSeenTimestamp) { - this.macAddress = macAddress; - this.ipv4Address = ipv4Address; - this.vlan = vlan; - this.switchDPID = switchDPID; - this.switchPort = switchPort; - this.lastSeenTimestamp = lastSeenTimestamp; - this.activeSince = lastSeenTimestamp; - } - - // *************** - // Getters/Setters - // *************** - - @JsonSerialize(using=MACSerializer.class) - public MacAddress getMacAddress() { - return macAddress; - } - - @JsonSerialize(using=IPv4Serializer.class) - public IPv4Address getIpv4Address() { - return ipv4Address; - } - - public VlanVid getVlan() { - return vlan; - } - - @JsonSerialize(using=DPIDSerializer.class) - public DatapathId getSwitchDPID() { - return switchDPID; - } - - public OFPort getSwitchPort() { - return switchPort; - } - - @JsonIgnore - public boolean hasSwitchPort() { - return (switchDPID != null && switchPort != null); - } - - public Date getLastSeenTimestamp() { - return lastSeenTimestamp; - } - - /** - * Set the last seen timestamp and also update {@link Entity#activeSince} - * if appropriate - * @param lastSeenTimestamp the new last seen timestamp - * @see {@link Entity#activeSince} - */ - public void setLastSeenTimestamp(Date lastSeenTimestamp) { - if (activeSince == null || - (activeSince.getTime() + ACTIVITY_TIMEOUT) < - lastSeenTimestamp.getTime()) - this.activeSince = lastSeenTimestamp; - this.lastSeenTimestamp = lastSeenTimestamp; - } - - public Date getActiveSince() { - return activeSince; - } - - public void setActiveSince(Date activeSince) { - this.activeSince = activeSince; - } - - @Override - public int hashCode() { - if (hashCode != 0) return hashCode; - final int prime = 31; - hashCode = 1; - hashCode = prime * hashCode - + ((ipv4Address == null) ? 0 : ipv4Address.hashCode()); - hashCode = prime * hashCode + (int) (macAddress.getLong() ^ (macAddress.getLong() >>> 32)); - hashCode = prime * hashCode - + ((switchDPID == null) ? 0 : switchDPID.hashCode()); - hashCode = prime * hashCode - + ((switchPort == null) ? 0 : switchPort.hashCode()); - hashCode = prime * hashCode + ((vlan == null) ? 0 : vlan.hashCode()); - return hashCode; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Entity other = (Entity) obj; - if (hashCode() != other.hashCode()) return false; - if (ipv4Address == null) { - if (other.ipv4Address != null) return false; - } else if (!ipv4Address.equals(other.ipv4Address)) return false; - if (macAddress != other.macAddress) return false; - if (switchDPID == null) { - if (other.switchDPID != null) return false; - } else if (!switchDPID.equals(other.switchDPID)) return false; - if (switchPort == null) { - if (other.switchPort != null) return false; - } else if (!switchPort.equals(other.switchPort)) return false; - if (vlan == null) { - if (other.vlan != null) return false; - } else if (!vlan.equals(other.vlan)) return false; - return true; - } - - - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Entity [macAddress="); - builder.append(macAddress.toString()); - builder.append(", ipv4Address="); - builder.append(ipv4Address.toString()); - builder.append(", vlan="); - builder.append(vlan.getVlan()); - builder.append(", switchDPID="); - builder.append(switchDPID.toString()); - builder.append(", switchPort="); - builder.append(switchPort.getPortNumber()); - builder.append(", lastSeenTimestamp="); - builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.getTime()); - builder.append(", activeSince="); - builder.append(activeSince == null? "null" : activeSince.getTime()); - builder.append("]"); - return builder.toString(); - } - - @Override - public int compareTo(Entity o) { - if (macAddress.getLong() < o.macAddress.getLong()) return -1; - if (macAddress.getLong() > o.macAddress.getLong()) return 1; - - int r; - if (switchDPID == null) - r = o.switchDPID == null ? 0 : -1; - else if (o.switchDPID == null) - r = 1; - else - r = switchDPID.compareTo(o.switchDPID); - if (r != 0) return r; - - if (switchPort == null) - r = o.switchPort == null ? 0 : -1; - else if (o.switchPort == null) - r = 1; - else - r = switchPort.compareTo(o.switchPort); - if (r != 0) return r; - - if (ipv4Address == null) - r = o.ipv4Address == null ? 0 : -1; - else if (o.ipv4Address == null) - r = 1; - else - r = ipv4Address.compareTo(o.ipv4Address); - if (r != 0) return r; - - if (vlan == null) - r = o.vlan == null ? 0 : -1; - else if (o.vlan == null) - r = 1; - else - r = vlan.compareTo(o.vlan); - if (r != 0) return r; - - return 0; - } - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java deleted file mode 100644 index a1e7160b2b4987ffa2d87a07b3d6367a191ba43c..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - **/ - -package net.floodlightcontroller.devicemanager.internal; - -import java.util.EnumSet; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; - - -/** - * This is a thin wrapper around {@link Entity} that allows overriding - * the behavior of {@link Object#hashCode()} and {@link Object#equals(Object)} - * so that the keying behavior in a hash map can be changed dynamically - * @author readams - */ -public class IndexedEntity { - protected EnumSet<DeviceField> keyFields; - protected Entity entity; - private int hashCode = 0; - protected static Logger logger = - LoggerFactory.getLogger(IndexedEntity.class); - /** - * Create a new {@link IndexedEntity} for the given {@link Entity} using - * the provided key fields. - * @param keyFields The key fields that will be used for computing - * {@link IndexedEntity#hashCode()} and {@link IndexedEntity#equals(Object)} - * @param entity the entity to wrap - */ - public IndexedEntity(EnumSet<DeviceField> keyFields, Entity entity) { - super(); - this.keyFields = keyFields; - this.entity = entity; - } - - /** - * Check whether this entity has non-null values in any of its key fields - * @return true if any key fields have a non-null value - */ - public boolean hasNonNullKeys() { - for (DeviceField f : keyFields) { - switch (f) { - case MAC: - return true; - case IPV4: - if (entity.ipv4Address != null) return true; - break; - case SWITCH: - if (entity.switchDPID != null) return true; - break; - case PORT: - if (entity.switchPort != null) return true; - break; - case VLAN: - if (entity.vlan != null) return true; - break; - } - } - return false; - } - - @Override - public int hashCode() { - - if (hashCode != 0) { - return hashCode; - } - - final int prime = 31; - hashCode = 1; - for (DeviceField f : keyFields) { - switch (f) { - case MAC: - hashCode = prime * hashCode - + (int) (entity.macAddress.getLong() ^ - (entity.macAddress.getLong() >>> 32)); - break; - case IPV4: - hashCode = prime * hashCode - + ((entity.ipv4Address == null) - ? 0 - : entity.ipv4Address.hashCode()); - break; - case SWITCH: - hashCode = prime * hashCode - + ((entity.switchDPID == null) - ? 0 - : entity.switchDPID.hashCode()); - break; - case PORT: - hashCode = prime * hashCode - + ((entity.switchPort == null) - ? 0 - : entity.switchPort.hashCode()); - break; - case VLAN: - hashCode = prime * hashCode - + ((entity.vlan == null) - ? 0 - : entity.vlan.hashCode()); - break; - } - } - return hashCode; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - IndexedEntity other = (IndexedEntity) obj; - - if (!keyFields.equals(other.keyFields)) - return false; - - for (IDeviceService.DeviceField f : keyFields) { - switch (f) { - case MAC: - if (entity.macAddress != other.entity.macAddress) - return false; - break; - 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 SWITCH: - if (entity.switchDPID == null) { - if (other.entity.switchDPID != null) return false; - } else if (!entity.switchDPID. - equals(other.entity.switchDPID)) return false; - break; - case PORT: - if (entity.switchPort == null) { - if (other.entity.switchPort != null) return false; - } else if (!entity.switchPort. - equals(other.entity.switchPort)) return false; - break; - case VLAN: - if (entity.vlan == null) { - if (other.entity.vlan != null) return false; - } else if (!entity.vlan. - equals(other.entity.vlan)) return false; - break; - } - } - - return true; - } - - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java b/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java deleted file mode 100644 index 7866b7914a57f0e7e91f6e2b2283a12c3df64d46..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java +++ /dev/null @@ -1,200 +0,0 @@ -/** -* Copyright 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.devicemanager.web; - -import java.util.Iterator; - -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.devicemanager.internal.Device; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.util.FilterIterator; - -import org.openflow.util.HexString; -import org.restlet.data.Form; -import org.restlet.data.Status; -import org.restlet.resource.ServerResource; - -/** - * Resource for querying and displaying devices that exist in the system - */ -public abstract class AbstractDeviceResource extends ServerResource { - public static final String MAC_ERROR = - "Invalid MAC address: must be a 48-bit quantity, " + - "expressed in hex as AA:BB:CC:DD:EE:FF"; - public static final String VLAN_ERROR = - "Invalid VLAN: must be an integer in the range 0-4095"; - public static final String IPV4_ERROR = - "Invalid IPv4 address: must be in dotted decimal format, " + - "234.0.59.1"; - 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"; - public static final String PORT_ERROR = - "Invalid Port: must be a positive integer"; - - public Iterator<? extends IDevice> getDevices() { - IDeviceService deviceManager = - (IDeviceService)getContext().getAttributes(). - get(IDeviceService.class.getCanonicalName()); - - Long macAddress = null; - Short vlan = null; - Integer ipv4Address = null; - Long switchDPID = null; - Integer switchPort = null; - - Form form = getQuery(); - String macAddrStr = form.getFirstValue("mac", true); - String vlanStr = form.getFirstValue("vlan", true); - String ipv4Str = form.getFirstValue("ipv4", true); - String dpid = form.getFirstValue("dpid", true); - String port = form.getFirstValue("port", true); - - if (macAddrStr != null) { - try { - macAddress = HexString.toLong(macAddrStr); - } catch (Exception e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, MAC_ERROR); - return null; - } - } - if (vlanStr != null) { - try { - vlan = Short.parseShort(vlanStr); - if (vlan > 4095 || vlan < 0) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR); - return null; - } - } catch (Exception e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR); - return null; - } - } - if (ipv4Str != null) { - try { - ipv4Address = IPv4.toIPv4Address(ipv4Str); - } catch (Exception e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, IPV4_ERROR); - return null; - } - } - if (dpid != null) { - try { - switchDPID = HexString.toLong(dpid); - } catch (Exception e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR); - return null; - } - } - if (port != null) { - try { - switchPort = Integer.parseInt(port); - if (switchPort < 0) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR); - return null; - } - } catch (Exception e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR); - return null; - } - } - - @SuppressWarnings("unchecked") - Iterator<Device> diter = (Iterator<Device>) - deviceManager.queryDevices(macAddress, - vlan, - ipv4Address, - switchDPID, - switchPort); - - final String macStartsWith = - form.getFirstValue("mac__startswith", true); - final String vlanStartsWith = - form.getFirstValue("vlan__startswith", true); - final String ipv4StartsWith = - form.getFirstValue("ipv4__startswith", true); - final String dpidStartsWith = - form.getFirstValue("dpid__startswith", true); - final String portStartsWith = - form.getFirstValue("port__startswith", true); - - return new FilterIterator<Device>(diter) { - @Override - protected boolean matches(Device value) { - if (macStartsWith != null) { - if (!value.getMACAddressString().startsWith(macStartsWith)) - return false; - } - if (vlanStartsWith != null) { - boolean match = false; - for (Short v : value.getVlanId()) { - if (v != null && - v.toString().startsWith(vlanStartsWith)) { - match = true; - break; - } - } - if (!match) return false; - } - if (ipv4StartsWith != null) { - boolean match = false; - for (Integer v : value.getIPv4Addresses()) { - String str; - if (v != null && - (str = IPv4.fromIPv4Address(v)) != null && - str.startsWith(ipv4StartsWith)) { - match = true; - break; - } - } - if (!match) return false; - } - if (dpidStartsWith != null) { - boolean match = false; - for (SwitchPort v : value.getAttachmentPoints(true)) { - String str; - if (v != null && - (str = HexString.toHexString(v.getSwitchDPID(), - 8)) != null && - str.startsWith(dpidStartsWith)) { - match = true; - break; - } - } - if (!match) return false; - } - if (portStartsWith != null) { - boolean match = false; - for (SwitchPort v : value.getAttachmentPoints(true)) { - String str; - if (v != null && - (str = Integer.toString(v.getPort())) != null && - str.startsWith(portStartsWith)) { - match = true; - break; - } - } - if (!match) return false; - } - return true; - } - }; - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceEntityResource.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceEntityResource.java deleted file mode 100644 index 2783a26d21744eddf3cb240fd62e10d996b6f170..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceEntityResource.java +++ /dev/null @@ -1,55 +0,0 @@ -/** -* Copyright 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.devicemanager.web; - -import java.util.Iterator; - -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.internal.Device; -import net.floodlightcontroller.devicemanager.internal.Entity; - -import org.restlet.resource.Get; - -/** - * Resource for querying and displaying internal debug information on - * network entities associated with devices - */ -public class DeviceEntityResource extends AbstractDeviceResource { - @Get("json") - public Iterator<Entity[]> getDeviceEntities() { - final Iterator<? extends IDevice> devices = super.getDevices(); - return new Iterator<Entity[]>() { - - @Override - public boolean hasNext() { - return devices.hasNext(); - } - - @Override - public Entity[] next() { - Device d = (Device)devices.next(); - return d.getEntities(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceResource.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceResource.java deleted file mode 100644 index c479af0c812dac489f6127b11d6b6e78fc13ebda..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceResource.java +++ /dev/null @@ -1,33 +0,0 @@ -/** -* Copyright 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.devicemanager.web; - -import java.util.Iterator; - -import net.floodlightcontroller.devicemanager.IDevice; -import org.restlet.resource.Get; - -/** - * Resource for querying and displaying devices that exist in the system - */ -public class DeviceResource extends AbstractDeviceResource { - @Get("json") - public Iterator<? extends IDevice> getDevices() { - return super.getDevices(); - } -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java deleted file mode 100644 index 9a765059812e49c673af1d7c9e085e8f1a3ac204..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java +++ /dev/null @@ -1,44 +0,0 @@ -/** -* Copyright 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.devicemanager.web; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -import net.floodlightcontroller.restserver.RestletRoutable; - -/** - * Routable for device rest api - */ -public class DeviceRoutable implements RestletRoutable { - - @Override - public String basePath() { - return "/wm/device"; - } - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/", DeviceResource.class); - router.attach("/debug", DeviceEntityResource.class); - return router; - } - -} diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java deleted file mode 100644 index 26b2027aaa34ece55d1541a3f60bb058d27e74e3..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java +++ /dev/null @@ -1,75 +0,0 @@ -/** -* Copyright 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.devicemanager.web; - -import java.io.IOException; - -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.devicemanager.internal.Device; -import net.floodlightcontroller.packet.IPv4; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import org.openflow.util.HexString; - -/** - * Serialize a device object - */ -public class DeviceSerializer extends JsonSerializer<Device> { - - @Override - public void serialize(Device device, JsonGenerator jGen, - SerializerProvider serializer) throws IOException, - JsonProcessingException { - jGen.writeStartObject(); - - jGen.writeStringField("entityClass", device.getEntityClass().getName()); - - jGen.writeArrayFieldStart("mac"); - jGen.writeString(HexString.toHexString(device.getMACAddress(), 6)); - jGen.writeEndArray(); - - jGen.writeArrayFieldStart("ipv4"); - for (Integer ip : device.getIPv4Addresses()) - jGen.writeString(IPv4.fromIPv4Address(ip)); - jGen.writeEndArray(); - - jGen.writeArrayFieldStart("vlan"); - for (Short vlan : device.getVlanId()) - if (vlan >= 0) - jGen.writeNumber(vlan); - jGen.writeEndArray(); - jGen.writeArrayFieldStart("attachmentPoint"); - for (SwitchPort ap : device.getAttachmentPoints(true)) { - serializer.defaultSerializeValue(ap, jGen); - } - jGen.writeEndArray(); - - jGen.writeNumberField("lastSeen", device.getLastSeen().getTime()); - - String dhcpClientName = device.getDHCPClientName(); - if (dhcpClientName != null) { - jGen.writeStringField("dhcpClientName", dhcpClientName); - } - - jGen.writeEndObject(); - } - -} diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java deleted file mode 100644 index 6b6b5578f06dbe18416fc0eb166a7245dd076f4f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java +++ /dev/null @@ -1,689 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.EthType; -import org.projectfloodlight.openflow.types.IPv4AddressWithMask; -import org.projectfloodlight.openflow.types.IpProtocol; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.TransportPort; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.devicemanager.IDeviceService; - -import java.util.ArrayList; - -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.routing.IRoutingDecision; -import net.floodlightcontroller.routing.RoutingDecision; -import net.floodlightcontroller.storage.IResultSet; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.StorageException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Stateless firewall implemented as a Google Summer of Code project. - * Configuration done through REST API - * - * @author Amer Tahir - * @edited KC Wang - */ -public class Firewall implements IFirewallService, IOFMessageListener, - IFloodlightModule { - - // service modules needed - protected IFloodlightProviderService floodlightProvider; - protected IStorageSourceService storageSource; - protected IRestApiService restApi; - protected static Logger logger; - - protected List<FirewallRule> rules; // protected by synchronized - protected boolean enabled; - protected int subnet_mask = IPv4.toIPv4Address("255.255.255.0"); - - // constant strings for storage/parsing - public static final String TABLE_NAME = "controller_firewallrules"; - public static final String COLUMN_RULEID = "ruleid"; - public static final String COLUMN_DPID = "dpid"; - public static final String COLUMN_IN_PORT = "in_port"; - public static final String COLUMN_DL_SRC = "dl_src"; - public static final String COLUMN_DL_DST = "dl_dst"; - public static final String COLUMN_DL_TYPE = "dl_type"; - public static final String COLUMN_NW_SRC_PREFIX = "nw_src_prefix"; - public static final String COLUMN_NW_SRC_MASKBITS = "nw_src_maskbits"; - public static final String COLUMN_NW_DST_PREFIX = "nw_dst_prefix"; - public static final String COLUMN_NW_DST_MASKBITS = "nw_dst_maskbits"; - public static final String COLUMN_NW_PROTO = "nw_proto"; - public static final String COLUMN_TP_SRC = "tp_src"; - public static final String COLUMN_TP_DST = "tp_dst"; - public static final String COLUMN_WILDCARD_DPID = "wildcard_dpid"; - public static final String COLUMN_WILDCARD_IN_PORT = "wildcard_in_port"; - public static final String COLUMN_WILDCARD_DL_SRC = "wildcard_dl_src"; - public static final String COLUMN_WILDCARD_DL_DST = "wildcard_dl_dst"; - public static final String COLUMN_WILDCARD_DL_TYPE = "wildcard_dl_type"; - public static final String COLUMN_WILDCARD_NW_SRC = "wildcard_nw_src"; - public static final String COLUMN_WILDCARD_NW_DST = "wildcard_nw_dst"; - public static final String COLUMN_WILDCARD_NW_PROTO = "wildcard_nw_proto"; - public static final String COLUMN_WILDCARD_TP_SRC = "wildcard_tp_src"; - public static final String COLUMN_WILDCARD_TP_DST = "wildcard_tp_dst"; - public static final String COLUMN_PRIORITY = "priority"; - public static final String COLUMN_ACTION = "action"; - public static String ColumnNames[] = { COLUMN_RULEID, COLUMN_DPID, - COLUMN_IN_PORT, COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_TYPE, - COLUMN_NW_SRC_PREFIX, COLUMN_NW_SRC_MASKBITS, COLUMN_NW_DST_PREFIX, - COLUMN_NW_DST_MASKBITS, COLUMN_NW_PROTO, COLUMN_TP_SRC, - COLUMN_TP_DST, COLUMN_WILDCARD_DPID, COLUMN_WILDCARD_IN_PORT, - COLUMN_WILDCARD_DL_SRC, COLUMN_WILDCARD_DL_DST, - COLUMN_WILDCARD_DL_TYPE, COLUMN_WILDCARD_NW_SRC, - COLUMN_WILDCARD_NW_DST, COLUMN_WILDCARD_NW_PROTO, COLUMN_PRIORITY, - COLUMN_ACTION }; - - @Override - public String getName() { - return "firewall"; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - // no prereq - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")); - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFirewallService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); - // We are the class that implements the service - m.put(IFirewallService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IStorageSourceService.class); - l.add(IRestApiService.class); - return l; - } - - /** - * Reads the rules from the storage and creates a sorted arraylist of - * FirewallRule from them. - * - * Similar to getStorageRules(), which only reads contents for REST GET and - * does no parsing, checking, nor putting into FirewallRule objects - * - * @return the sorted arraylist of FirewallRule instances (rules from - * storage) - */ - protected ArrayList<FirewallRule> readRulesFromStorage() { - ArrayList<FirewallRule> l = new ArrayList<FirewallRule>(); - - try { - Map<String, Object> row; - - // (..., null, null) for no predicate, no ordering - IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, - ColumnNames, null, null); - - // put retrieved rows into FirewallRules - for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) { - row = it.next().getRow(); - // now, parse row - FirewallRule r = new FirewallRule(); - if (!row.containsKey(COLUMN_RULEID) - || !row.containsKey(COLUMN_DPID)) { - logger.error( - "skipping entry with missing required 'ruleid' or 'switchid' entry: {}", - row); - return l; - } - try { - r.ruleid = Integer - .parseInt((String) row.get(COLUMN_RULEID)); - r.dpid = DatapathId.of((String) row.get(COLUMN_DPID)); - - for (String key : row.keySet()) { - if (row.get(key) == null) - continue; - if (key.equals(COLUMN_RULEID) - || key.equals(COLUMN_DPID) - || key.equals("id")) { - continue; // already handled - } - - else if (key.equals(COLUMN_IN_PORT)) { - r.in_port = OFPort.of(Integer.parseInt((String) row - .get(COLUMN_IN_PORT))); - } - - else if (key.equals(COLUMN_DL_SRC)) { - r.dl_src = MacAddress.of(Long.parseLong((String) row - .get(COLUMN_DL_SRC))); - } - - else if (key.equals(COLUMN_DL_DST)) { - r.dl_dst = MacAddress.of(Long.parseLong((String) row - .get(COLUMN_DL_DST))); - } - - else if (key.equals(COLUMN_DL_TYPE)) { - r.dl_type = EthType.of(Integer.parseInt((String) row - .get(COLUMN_DL_TYPE))); - } - - else if (key.equals(COLUMN_NW_SRC_PREFIX)) { - r.nw_src_prefix_and_mask = IPv4AddressWithMask.of(Integer.parseInt((String) row - .get(COLUMN_NW_SRC_PREFIX)), r.nw_src_prefix_and_mask.getMask().getInt()); - } - - else if (key.equals(COLUMN_NW_SRC_MASKBITS)) { - r.nw_src_prefix_and_mask = IPv4AddressWithMask.of(r.nw_src_prefix_and_mask.getValue().getInt(), Integer.parseInt((String) row - .get(COLUMN_NW_SRC_MASKBITS))); - } - - else if (key.equals(COLUMN_NW_DST_PREFIX)) { - r.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(Integer.parseInt((String) row - .get(COLUMN_NW_DST_PREFIX)), r.nw_dst_prefix_and_mask.getMask().getInt()); - } - - else if (key.equals(COLUMN_NW_DST_MASKBITS)) { - r.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(r.nw_dst_prefix_and_mask.getValue().getInt(), Integer.parseInt((String) row - .get(COLUMN_NW_DST_MASKBITS))); - } - - else if (key.equals(COLUMN_NW_PROTO)) { - r.nw_proto = IpProtocol.of(Short.parseShort((String) row - .get(COLUMN_NW_PROTO))); - } - - else if (key.equals(COLUMN_TP_SRC)) { - r.tp_src = TransportPort.of(Integer.parseInt((String) row - .get(COLUMN_TP_SRC))); - } - - else if (key.equals(COLUMN_TP_DST)) { - r.tp_dst = TransportPort.of(Integer.parseInt((String) row - .get(COLUMN_TP_DST))); - } - - else if (key.equals(COLUMN_WILDCARD_DPID)) { - r.wildcard_dpid = Boolean.parseBoolean((String) row - .get(COLUMN_WILDCARD_DPID)); - } - - else if (key.equals(COLUMN_WILDCARD_IN_PORT)) { - r.wildcard_in_port = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_IN_PORT)); - } - - else if (key.equals(COLUMN_WILDCARD_DL_SRC)) { - r.wildcard_dl_src = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_DL_SRC)); - } - - else if (key.equals(COLUMN_WILDCARD_DL_DST)) { - r.wildcard_dl_dst = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_DL_DST)); - } - - else if (key.equals(COLUMN_WILDCARD_DL_TYPE)) { - r.wildcard_dl_type = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_DL_TYPE)); - } - - else if (key.equals(COLUMN_WILDCARD_NW_SRC)) { - r.wildcard_nw_src = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_NW_SRC)); - } - - else if (key.equals(COLUMN_WILDCARD_NW_DST)) { - r.wildcard_nw_dst = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_NW_DST)); - } - - else if (key.equals(COLUMN_WILDCARD_NW_PROTO)) { - r.wildcard_nw_proto = Boolean - .parseBoolean((String) row - .get(COLUMN_WILDCARD_NW_PROTO)); - } - - else if (key.equals(COLUMN_PRIORITY)) { - r.priority = Integer.parseInt((String) row - .get(COLUMN_PRIORITY)); - } - - else if (key.equals(COLUMN_ACTION)) { - int tmp = Integer.parseInt((String) row.get(COLUMN_ACTION)); - if (tmp == FirewallRule.FirewallAction.DENY.ordinal()) - r.action = FirewallRule.FirewallAction.DENY; - else if (tmp == FirewallRule.FirewallAction.ALLOW.ordinal()) - r.action = FirewallRule.FirewallAction.ALLOW; - else { - r.action = null; - logger.error("action not recognized"); - } - } - } - } catch (ClassCastException e) { - logger.error( - "skipping rule {} with bad data : " - + e.getMessage(), r.ruleid); - } - if (r.action != null) - l.add(r); - } - } catch (StorageException e) { - logger.error("failed to access storage: {}", e.getMessage()); - // if the table doesn't exist, then wait to populate later via - // setStorageSource() - } - - // now, sort the list based on priorities - Collections.sort(l); - - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - floodlightProvider = context - .getServiceImpl(IFloodlightProviderService.class); - storageSource = context.getServiceImpl(IStorageSourceService.class); - restApi = context.getServiceImpl(IRestApiService.class); - rules = new ArrayList<FirewallRule>(); - logger = LoggerFactory.getLogger(Firewall.class); - - // start disabled - enabled = false; - } - - @Override - public void startUp(FloodlightModuleContext context) { - // register REST interface - restApi.addRestletRoutable(new FirewallWebRoutable()); - - // always place firewall in pipeline at bootup - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - - // storage, create table and read rules - storageSource.createTable(TABLE_NAME, null); - storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_RULEID); - this.rules = readRulesFromStorage(); - } - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { - if (!this.enabled) - return Command.CONTINUE; - - switch (msg.getType()) { - case PACKET_IN: - IRoutingDecision decision = null; - if (cntx != null) { - decision = IRoutingDecision.rtStore.get(cntx, - IRoutingDecision.CONTEXT_DECISION); - - return this.processPacketInMessage(sw, (OFPacketIn) msg, - decision, cntx); - } - break; - default: - break; - } - - return Command.CONTINUE; - } - - @Override - public void enableFirewall(boolean enabled) { - logger.info("Setting firewall to {}", enabled); - this.enabled = enabled; - } - - @Override - public List<FirewallRule> getRules() { - return this.rules; - } - - // Only used to serve REST GET - // Similar to readRulesFromStorage(), which actually checks and stores - // record into FirewallRule list - @Override - public List<Map<String, Object>> getStorageRules() { - ArrayList<Map<String, Object>> l = new ArrayList<Map<String, Object>>(); - try { - // null1=no predicate, null2=no ordering - IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, - ColumnNames, null, null); - for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) { - l.add(it.next().getRow()); - } - } catch (StorageException e) { - logger.error("failed to access storage: {}", e.getMessage()); - // if the table doesn't exist, then wait to populate later via - // setStorageSource() - } - return l; - } - - @Override - public String getSubnetMask() { - return IPv4.fromIPv4Address(this.subnet_mask); - } - - @Override - public void setSubnetMask(String newMask) { - if (newMask.trim().isEmpty()) - return; - this.subnet_mask = IPv4.toIPv4Address(newMask.trim()); - } - - @Override - public synchronized void addRule(FirewallRule rule) { - - // generate random ruleid for each newly created rule - // may want to return to caller if useful - // may want to check conflict - rule.ruleid = rule.genID(); - - int i = 0; - // locate the position of the new rule in the sorted arraylist - for (i = 0; i < this.rules.size(); i++) { - if (this.rules.get(i).priority >= rule.priority) - break; - } - // now, add rule to the list - if (i <= this.rules.size()) { - this.rules.add(i, rule); - } else { - this.rules.add(rule); - } - // add rule to database - Map<String, Object> entry = new HashMap<String, Object>(); - entry.put(COLUMN_RULEID, Integer.toString(rule.ruleid)); - entry.put(COLUMN_DPID, Long.toString(rule.dpid.getLong())); - entry.put(COLUMN_IN_PORT, Integer.toString(rule.in_port.getPortNumber())); - entry.put(COLUMN_DL_SRC, Long.toString(rule.dl_src.getLong())); - entry.put(COLUMN_DL_DST, Long.toString(rule.dl_dst.getLong())); - entry.put(COLUMN_DL_TYPE, Integer.toString(rule.dl_type.getValue())); - entry.put(COLUMN_NW_SRC_PREFIX, Integer.toString(rule.nw_src_prefix_and_mask.getValue().getInt())); - entry.put(COLUMN_NW_SRC_MASKBITS, Integer.toString(rule.nw_src_prefix_and_mask.getMask().getInt())); - entry.put(COLUMN_NW_DST_PREFIX, Integer.toString(rule.nw_dst_prefix_and_mask.getValue().getInt())); - entry.put(COLUMN_NW_DST_MASKBITS, Integer.toString(rule.nw_dst_prefix_and_mask.getMask().getInt())); - entry.put(COLUMN_NW_PROTO, Short.toString(rule.nw_proto.getIpProtocolNumber())); - entry.put(COLUMN_TP_SRC, Integer.toString(rule.tp_src.getPort())); - entry.put(COLUMN_TP_DST, Integer.toString(rule.tp_dst.getPort())); - entry.put(COLUMN_WILDCARD_DPID, - Boolean.toString(rule.wildcard_dpid)); - entry.put(COLUMN_WILDCARD_IN_PORT, - Boolean.toString(rule.wildcard_in_port)); - entry.put(COLUMN_WILDCARD_DL_SRC, - Boolean.toString(rule.wildcard_dl_src)); - entry.put(COLUMN_WILDCARD_DL_DST, - Boolean.toString(rule.wildcard_dl_dst)); - entry.put(COLUMN_WILDCARD_DL_TYPE, - Boolean.toString(rule.wildcard_dl_type)); - entry.put(COLUMN_WILDCARD_NW_SRC, - Boolean.toString(rule.wildcard_nw_src)); - entry.put(COLUMN_WILDCARD_NW_DST, - Boolean.toString(rule.wildcard_nw_dst)); - entry.put(COLUMN_WILDCARD_NW_PROTO, - Boolean.toString(rule.wildcard_nw_proto)); - entry.put(COLUMN_WILDCARD_TP_SRC, - Boolean.toString(rule.wildcard_tp_src)); - entry.put(COLUMN_WILDCARD_TP_DST, - Boolean.toString(rule.wildcard_tp_dst)); - entry.put(COLUMN_PRIORITY, Integer.toString(rule.priority)); - entry.put(COLUMN_ACTION, Integer.toString(rule.action.ordinal())); - storageSource.insertRow(TABLE_NAME, entry); - } - - @Override - public synchronized void deleteRule(int ruleid) { - Iterator<FirewallRule> iter = this.rules.iterator(); - while (iter.hasNext()) { - FirewallRule r = iter.next(); - if (r.ruleid == ruleid) { - // found the rule, now remove it - iter.remove(); - break; - } - } - // delete from database - storageSource.deleteRow(TABLE_NAME, Integer.toString(ruleid)); - } - - /** - * Iterates over the firewall rules and tries to match them with the - * incoming packet (flow). Uses the FirewallRule class's matchWithFlow - * method to perform matching. It maintains a pair of wildcards (allow and - * deny) which are assigned later to the firewall's decision, where 'allow' - * wildcards are applied if the matched rule turns out to be an ALLOW rule - * and 'deny' wildcards are applied otherwise. Wildcards are applied to - * firewall decision to optimize flows in the switch, ensuring least number - * of flows per firewall rule. So, if a particular field is not "ANY" (i.e. - * not wildcarded) in a higher priority rule, then if a lower priority rule - * matches the packet and wildcards it, it can't be wildcarded in the - * switch's flow entry, because otherwise some packets matching the higher - * priority rule might escape the firewall. The reason for keeping different - * two different wildcards is that if a field is not wildcarded in a higher - * priority allow rule, the same field shouldn't be wildcarded for packets - * matching the lower priority deny rule (non-wildcarded fields in higher - * priority rules override the wildcarding of those fields in lower priority - * rules of the opposite type). So, to ensure that wildcards are - * appropriately set for different types of rules (allow vs. deny), separate - * wildcards are maintained. Iteration is performed on the sorted list of - * rules (sorted in decreasing order of priority). - * - * @param sw - * the switch instance - * @param pi - * the incoming packet data structure - * @param cntx - * the floodlight context - * @return an instance of RuleWildcardsPair that specify rule that matches - * and the wildcards for the firewall decision - */ - protected RuleWildcardsPair matchWithRule(IOFSwitch sw, OFPacketIn pi, - FloodlightContext cntx) { - FirewallRule matched_rule = null; - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - WildcardsPair wildcards = new WildcardsPair(); - - synchronized (rules) { - Iterator<FirewallRule> iter = this.rules.iterator(); - FirewallRule rule = null; - // iterate through list to find a matching firewall rule - while (iter.hasNext()) { - // get next rule from list - rule = iter.next(); - - // check if rule matches - if (rule.matchesFlow(sw.getId(), pi.getInPort(), eth, wildcards) == true) { - matched_rule = rule; - break; - } - } - } - - // make a pair of rule and wildcards, then return it - RuleWildcardsPair ret = new RuleWildcardsPair(); - ret.rule = matched_rule; - if (matched_rule == null || matched_rule.action == FirewallRule.FirewallAction.DENY) { - ret.wildcards = wildcards.drop; - } else { - ret.wildcards = wildcards.allow; - } - return ret; - } - - /** - * Checks whether an IP address is a broadcast address or not (determines - * using subnet mask) - * - * @param IPAddress - * the IP address to check - * @return true if it is a broadcast address, false otherwise - */ - protected boolean IPIsBroadcast(int IPAddress) { - // inverted subnet mask - int inv_subnet_mask = ~this.subnet_mask; - return ((IPAddress & inv_subnet_mask) == inv_subnet_mask); - } - - public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, - IRoutingDecision decision, FloodlightContext cntx) { - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - // Allowing L2 broadcast + ARP broadcast request (also deny malformed - // broadcasts -> L2 broadcast + L3 unicast) - if (eth.isBroadcast() == true) { - boolean allowBroadcast = true; - // the case to determine if we have L2 broadcast + L3 unicast - // don't allow this broadcast packet if such is the case (malformed - // packet) - if ((eth.getPayload() instanceof IPv4) - && this.IPIsBroadcast(((IPv4) eth.getPayload()) - .getDestinationAddress()) == false) { - allowBroadcast = false; - } - if (allowBroadcast == true) { - if (logger.isTraceEnabled()) - logger.trace("Allowing broadcast traffic for PacketIn={}", - pi); - - decision = new RoutingDecision(sw.getId(), pi.getInPort() - , IDeviceService.fcStore. - get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), - IRoutingDecision.RoutingAction.MULTICAST); - decision.addToContext(cntx); - } else { - if (logger.isTraceEnabled()) - logger.trace( - "Blocking malformed broadcast traffic for PacketIn={}", - pi); - - decision = new RoutingDecision(sw.getId(), pi.getInPort() - , IDeviceService.fcStore. - get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), - IRoutingDecision.RoutingAction.DROP); - decision.addToContext(cntx); - } - return Command.CONTINUE; - } - /* - * ARP response (unicast) can be let through without filtering through - * rules by uncommenting the code below - */ - /* - * else if (eth.getEtherType() == Ethernet.TYPE_ARP) { - * logger.info("allowing ARP traffic"); decision = new - * FirewallDecision(IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); - * decision.addToContext(cntx); return Command.CONTINUE; } - */ - - // check if we have a matching rule for this packet/flow - // and no decision is taken yet - if (decision == null) { - RuleWildcardsPair match_ret = this.matchWithRule(sw, pi, cntx); - FirewallRule rule = match_ret.rule; - - if (rule == null || rule.action == FirewallRule.FirewallAction.DENY) { - decision = new RoutingDecision(sw.getId(), pi.getInPort() - , IDeviceService.fcStore. - get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), - IRoutingDecision.RoutingAction.DROP); - decision.setWildcards(match_ret.wildcards); - decision.addToContext(cntx); - if (logger.isTraceEnabled()) { - if (rule == null) - logger.trace( - "No firewall rule found for PacketIn={}, blocking flow", - pi); - else if (rule.action == FirewallRule.FirewallAction.DENY) { - logger.trace("Deny rule={} match for PacketIn={}", - rule, pi); - } - } - } else { - decision = new RoutingDecision(sw.getId(), pi.getInPort() - , IDeviceService.fcStore. - get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), - IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); - decision.setWildcards(match_ret.wildcards); - decision.addToContext(cntx); - if (logger.isTraceEnabled()) - logger.trace("Allow rule={} match for PacketIn={}", rule, - pi); - } - } - - return Command.CONTINUE; - } - - @Override - public boolean isEnabled() { - return enabled; - } - -} diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallResource.java b/src/main/java/net/floodlightcontroller/firewall/FirewallResource.java deleted file mode 100644 index 03f9baef2c2e07c9876f2aebaa6abaf758aa1539..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/FirewallResource.java +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import java.io.IOException; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.restlet.resource.Post; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FirewallResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(FirewallResource.class); - - @Get("json") - public Object handleRequest() { - IFirewallService firewall = - (IFirewallService)getContext().getAttributes(). - get(IFirewallService.class.getCanonicalName()); - - String op = (String) getRequestAttributes().get("op"); - - // REST API check status - if (op.equalsIgnoreCase("status")) { - if (firewall.isEnabled()) - return "{\"result\" : \"firewall enabled\"}"; - else - return "{\"result\" : \"firewall disabled\"}"; - } - - // REST API enable firewall - if (op.equalsIgnoreCase("enable")) { - firewall.enableFirewall(true); - return "{\"status\" : \"success\", \"details\" : \"firewall running\"}"; - } - - // REST API disable firewall - if (op.equalsIgnoreCase("disable")) { - firewall.enableFirewall(false); - return "{\"status\" : \"success\", \"details\" : \"firewall stopped\"}"; - } - - // REST API retrieving rules from storage - // currently equivalent to /wm/firewall/rules/json - if (op.equalsIgnoreCase("storageRules")) { - return firewall.getStorageRules(); - } - - // REST API set local subnet mask -- this only makes sense for one subnet - // will remove later - if (op.equalsIgnoreCase("subnet-mask")) { - return firewall.getSubnetMask(); - } - - // no known options found - return "{\"status\" : \"failure\", \"details\" : \"invalid operation\"}"; - } - - /** - * Allows setting of subnet mask - * @param fmJson The Subnet Mask in JSON format. - * @return A string status message - */ - @Post - public String handlePost(String fmJson) { - IFirewallService firewall = - (IFirewallService)getContext().getAttributes(). - get(IFirewallService.class.getCanonicalName()); - - String newMask; - try { - newMask = jsonExtractSubnetMask(fmJson); - } catch (IOException e) { - log.error("Error parsing new subnet mask: " + fmJson, e); - return "{\"status\" : \"Error! Could not parse new subnet mask, see log for details.\"}"; - } - firewall.setSubnetMask(newMask); - return ("{\"status\" : \"subnet mask set\"}"); - } - - /** - * Extracts subnet mask from a JSON string - * @param fmJson The JSON formatted string - * @return The subnet mask - * @throws IOException If there was an error parsing the JSON - */ - public static String jsonExtractSubnetMask(String fmJson) throws IOException { - String subnet_mask = ""; - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - - try { - jp = f.createJsonParser(fmJson); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - - if (n == "subnet-mask") { - subnet_mask = jp.getText(); - break; - } - } - - return subnet_mask; - } -} diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java deleted file mode 100644 index bee8fddef5942d16806c3cef144ded5a01dcfd3b..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java +++ /dev/null @@ -1,450 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import org.projectfloodlight.openflow.protocol.match.MatchField; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.EthType; -import org.projectfloodlight.openflow.types.IPv4AddressWithMask; -import org.projectfloodlight.openflow.types.IpProtocol; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.TransportPort; - -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.TCP; -import net.floodlightcontroller.packet.UDP; - -@JsonSerialize(using=FirewallRuleSerializer.class) -public class FirewallRule implements Comparable<FirewallRule> { - public int ruleid; - - public DatapathId dpid; - public OFPort in_port; - public MacAddress dl_src; - public MacAddress dl_dst; - public EthType dl_type; - public IPv4AddressWithMask nw_src_prefix_and_mask; - //public int nw_src_maskbits; - public IPv4AddressWithMask nw_dst_prefix_and_mask; - //public int nw_dst_maskbits; - public IpProtocol nw_proto; - public TransportPort tp_src; - public TransportPort tp_dst; - - public boolean wildcard_dpid; - public boolean wildcard_in_port; - public boolean wildcard_dl_src; - public boolean wildcard_dl_dst; - public boolean wildcard_dl_type; - public boolean wildcard_nw_src; - public boolean wildcard_nw_dst; - public boolean wildcard_nw_proto; - public boolean wildcard_tp_src; - public boolean wildcard_tp_dst; - - public int priority = 0; - - public FirewallAction action; - - public enum FirewallAction { - /* - * DENY: Deny rule - * ALLOW: Allow rule - */ - DENY, ALLOW - } - - public FirewallRule() { - this.in_port = OFPort.ZERO; - this.dl_src = MacAddress.NONE; - this.nw_src_prefix_and_mask = IPv4AddressWithMask.NONE; - //this.nw_src_maskbits = 0; - this.dl_dst = MacAddress.NONE; - this.nw_proto = IpProtocol.NONE; - this.tp_src = TransportPort.NONE; - this.tp_dst = TransportPort.NONE; - this.dl_dst = MacAddress.NONE; - this.nw_dst_prefix_and_mask = IPv4AddressWithMask.NONE; - //this.nw_dst_maskbits = 0; - this.dpid = DatapathId.NONE; - this.wildcard_dpid = true; - this.wildcard_in_port = true; - this.wildcard_dl_src = true; - this.wildcard_dl_dst = true; - this.wildcard_dl_type = true; - this.wildcard_nw_src = true; - this.wildcard_nw_dst = true; - this.wildcard_nw_proto = true; - this.wildcard_tp_src = true; - this.wildcard_tp_dst = true; - this.priority = 0; - this.action = FirewallAction.ALLOW; - this.ruleid = 0; - } - - /** - * Generates a unique ID for the instance - * - * @return int representing the unique id - */ - public int genID() { - int uid = this.hashCode(); - if (uid < 0) { - uid = Math.abs(uid); - uid = uid * 15551; - } - return uid; - } - - /** - * Comparison method for Collections.sort method - * - * @param rule - * the rule to compare with - * @return number representing the result of comparison 0 if equal negative - * if less than 'rule' greater than zero if greater priority rule - * than 'rule' - */ - @Override - public int compareTo(FirewallRule rule) { - return this.priority - rule.priority; - } - - /** - * Determines if this instance matches an existing rule instance - * - * @param r - * : the FirewallRule instance to compare with - * @return boolean: true if a match is found - **/ - public boolean isSameAs(FirewallRule r) { - if (this.action != r.action - || this.wildcard_dl_type != r.wildcard_dl_type - || (this.wildcard_dl_type == false && !this.dl_type.equals(r.dl_type)) - || this.wildcard_tp_src != r.wildcard_tp_src - || (this.wildcard_tp_src == false && !this.tp_src.equals(r.tp_src)) - || this.wildcard_tp_dst != r.wildcard_tp_dst - || (this.wildcard_tp_dst == false && !this.tp_dst.equals(r.tp_dst)) - || this.wildcard_dpid != r.wildcard_dpid - || (this.wildcard_dpid == false && !this.dpid.equals(r.dpid)) - || this.wildcard_in_port != r.wildcard_in_port - || (this.wildcard_in_port == false && !this.in_port.equals(r.in_port)) - || this.wildcard_nw_src != r.wildcard_nw_src - || (this.wildcard_nw_src == false && !this.nw_src_prefix_and_mask.equals(r.nw_src_prefix_and_mask)) - || this.wildcard_dl_src != r.wildcard_dl_src - || (this.wildcard_dl_src == false && !this.dl_src.equals(r.dl_src)) - || this.wildcard_nw_proto != r.wildcard_nw_proto - || (this.wildcard_nw_proto == false && !this.nw_proto.equals(r.nw_proto)) - || this.wildcard_nw_dst != r.wildcard_nw_dst - || (this.wildcard_nw_dst == false && !this.nw_dst_prefix_and_mask.equals(r.nw_dst_prefix_and_mask)) - || this.wildcard_dl_dst != r.wildcard_dl_dst - || (this.wildcard_dl_dst == false && this.dl_dst != r.dl_dst)) { - return false; - } - return true; - } - - /** - * Matches this rule to a given flow - incoming packet - * - * @param switchDpid - * the Id of the connected switch - * @param inPort - * the switch port where the packet originated from - * @param packet - * the Ethernet packet that arrives at the switch - * @param wildcards - * the pair of wildcards (allow and deny) given by Firewall - * module that is used by the Firewall module's matchWithRule - * method to derive wildcards for the decision to be taken - * @return true if the rule matches the given packet-in, false otherwise - */ - public boolean matchesFlow(DatapathId switchDpid, OFPort inPort, Ethernet packet, - WildcardsPair wildcards) { - IPacket pkt = packet.getPayload(); - - // dl_type type - IPv4 pkt_ip = null; - - // nw_proto types - TCP pkt_tcp = null; - UDP pkt_udp = null; - - // tp_src and tp_dst (tp port numbers) - short pkt_tp_src = 0; - short pkt_tp_dst = 0; - - // switchID matches? - if (wildcard_dpid == false && !dpid.equals(switchDpid)) - return false; - - // in_port matches? - if (wildcard_in_port == false && !in_port.equals(inPort)) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_IN_PORT; - wildcards.drop.setExact(MatchField.IN_PORT, this.in_port); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_IN_PORT; - wildcards.allow.setExact(MatchField.IN_PORT, this.in_port); - } - - // mac address (src and dst) match? - if (wildcard_dl_src == false && !dl_src.equals(packet.getSourceMAC())) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_DL_SRC; - wildcards.drop.setExact(MatchField.ETH_SRC, this.dl_src); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_DL_SRC; - wildcards.allow.setExact(MatchField.ETH_SRC, this.dl_src); - } - - if (wildcard_dl_dst == false && !dl_dst.equals(packet.getDestinationMAC())) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_DL_DST; - wildcards.drop.setExact(MatchField.ETH_DST, this.dl_dst); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_DL_DST; - wildcards.allow.setExact(MatchField.ETH_DST, this.dl_dst); - } - - // dl_type check: ARP, IP - - // if this is not an ARP rule but the pkt is ARP, - // return false match - no need to continue protocol specific check - if (wildcard_dl_type == false) { - if (dl_type.equals(EthType.ARP)) { - if (packet.getEtherType() != EthType.ARP.getValue()) - return false; - else { - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE; - wildcards.drop.setExact(MatchField.ETH_TYPE, this.dl_type); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE; - wildcards.allow.setExact(MatchField.ETH_TYPE, this.dl_type); - } - } - } else if (dl_type.equals(EthType.IPv4)) { - if (packet.getEtherType() != EthType.IPv4.getValue()) - return false; - else { - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO; - wildcards.drop.setExact(MatchField.IP_PROTO, this.nw_proto); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO; - wildcards.allow.setExact(MatchField.IP_PROTO, this.nw_proto); - } - // IP packets, proceed with ip address check - pkt_ip = (IPv4) pkt; - - // IP addresses (src and dst) match? - if (wildcard_nw_src == false && this.matchIPAddress(nw_src_prefix_and_mask.getValue().getInt(), nw_src_prefix_and_mask.getMask().getInt(), pkt_ip.getSourceAddress()) == false) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL; - //wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT); - wildcards.drop.setMasked(MatchField.IPV4_SRC, nw_src_prefix_and_mask); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL; - //wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT); - wildcards.allow.setMasked(MatchField.IPV4_SRC, nw_src_prefix_and_mask); - } - - if (wildcard_nw_dst == false && this.matchIPAddress(nw_dst_prefix_and_mask.getValue().getInt(), nw_dst_prefix_and_mask.getMask().getInt(), pkt_ip.getDestinationAddress()) == false) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL; - //wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT); - wildcards.drop.setMasked(MatchField.IPV4_DST, nw_dst_prefix_and_mask); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL; - //wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT); - wildcards.allow.setMasked(MatchField.IPV4_DST, nw_dst_prefix_and_mask); - } - - // nw_proto check - if (wildcard_nw_proto == false) { - if (nw_proto.equals(IpProtocol.TCP)) { - if ((short) pkt_ip.getProtocol() != IpProtocol.TCP.getIpProtocolNumber()) - return false; - else { - pkt_tcp = (TCP) pkt_ip.getPayload(); - pkt_tp_src = pkt_tcp.getSourcePort(); - pkt_tp_dst = pkt_tcp.getDestinationPort(); - } - } else if (nw_proto.equals(IpProtocol.UDP)) { - if ((short) pkt_ip.getProtocol() != IpProtocol.UDP.getIpProtocolNumber()) - return false; - else { - pkt_udp = (UDP) pkt_ip.getPayload(); - pkt_tp_src = pkt_udp.getSourcePort(); - pkt_tp_dst = pkt_udp.getDestinationPort(); - } - } else if (nw_proto.equals(IpProtocol.ICMP)) { - if ((short) pkt_ip.getProtocol() != IpProtocol.ICMP.getIpProtocolNumber()) - return false; - else { - // nothing more needed for ICMP - } - } - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO; - wildcards.drop.setExact(MatchField.IP_PROTO, this.nw_proto); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO; - wildcards.allow.setExact(MatchField.IP_PROTO, this.nw_proto); - } - - // TCP/UDP source and destination ports match? - if (pkt_tcp != null || pkt_udp != null) { - // does the source port match? - if (tp_src.getPort() != 0 && tp_src.getPort() != pkt_tp_src) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_TP_SRC; - if (pkt_tcp != null) { - wildcards.drop.setExact(MatchField.TCP_SRC, this.tp_src); - } else { - wildcards.drop.setExact(MatchField.UDP_SRC, this.tp_src); - } - } else { - //wildcards.allow &= ~OFMatch.OFPFW_TP_SRC; - if (pkt_tcp != null) { - wildcards.allow.setExact(MatchField.TCP_SRC, this.tp_src); - } else { - wildcards.allow.setExact(MatchField.UDP_SRC, this.tp_src); - } - } - - // does the destination port match? - if (tp_dst.getPort() != 0 && tp_dst.getPort() != pkt_tp_dst) - return false; - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_TP_DST; - if (pkt_tcp != null) { - wildcards.drop.setExact(MatchField.TCP_DST, this.tp_dst); - } else { - wildcards.drop.setExact(MatchField.UDP_DST, this.tp_dst); - } - } else { - //wildcards.allow &= ~OFMatch.OFPFW_TP_DST; - if (pkt_tcp != null) { - wildcards.allow.setExact(MatchField.TCP_DST, this.tp_dst); - } else { - wildcards.allow.setExact(MatchField.UDP_DST, this.tp_dst); - } - } - } - } - - } - } else { - // non-IP packet - not supported - report no match - return false; - } - } - if (action == FirewallRule.FirewallAction.DENY) { - //wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE; - wildcards.drop.setExact(MatchField.ETH_TYPE, this.dl_type); - } else { - //wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE; - wildcards.allow.setExact(MatchField.ETH_TYPE, this.dl_type); - } - - // all applicable checks passed - return true; - } - - /** - * Determines if rule's CIDR address matches IP address of the packet - * - * @param rulePrefix - * prefix part of the CIDR address - * @param ruleBits - * the size of mask of the CIDR address - * @param packetAddress - * the IP address of the incoming packet to match with - * @return true if CIDR address matches the packet's IP address, false - * otherwise - */ - protected boolean matchIPAddress(int rulePrefix, int ruleBits, - int packetAddress) { - boolean matched = true; - - int rule_iprng = 32 - ruleBits; - int rule_ipint = rulePrefix; - int pkt_ipint = packetAddress; - // if there's a subnet range (bits to be wildcarded > 0) - if (rule_iprng > 0) { - // right shift bits to remove rule_iprng of LSB that are to be - // wildcarded - rule_ipint = rule_ipint >> rule_iprng; - pkt_ipint = pkt_ipint >> rule_iprng; - // now left shift to return to normal range, except that the - // rule_iprng number of LSB - // are now zeroed - rule_ipint = rule_ipint << rule_iprng; - pkt_ipint = pkt_ipint << rule_iprng; - } - // check if we have a match - if (rule_ipint != pkt_ipint) - matched = false; - - return matched; - } - - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + (int) dpid.getLong(); - result = prime * result + in_port.getPortNumber(); - result = prime * result + (int) dl_src.getLong(); - result = prime * result + (int) dl_dst.getLong(); - result = prime * result + dl_type.getValue(); - result = prime * result + nw_src_prefix_and_mask.getValue().getInt(); - result = prime * result + nw_src_prefix_and_mask.getMask().getInt(); - result = prime * result + nw_dst_prefix_and_mask.getValue().getInt(); - result = prime * result + nw_dst_prefix_and_mask.getMask().getInt(); - result = prime * result + nw_proto.getIpProtocolNumber(); - result = prime * result + tp_src.getPort(); - result = prime * result + tp_dst.getPort(); - result = prime * result + action.ordinal(); - result = prime * result + priority; - result = prime * result + (new Boolean(wildcard_dpid)).hashCode(); - result = prime * result + (new Boolean(wildcard_in_port)).hashCode(); - result = prime * result + (new Boolean(wildcard_dl_src)).hashCode(); - result = prime * result + (new Boolean(wildcard_dl_dst)).hashCode(); - result = prime * result + (new Boolean(wildcard_dl_type)).hashCode(); - result = prime * result + (new Boolean(wildcard_nw_src)).hashCode(); - result = prime * result + (new Boolean(wildcard_nw_dst)).hashCode(); - result = prime * result + (new Boolean(wildcard_nw_proto)).hashCode(); - result = prime * result + (new Boolean(wildcard_tp_src)).hashCode(); - result = prime * result + (new Boolean(wildcard_tp_dst)).hashCode(); - return result; - } -} diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java deleted file mode 100644 index 42cb2727f79e3403d0b1ddd0d777468a07092627..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import java.io.IOException; - -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 a FirewallRule object - * Implemented to output easily readable MAC, IP addresses - * @author Jason Parraga - */ -public class FirewallRuleSerializer extends JsonSerializer<FirewallRule> { - - @Override - public void serialize(FirewallRule rule, JsonGenerator jGen, - SerializerProvider serializer) throws IOException, - JsonProcessingException { - jGen.writeStartObject(); - - jGen.writeNumberField("ruleid", rule.ruleid); - jGen.writeStringField("dpid", rule.dpid.toString()); - jGen.writeNumberField("in_port", rule.in_port.getPortNumber()); - jGen.writeStringField("dl_src", rule.dl_src.toString()); - jGen.writeStringField("dl_dst", rule.dl_dst.toString()); - jGen.writeNumberField("dl_type", rule.dl_type.getValue()); - jGen.writeStringField("nw_src_prefix", rule.nw_src_prefix_and_mask.getValue().toString()); - jGen.writeNumberField("nw_src_maskbits", rule.nw_src_prefix_and_mask.getMask().asCidrMaskLength()); - jGen.writeStringField("nw_dst_prefix", rule.nw_dst_prefix_and_mask.getValue().toString()); - jGen.writeNumberField("nw_dst_maskbits", rule.nw_dst_prefix_and_mask.getMask().asCidrMaskLength()); - jGen.writeNumberField("nw_proto", rule.nw_proto.getIpProtocolNumber()); - jGen.writeNumberField("tp_src", rule.tp_src.getPort()); - jGen.writeNumberField("tp_dst", rule.tp_dst.getPort()); - jGen.writeBooleanField("wildcard_dpid", rule.wildcard_dpid); - jGen.writeBooleanField("wildcard_in_port", rule.wildcard_in_port); - jGen.writeBooleanField("wildcard_dl_src", rule.wildcard_dl_src); - jGen.writeBooleanField("wildcard_dl_dst", rule.wildcard_dl_dst); - jGen.writeBooleanField("wildcard_dl_type", rule.wildcard_dl_type); - jGen.writeBooleanField("wildcard_nw_src", rule.wildcard_nw_src); - jGen.writeBooleanField("wildcard_nw_dst", rule.wildcard_nw_dst); - jGen.writeBooleanField("wildcard_nw_proto", rule.wildcard_nw_proto); - jGen.writeBooleanField("wildcard_tp_src", rule.wildcard_tp_src); - jGen.writeBooleanField("wildcard_tp_dst", rule.wildcard_tp_dst); - jGen.writeNumberField("priority", rule.priority); - jGen.writeStringField("action", String.valueOf(rule.action)); - - jGen.writeEndObject(); - } - -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java deleted file mode 100644 index 27e40d3ffecebecc8b268125ee0441cf7ea8348c..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java +++ /dev/null @@ -1,314 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import java.io.IOException; -import java.util.Iterator; -import java.util.List; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.EthType; -import org.projectfloodlight.openflow.types.IPv4AddressWithMask; -import org.projectfloodlight.openflow.types.IpProtocol; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.TransportPort; -import org.restlet.resource.Delete; -import org.restlet.resource.Post; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.packet.IPv4; - -public class FirewallRulesResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(FirewallRulesResource.class); - - @Get("json") - public List<FirewallRule> retrieve() { - IFirewallService firewall = - (IFirewallService)getContext().getAttributes(). - get(IFirewallService.class.getCanonicalName()); - - return firewall.getRules(); - } - - /** - * Takes a Firewall Rule string in JSON format and parses it into - * our firewall rule data structure, then adds it to the firewall. - * @param fmJson The Firewall rule entry in JSON format. - * @return A string status message - */ - @Post - public String store(String fmJson) { - IFirewallService firewall = - (IFirewallService)getContext().getAttributes(). - get(IFirewallService.class.getCanonicalName()); - - FirewallRule rule; - try { - rule = jsonToFirewallRule(fmJson); - } catch (IOException e) { - log.error("Error parsing firewall rule: " + fmJson, e); - return "{\"status\" : \"Error! Could not parse firewall rule, see log for details.\"}"; - } - String status = null; - if (checkRuleExists(rule, firewall.getRules())) { - status = "Error! A similar firewall rule already exists."; - log.error(status); - return ("{\"status\" : \"" + status + "\"}"); - } else { - // add rule to firewall - firewall.addRule(rule); - status = "Rule added"; - return ("{\"status\" : \"" + status + "\", \"rule-id\" : \""+ Integer.toString(rule.ruleid) + "\"}"); - } - } - - /** - * Takes a Firewall Rule string in JSON format and parses it into - * our firewall rule data structure, then deletes it from the firewall. - * @param fmJson The Firewall rule entry in JSON format. - * @return A string status message - */ - - @Delete - public String remove(String fmJson) { - IFirewallService firewall = - (IFirewallService)getContext().getAttributes(). - get(IFirewallService.class.getCanonicalName()); - - FirewallRule rule; - try { - rule = jsonToFirewallRule(fmJson); - } catch (IOException e) { - log.error("Error parsing firewall rule: " + fmJson, e); - return "{\"status\" : \"Error! Could not parse firewall rule, see log for details.\"}"; - } - String status = null; - boolean exists = false; - Iterator<FirewallRule> iter = firewall.getRules().iterator(); - while (iter.hasNext()) { - FirewallRule r = iter.next(); - if (r.ruleid == rule.ruleid) { - exists = true; - break; - } - } - if (!exists) { - status = "Error! Can't delete, a rule with this ID doesn't exist."; - log.error(status); - } else { - // delete rule from firewall - firewall.deleteRule(rule.ruleid); - status = "Rule deleted"; - } - return ("{\"status\" : \"" + status + "\"}"); - } - - /** - * Turns a JSON formatted Firewall Rule string into a FirewallRule instance - * @param fmJson The JSON formatted static firewall rule - * @return The FirewallRule instance - * @throws IOException If there was an error parsing the JSON - */ - - public static FirewallRule jsonToFirewallRule(String fmJson) throws IOException { - FirewallRule rule = new FirewallRule(); - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - - try { - jp = f.createJsonParser(fmJson); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - - String tmp; - - // This is currently only applicable for remove(). In store(), ruleid takes a random number - if (n == "ruleid") { - rule.ruleid = Integer.parseInt(jp.getText()); - } - - // This assumes user having dpid info for involved switches - else if (n == "switchid") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("-1") == false) { - // user inputs hex format dpid - rule.dpid = DatapathId.of(tmp); - rule.wildcard_dpid = false; - } - } - - else if (n == "src-inport") { - rule.in_port = OFPort.of(Integer.parseInt(jp.getText())); - rule.wildcard_in_port = false; - } - - else if (n == "src-mac") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("ANY") == false) { - rule.wildcard_dl_src = false; - rule.dl_src = MacAddress.of(tmp); - } - } - - else if (n == "dst-mac") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("ANY") == false) { - rule.wildcard_dl_dst = false; - rule.dl_dst = MacAddress.of(tmp); - } - } - - else if (n == "dl-type") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("ARP")) { - rule.wildcard_dl_type = false; - rule.dl_type = EthType.ARP; - } - if (tmp.equalsIgnoreCase("IPv4")) { - rule.wildcard_dl_type = false; - rule.dl_type = EthType.IPv4; - } - } - - else if (n == "src-ip") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("ANY") == false) { - rule.wildcard_nw_src = false; - rule.wildcard_dl_type = false; - rule.dl_type = EthType.IPv4; - rule.nw_src_prefix_and_mask = IPv4AddressWithMask.of(tmp); - } - } - - else if (n == "dst-ip") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("ANY") == false) { - rule.wildcard_nw_dst = false; - rule.wildcard_dl_type = false; - rule.dl_type = EthType.IPv4; - rule.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(tmp); - } - } - - else if (n == "nw-proto") { - tmp = jp.getText(); - if (tmp.equalsIgnoreCase("TCP")) { - rule.wildcard_nw_proto = false; - rule.nw_proto = IpProtocol.TCP; - rule.wildcard_dl_type = false; - rule.dl_type = EthType.IPv4; - } else if (tmp.equalsIgnoreCase("UDP")) { - rule.wildcard_nw_proto = false; - rule.nw_proto = IpProtocol.UDP; - rule.wildcard_dl_type = false; - rule.dl_type = EthType.IPv4; - } else if (tmp.equalsIgnoreCase("ICMP")) { - rule.wildcard_nw_proto = false; - rule.nw_proto = IpProtocol.ICMP; - rule.wildcard_dl_type = false; - rule.dl_type = EthType.IPv4; - } - } - - else if (n == "tp-src") { - rule.wildcard_tp_src = false; - rule.tp_src = TransportPort.of(Integer.parseInt(jp.getText())); - } - - else if (n == "tp-dst") { - rule.wildcard_tp_dst = false; - rule.tp_dst = TransportPort.of(Integer.parseInt(jp.getText())); - } - - else if (n == "priority") { - rule.priority = Integer.parseInt(jp.getText()); - } - - else if (n == "action") { - if (jp.getText().equalsIgnoreCase("allow") == true) { - rule.action = FirewallRule.FirewallAction.ALLOW; - } else if (jp.getText().equalsIgnoreCase("deny") == true) { - rule.action = FirewallRule.FirewallAction.DENY; - } - } - } - - return rule; - } - - public static int[] IPCIDRToPrefixBits(String cidr) { - int ret[] = new int[2]; - - // as IP can also be a prefix rather than an absolute address - // split it over "/" to get the bit range - String[] parts = cidr.split("/"); - String cidr_prefix = parts[0].trim(); - int cidr_bits = 0; - if (parts.length == 2) { - try { - cidr_bits = Integer.parseInt(parts[1].trim()); - } catch (Exception exp) { - cidr_bits = 32; - } - } - ret[0] = IPv4.toIPv4Address(cidr_prefix); - ret[1] = cidr_bits; - - return ret; - } - - public static boolean checkRuleExists(FirewallRule rule, List<FirewallRule> rules) { - Iterator<FirewallRule> iter = rules.iterator(); - while (iter.hasNext()) { - FirewallRule r = iter.next(); - - // check if we find a similar rule - if (rule.isSameAs(r)) { - return true; - } - } - - // no rule matched, so it doesn't exist in the rules - return false; - } -} diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallWebRoutable.java b/src/main/java/net/floodlightcontroller/firewall/FirewallWebRoutable.java deleted file mode 100644 index c2d1c8fdb053e019eedecadc476c7cec7101fc79..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/FirewallWebRoutable.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import net.floodlightcontroller.restserver.RestletRoutable; -import org.restlet.Context; -import org.restlet.routing.Router; - -public class FirewallWebRoutable implements RestletRoutable { - /** - * Create the Restlet router and bind to the proper resources. - */ - @Override - public Router getRestlet(Context context) { - Router router = new Router(context); - router.attach("/module/{op}/json", FirewallResource.class); - router.attach("/rules/json", FirewallRulesResource.class); - return router; - } - - /** - * Set the base path for the Firewall - */ - @Override - public String basePath() { - return "/wm/firewall"; - } -} diff --git a/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java b/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java deleted file mode 100644 index 56cc70eb9f59abdd93afc50c6d53217531a5d975..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.core.module.IFloodlightService; - -public interface IFirewallService extends IFloodlightService { - - /** - * Enables/disables the firewall. - * @param enable Whether to enable or disable the firewall. - */ - public void enableFirewall(boolean enable); - - /** - * Returns operational status of the firewall - * @return boolean enabled; - */ - public boolean isEnabled(); - - /** - * Returns all of the firewall rules - * @return List of all rules - */ - public List<FirewallRule> getRules(); - - /** - * Returns the subnet mask - * @return subnet mask - */ - public String getSubnetMask(); - - /** - * Sets the subnet mask - * @param newMask The new subnet mask - */ - public void setSubnetMask(String newMask); - - /** - * Returns all of the firewall rules in storage - * for debugging and unit-testing purposes - * @return List of all rules in storage - */ - public List<Map<String, Object>> getStorageRules(); - - /** - * Adds a new Firewall rule - */ - public void addRule(FirewallRule rule); - - /** - * Deletes a Firewall rule - */ - public void deleteRule(int ruleid); -} diff --git a/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java b/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java deleted file mode 100644 index 114dc3eee332c005030152b69141873e1a7371b8..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import org.projectfloodlight.openflow.protocol.match.Match; - -public class RuleWildcardsPair { - public FirewallRule rule; - public Match.Builder wildcards; -} diff --git a/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java b/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java deleted file mode 100644 index f6443c403e1de021319e84869b8f07f911e48f21..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import org.projectfloodlight.openflow.protocol.match.Match; - - -public class WildcardsPair { - //public int allow = OFMatch.OFPFW_ALL; - //public int drop = OFMatch.OFPFW_ALL; - public Match.Builder allow; - public Match.Builder drop; -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java deleted file mode 100644 index a9370956cc6d558578f598499916216c5dcc2caf..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsAcl.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -/** - * The Class for FlowReconcileQuery for BVS config ACL application change . - */ -public class FRQueryBvsAcl extends FlowReconcileQuery { - /* The BVS name. */ - public String bvsName; - /*BVS interface name*/ - public String bvsInterfaceName; - /*ACL applied direction*/ - public DIRECTION direction; - public enum DIRECTION { - INGRESS, - EGRESS, - }; - public FRQueryBvsAcl() { - super(ReconcileQueryEvType.ACL_CONFIG_CHANGED); - } - - public FRQueryBvsAcl(String bvsName, String bvsInterfaceName, DIRECTION direction) { - this(); - this.bvsName = bvsName; - this.bvsInterfaceName = bvsInterfaceName; - this.direction = direction; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + bvsName.hashCode(); - result = prime * result + bvsInterfaceName.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsAcl)) { - return false; - } - FRQueryBvsAcl other = (FRQueryBvsAcl) obj; - if (! bvsName.equals(other.bvsName)) return false; - if (! bvsInterfaceName.equals(other.bvsInterfaceName)) return false; - if (! direction.equals(other.direction)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("BVS Name: "); - builder.append(bvsName); - builder.append(", BVS Interface Name: "); - builder.append(bvsInterfaceName); - builder.append(", ACL Direction: "); - builder.append(direction); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java deleted file mode 100644 index 12fac87914b6292112fedd8e8d88e5c40d394f22..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import net.floodlightcontroller.util.MACAddress; - -/** - * The Class for FlowReconcileQuery for link down event. - */ -public class FRQueryBvsMatchMac extends FlowReconcileQuery { - /*the match mac*/ - public String mac; - - public FRQueryBvsMatchMac() { - super(ReconcileQueryEvType.BVS_INTERFACE_RULE_CHANGED_MATCH_MAC); - } - - public FRQueryBvsMatchMac(String mac) { - this(); - this.mac = mac; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + mac.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsMatchMac)) { - return false; - } - FRQueryBvsMatchMac other = (FRQueryBvsMatchMac) obj; - if (! mac.equals(other.mac)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("MAC: "); - builder.append(MACAddress.valueOf(mac).toString()); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java deleted file mode 100644 index cdb9168f104a32c0eca146ab01891821c5872d4e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSubnet.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -/** - * The Class for FlowReconcileQuery for BVS config interface match IP subnet . - */ -public class FRQueryBvsMatchSubnet extends FlowReconcileQuery { - /*match ip subnet*/ - public String ipSubnet; - - public FRQueryBvsMatchSubnet() { - super(ReconcileQueryEvType.BVS_INTERFACE_RULE_CHANGED_MATCH_IPSUBNET); - } - - public FRQueryBvsMatchSubnet(String ipSubnet) { - this(); - this.ipSubnet = ipSubnet; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + ipSubnet.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsMatchSubnet)) { - return false; - } - FRQueryBvsMatchSubnet other = (FRQueryBvsMatchSubnet) obj; - if (! ipSubnet.equals(other.ipSubnet)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("IP Subnet: "); - builder.append(ipSubnet); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java deleted file mode 100644 index 27ecc8dfbda9628a9cec5a121e8edb959385cffb..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.List; - -import org.openflow.util.HexString; -/** - * The Class for FlowReconcileQuery for BVS config interface match switch port. - */ -public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery { - /*switch DPID*/ - public long swId; - /*List of ports:*/ - public List<String> matchPortList; - - public FRQueryBvsMatchSwitchPort() { - super(ReconcileQueryEvType.BVS_INTERFACE_RULE_CHANGED_MATCH_SWITCH_PORT); - } - - public FRQueryBvsMatchSwitchPort(Long swId, List<String> portList) { - this(); - this.swId = swId; - this.matchPortList = portList; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + (int)swId; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsMatchSwitchPort)) { - return false; - } - FRQueryBvsMatchSwitchPort other = (FRQueryBvsMatchSwitchPort) obj; - if (swId != other.swId) return false; - if (! matchPortList.equals(other.matchPortList)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Switch: "); - builder.append(HexString.toHexString(swId)); - builder.append(", Match Port List:"); - builder.append(matchPortList); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java deleted file mode 100644 index ba7b90da4d0e5a25524107a08a948878e9e514d6..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchTag.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.List; - -/** - * The Class for FlowReconcileQuery for BVS config interface match tag. - */ -public class FRQueryBvsMatchTag extends FlowReconcileQuery { - public List<String> tag; - - public FRQueryBvsMatchTag() { - super(ReconcileQueryEvType.BVS_INTERFACE_RULE_CHANGED_MATCH_TAG); - } - - public FRQueryBvsMatchTag(List<String> tag) { - this(); - this.tag = tag; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + tag.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsMatchTag)) { - return false; - } - FRQueryBvsMatchTag other = (FRQueryBvsMatchTag) obj; - if (! tag.equals(other.tag)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Tags: "); - builder.append(tag); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java deleted file mode 100644 index 732e64abb26d7f7b42057700c39d8015c2f3a674..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchVlan.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.List; - -/** - * The Class for FlowReconcileQuery for BVS config interface match VLAN. - */ -public class FRQueryBvsMatchVlan extends FlowReconcileQuery { - /* The match vlan IDs. */ - public List<Integer> vlans; - - public FRQueryBvsMatchVlan() { - super(ReconcileQueryEvType.BVS_INTERFACE_RULE_CHANGED_MATCH_VLAN); - } - - public FRQueryBvsMatchVlan(List<Integer> vlans) { - this(); - this.vlans = vlans; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + vlans.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsMatchVlan)) { - return false; - } - FRQueryBvsMatchVlan other = (FRQueryBvsMatchVlan) obj; - if (! vlans.equals(other.vlans)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Vlans: "); - builder.append(vlans); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java deleted file mode 100644 index 836dbcf2ef8476120c8279135fb1d2af933b7b58..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsPriority.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -/** - * The Class for FlowReconcileQuery for BVS config priority change . - */ -public class FRQueryBvsPriority extends FlowReconcileQuery { - /*BVS priority change*/ - public int lowP; //lower priority - public int highP; //higher priority - - public FRQueryBvsPriority() { - super(ReconcileQueryEvType.BVS_PRIORITY_CHANGED); - } - - public FRQueryBvsPriority(int lowP, int highP) { - this(); - this.lowP = lowP; - this.highP = highP; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + lowP; - result = prime * result + highP; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryBvsPriority)) { - return false; - } - FRQueryBvsPriority other = (FRQueryBvsPriority) obj; - if (lowP != other.lowP) return false; - if (highP != other.highP) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Lower Priority: "); - builder.append(lowP); - builder.append("Higher Priority: "); - builder.append(highP); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java deleted file mode 100644 index 48a2eb304040f0e4b45a7b5213b91a4cf0c21e48..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.util.MACAddress; - -/** - * The Class for FlowReconcileQuery for device property changed event. - */ -public class FRQueryDevicePropertyChanged extends FlowReconcileQuery { - public IDevice device; - public FRQueryDevicePropertyChanged() { - super(ReconcileQueryEvType.DEVICE_PROPERTY_CHANGED); - } - - public FRQueryDevicePropertyChanged(IDevice device) { - this(); - this.device = device; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + device.getDeviceKey().hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryDevicePropertyChanged)) { - return false; - } - FRQueryDevicePropertyChanged other = (FRQueryDevicePropertyChanged) obj; - if (! device.equals(other.device)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Device: "); - builder.append(MACAddress.valueOf(device.getMACAddress())); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java deleted file mode 100644 index 8a48fa5a6b9b1fef7777d4abf216fafa2c5d3658..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSArpChange.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; -/** - * The Class for FlowReconcileQuery for VRS routing rule change event . - */ -public class FRQueryVRSArpChange extends FlowReconcileQuery { - /* The list of impacted bvs names. */ - public String tenant; - public FRQueryVRSArpChange() { - super(ReconcileQueryEvType.VRS_STATIC_ARP_CHANGED); - } - - public FRQueryVRSArpChange(String tenant) { - this(); - this.tenant = tenant; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + tenant.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryVRSArpChange)) { - return false; - } - FRQueryVRSArpChange other = (FRQueryVRSArpChange) obj; - if (! tenant.equals(other.tenant)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Tenant: "); - builder.append(tenant); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java deleted file mode 100644 index 59f4c29486501ddcbfd84e8b7b488bc5f994653e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryVRSRuleChange.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.Set; - -/** - * The Class for FlowReconcileQuery for VRS routing rule change event . - */ -public class FRQueryVRSRuleChange extends FlowReconcileQuery { - /* The list of impacted bvs names. */ - public Set<String> bvsNames; - public FRQueryVRSRuleChange() { - super(ReconcileQueryEvType.VRS_ROUTING_RULE_CHANGED); - } - - public FRQueryVRSRuleChange(Set<String> bvsNames) { - this(); - this.bvsNames = bvsNames; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + bvsNames.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FRQueryVRSRuleChange)) { - return false; - } - FRQueryVRSRuleChange other = (FRQueryVRSRuleChange) obj; - if (! bvsNames.equals(other.bvsNames)) return false; - return true; - } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("BVS Names: "); - builder.append(bvsNames); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java deleted file mode 100644 index 4ae2caed69063207f88d4fbd8422ddce5a4fd2f5..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java +++ /dev/null @@ -1,472 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.ListenerDispatcher; -import net.floodlightcontroller.core.util.SingletonTask; -import net.floodlightcontroller.counter.CounterStore; -import net.floodlightcontroller.counter.ICounter; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.counter.SimpleCounter; -import net.floodlightcontroller.debugcounter.IDebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugcounter.NullDebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType; -import net.floodlightcontroller.flowcache.FlowReconcileQuery.FlowReconcileQueryDebugEvent; -import net.floodlightcontroller.flowcache.IFlowReconcileListener; -import net.floodlightcontroller.flowcache.OFMatchReconcile; -import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority; -import net.floodlightcontroller.threadpool.IThreadPoolService; - -import org.openflow.protocol.OFType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FlowReconcileManager - implements IFloodlightModule, IFlowReconcileService { - - /** The logger. */ - private static Logger logger = - LoggerFactory.getLogger(FlowReconcileManager.class); - - /** Reference to dependent modules */ - protected IThreadPoolService threadPool; - protected ICounterStoreService counterStore; - protected IDebugCounterService debugCounters; - /** - * The list of flow reconcile listeners that have registered to get - * flow reconcile callbacks. Such callbacks are invoked, for example, when - * a switch with existing flow-mods joins this controller and those flows - * need to be reconciled with the current configuration of the controller. - */ - protected ListenerDispatcher<OFType, IFlowReconcileListener> - flowReconcileListeners; - - /** A FIFO queue to keep all outstanding flows for reconciliation */ - PriorityPendingQueue <OFMatchReconcile> flowQueue; - - /** Asynchronous task to feed the flowReconcile pipeline */ - protected SingletonTask flowReconcileTask; - - String controllerPktInCounterName; - protected SimpleCounter lastPacketInCounter; - - protected final static int MAX_SYSTEM_LOAD_PER_SECOND = 10000; - /** a minimum flow reconcile rate so that it won't stave */ - protected final static int MIN_FLOW_RECONCILE_PER_SECOND = 200; - - /** start flow reconcile in 10ms after a new reconcile request is received. - * The max delay is 1 second. */ - protected final static int FLOW_RECONCILE_DELAY_MILLISEC = 10; - protected Date lastReconcileTime; - - /** Config to enable or disable flowReconcile */ - protected static final String EnableConfigKey = "enable"; - - /* - * Debug Counters - */ - public static final String PACKAGE = FlowReconcileManager.class.getPackage().getName(); - private IDebugCounter ctrFlowReconcileRequest; - private IDebugCounter ctrReconciledFlows; - protected boolean flowReconcileEnabled; - - public AtomicInteger flowReconcileThreadRunCount; - - @Override - public synchronized void addFlowReconcileListener( - IFlowReconcileListener listener) { - flowReconcileListeners.addListener(OFType.FLOW_MOD, listener); - - if (logger.isTraceEnabled()) { - StringBuffer sb = new StringBuffer(); - sb.append("FlowMod listeners: "); - for (IFlowReconcileListener l : - flowReconcileListeners.getOrderedListeners()) { - sb.append(l.getName()); - sb.append(","); - } - logger.trace(sb.toString()); - } - } - - @Override - public synchronized void removeFlowReconcileListener( - IFlowReconcileListener listener) { - flowReconcileListeners.removeListener(listener); - } - - @Override - public synchronized void clearFlowReconcileListeners() { - flowReconcileListeners.clearListeners(); - } - - /** - * Add to-be-reconciled flow to the queue. - * - * @param ofmRcIn the ofm rc in - */ - @Override - public void reconcileFlow(OFMatchReconcile ofmRcIn, EventPriority priority) { - if (ofmRcIn == null) return; - - // Make a copy before putting on the queue. - OFMatchReconcile myOfmRc = new OFMatchReconcile(ofmRcIn); - - flowQueue.offer(myOfmRc, priority); - ctrFlowReconcileRequest.updateCounterWithFlush(); - - Date currTime = new Date(); - long delay = 0; - - /** schedule reconcile task immidiately if it has been more than 1 sec - * since the last run. Otherwise, schedule the reconcile task in - * DELAY_MILLISEC. - */ - if (currTime.after(new Date(lastReconcileTime.getTime() + 1000))) { - delay = 0; - } else { - delay = FLOW_RECONCILE_DELAY_MILLISEC; - } - flowReconcileTask.reschedule(delay, TimeUnit.MILLISECONDS); - - if (logger.isTraceEnabled()) { - logger.trace("Reconciling flow: {}, total: {}", - myOfmRc.toString(), flowQueue.size()); - } - } - - // IFloodlightModule - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFlowReconcileService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(IFlowReconcileService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IThreadPoolService.class); - l.add(ICounterStoreService.class); - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - threadPool = context.getServiceImpl(IThreadPoolService.class); - counterStore = context.getServiceImpl(ICounterStoreService.class); - debugCounters = context.getServiceImpl(IDebugCounterService.class); - flowQueue = new PriorityPendingQueue<OFMatchReconcile>(); - flowReconcileListeners = - new ListenerDispatcher<OFType, IFlowReconcileListener>(); - - Map<String, String> configParam = context.getConfigParams(this); - String enableValue = configParam.get(EnableConfigKey); - registerFlowReconcileManagerDebugCounters(); - // Set flowReconcile default to true - flowReconcileEnabled = true; - if (enableValue != null && - enableValue.equalsIgnoreCase("false")) { - flowReconcileEnabled = false; - } - flowReconcileThreadRunCount = new AtomicInteger(0); - lastReconcileTime = new Date(0); - logger.debug("FlowReconcile is {}", flowReconcileEnabled); - } - - private void registerFlowReconcileManagerDebugCounters() throws FloodlightModuleException { - if (debugCounters == null) { - logger.error("Debug Counter Service not found."); - debugCounters = new NullDebugCounter(); - } - try { - ctrFlowReconcileRequest = debugCounters.registerCounter(PACKAGE, "flow-reconcile-request", - "All flow reconcile request received by this module", - CounterType.ALWAYS_COUNT); - ctrReconciledFlows = debugCounters.registerCounter(PACKAGE, "reconciled-flows", - "All flows reconciled successfully by this module", - CounterType.ALWAYS_COUNT); - } catch (CounterException e) { - throw new FloodlightModuleException(e.getMessage()); - } - } - - - @Override - public void startUp(FloodlightModuleContext context) { - // thread to do flow reconcile - ScheduledExecutorService ses = threadPool.getScheduledExecutor(); - flowReconcileTask = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - try { - if (doReconcile()) { - flowReconcileTask.reschedule( - FLOW_RECONCILE_DELAY_MILLISEC, - TimeUnit.MILLISECONDS); - } - } catch (Exception e) { - logger.warn("Exception in doReconcile(): {}", e); - } - } - }); - - String packetInName = OFType.PACKET_IN.toClass().getName(); - packetInName = packetInName.substring(packetInName.lastIndexOf('.')+1); - - // Construct controller counter for the packet_in - controllerPktInCounterName = - CounterStore.createCounterName(ICounterStoreService.CONTROLLER_NAME, - -1, - packetInName); - } - - protected void updateFlush() { - // No-OP - } - /** - * Feed the flows into the flow reconciliation pipeline. - * @return true if more flows to be reconciled - * false if no more flows to be reconciled. - */ - protected boolean doReconcile() { - if (!flowReconcileEnabled) { - return false; - } - - // Record the execution time. - lastReconcileTime = new Date(); - - ArrayList<OFMatchReconcile> ofmRcList = - new ArrayList<OFMatchReconcile>(); - - // Get the maximum number of flows that can be reconciled. - int reconcileCapacity = getCurrentCapacity(); - if (logger.isTraceEnabled()) { - logger.trace("Reconcile capacity {} flows", reconcileCapacity); - } - while (!flowQueue.isEmpty() && reconcileCapacity > 0) { - OFMatchReconcile ofmRc = flowQueue.poll(); - reconcileCapacity--; - if (ofmRc != null) { - ofmRcList.add(ofmRc); - ctrReconciledFlows.updateCounterWithFlush(); - if (logger.isTraceEnabled()) { - logger.trace("Add flow {} to be the reconcileList", ofmRc.cookie); - } - } else { - break; - } - } - - // Run the flow through all the flow reconcile listeners - IFlowReconcileListener.Command retCmd; - if (ofmRcList.size() > 0) { - List<IFlowReconcileListener> listeners = - flowReconcileListeners.getOrderedListeners(); - if (listeners == null) { - if (logger.isTraceEnabled()) { - logger.trace("No flowReconcile listener"); - } - return false; - } - - for (IFlowReconcileListener flowReconciler : - flowReconcileListeners.getOrderedListeners()) { - if (logger.isTraceEnabled()) - { - logger.trace("Reconciling flow: call listener {}", - flowReconciler.getName()); - } - retCmd = flowReconciler.reconcileFlows(ofmRcList); - if (retCmd == IFlowReconcileListener.Command.STOP) { - break; - } - } - for (OFMatchReconcile ofmRc : ofmRcList) { - if (ofmRc.origReconcileQueryEvent != null) { - ofmRc.origReconcileQueryEvent.evType.getDebugEvent() - .updateEventWithFlush(new FlowReconcileQueryDebugEvent( - ofmRc.origReconcileQueryEvent, - "Flow Reconciliation Complete", - ofmRc)); - } - } - // Flush the flowCache counters. - updateFlush(); - flowReconcileThreadRunCount.incrementAndGet(); - } else { - if (logger.isTraceEnabled()) { - logger.trace("No flow to be reconciled."); - } - } - - // Return true if there are more flows to be reconciled - if (flowQueue.isEmpty()) { - return false; - } else { - if (logger.isTraceEnabled()) { - logger.trace("{} more flows to be reconciled.", - flowQueue.size()); - } - return true; - } - } - - /** - * Compute the maximum number of flows to be reconciled. - * - * It computes the packetIn increment from the counter values in - * the counter store; - * Then computes the rate based on the elapsed time - * from the last query; - * Then compute the max flow reconcile rate by subtracting the packetIn - * rate from the hard-coded max system rate. - * If the system rate is reached or less than MIN_FLOW_RECONCILE_PER_SECOND, - * set the maximum flow reconcile rate to the MIN_FLOW_RECONCILE_PER_SECOND - * to prevent starvation. - * Then convert the rate to an absolute number for the - * FLOW_RECONCILE_PERIOD. - * @return - */ - protected int getCurrentCapacity() { - ICounter pktInCounter = - counterStore.getCounter(controllerPktInCounterName); - int minFlows = MIN_FLOW_RECONCILE_PER_SECOND * - FLOW_RECONCILE_DELAY_MILLISEC / 1000; - - // If no packetInCounter, then there shouldn't be any flow. - if (pktInCounter == null || - pktInCounter.getCounterDate() == null || - pktInCounter.getCounterValue() == null) { - logger.debug("counter {} doesn't exist", - controllerPktInCounterName); - return minFlows; - } - - // Haven't get any counter yet. - if (lastPacketInCounter == null) { - logger.debug("First time get the count for {}", - controllerPktInCounterName); - lastPacketInCounter = (SimpleCounter) - SimpleCounter.createCounter(pktInCounter); - return minFlows; - } - - int pktInRate = getPktInRate(pktInCounter, new Date()); - - // Update the last packetInCounter - lastPacketInCounter = (SimpleCounter) - SimpleCounter.createCounter(pktInCounter); - int capacity = minFlows; - if ((pktInRate + MIN_FLOW_RECONCILE_PER_SECOND) <= - MAX_SYSTEM_LOAD_PER_SECOND) { - capacity = (MAX_SYSTEM_LOAD_PER_SECOND - pktInRate) - * FLOW_RECONCILE_DELAY_MILLISEC / 1000; - } - - if (logger.isTraceEnabled()) { - logger.trace("Capacity is {}", capacity); - } - return capacity; - } - - protected int getPktInRate(ICounter newCnt, Date currentTime) { - if (newCnt == null || - newCnt.getCounterDate() == null || - newCnt.getCounterValue() == null) { - return 0; - } - - // Somehow the system time is messed up. return max packetIn rate - // to reduce the system load. - if (newCnt.getCounterDate().before( - lastPacketInCounter.getCounterDate())) { - logger.debug("Time is going backward. new {}, old {}", - newCnt.getCounterDate(), - lastPacketInCounter.getCounterDate()); - return MAX_SYSTEM_LOAD_PER_SECOND; - } - - long elapsedTimeInSecond = (currentTime.getTime() - - lastPacketInCounter.getCounterDate().getTime()) / 1000; - if (elapsedTimeInSecond == 0) { - // This should never happen. Check to avoid division by zero. - return 0; - } - - long diff = 0; - switch (newCnt.getCounterValue().getType()) { - case LONG: - long newLong = newCnt.getCounterValue().getLong(); - long oldLong = lastPacketInCounter.getCounterValue().getLong(); - if (newLong < oldLong) { - // Roll over event - diff = Long.MAX_VALUE - oldLong + newLong; - } else { - diff = newLong - oldLong; - } - break; - - case DOUBLE: - double newDouble = newCnt.getCounterValue().getDouble(); - double oldDouble = lastPacketInCounter.getCounterValue().getDouble(); - if (newDouble < oldDouble) { - // Roll over event - diff = (long)(Double.MAX_VALUE - oldDouble + newDouble); - } else { - diff = (long)(newDouble - oldDouble); - } - break; - } - - return (int)(diff/elapsedTimeInSecond); - } -} - diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java deleted file mode 100644 index ad6ce1289f6a3976e00008b82310b09b09cdd2fe..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.lang.ref.SoftReference; - -import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; -import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType; -import net.floodlightcontroller.debugevent.IDebugEventService.EventType; -import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered; -import net.floodlightcontroller.debugevent.IDebugEventService; -import net.floodlightcontroller.debugevent.IEventUpdater; -import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority; - -/** - * The base Class for FlowReconcileQuery. - */ -public class FlowReconcileQuery { - public ReconcileQueryEvType evType; - public EventPriority evPriority; - public static class FlowReconcileQueryDebugEvent { - @EventColumn(name = "Event Info", - description = EventFieldType.SREF_OBJECT) - private final SoftReference<FlowReconcileQuery> eventInfo; - @EventColumn(name = "Stage", - description = EventFieldType.STRING) - private final String stage; - @EventColumn(name = "Stage Info", - description = EventFieldType.SREF_OBJECT) - private final SoftReference<Object> stageInfo; - public FlowReconcileQueryDebugEvent(FlowReconcileQuery eventInfo, - String stage, - Object stageInfo) { - super(); - this.eventInfo = new SoftReference<FlowReconcileQuery>(eventInfo); - this.stage = stage; - if (stageInfo != null) { - this.stageInfo = new SoftReference<Object>(stageInfo); - } else { - this.stageInfo = null; - } - } - } - public static enum ReconcileQueryEvType { - /* Interface rule of a bvs was modified */ - BVS_INTERFACE_RULE_CHANGED(EventPriority.LOW, - "Flow Reconcile Events triggered by BVS Interface Rule Changes"), - BVS_INTERFACE_RULE_CHANGED_MATCH_SWITCH_PORT(EventPriority.LOW, - "Flow Reconcile Events triggered by Switch-Port based BVS Interface Rule Changes"), - BVS_INTERFACE_RULE_CHANGED_MATCH_MAC(EventPriority.LOW, - "Flow Reconcile Events triggered by MAC based BVS Interface Rule Changes"), - BVS_INTERFACE_RULE_CHANGED_MATCH_VLAN(EventPriority.LOW, - "Flow Reconcile Events triggered by VLAN based BVS Interface Rule Changes"), - BVS_INTERFACE_RULE_CHANGED_MATCH_IPSUBNET(EventPriority.LOW, - "Flow Reconcile Events triggered by IP Subnet based BVS Interface Rule Changes"), - BVS_INTERFACE_RULE_CHANGED_MATCH_TAG(EventPriority.LOW, - "Flow Reconcile Events triggered by Tag based BVS Interface Rule Changes"), - /* Some bvs configuration was changed */ - BVS_PRIORITY_CHANGED(EventPriority.LOW, - "Flow Reconcile Events triggered by BVS Priority Changes"), - /* ACL configuration was changed */ - ACL_CONFIG_CHANGED(EventPriority.LOW, - "Flow Reconcile Events triggered by ACL Config Changes"), - /* VRS routing rule was changed */ - VRS_ROUTING_RULE_CHANGED(EventPriority.LOW, - "Flow Reconcile Events triggered by VRS Routing Rule Changes"), - /* VRS static ARP table was changed*/ - VRS_STATIC_ARP_CHANGED(EventPriority.LOW, - "Flow Reconcile Events triggered by VRS Static ARP Config Changes"), - /* device had moved to a different port in the network */ - DEVICE_MOVED(EventPriority.HIGH, - "Flow Reconcile Events triggered by Host moves"), - /* device's property had changed, such as tag assignment */ - DEVICE_PROPERTY_CHANGED(EventPriority.LOW, - "Flow Reconcile Events triggered by Host Property Changes"), - /* Link down */ - LINK_DOWN(EventPriority.MEDIUM, - "Flow Reconcile Events triggered by Link Down Events"); - - private String description; - private EventPriority priority; - private IEventUpdater<FlowReconcileQueryDebugEvent> - evReconcileQueryDebugEvent; - - private ReconcileQueryEvType(EventPriority priority, - String description) { - this.priority = priority; - this.description = description; - } - public EventPriority getPriority() { - return this.priority; - } - public String getDescription() { - return description; - } - public void registerDebugEvent(String packageName, - IDebugEventService debugEvents) - throws MaxEventsRegistered { - try { - evReconcileQueryDebugEvent = - debugEvents.registerEvent( - packageName, - this.toString().toLowerCase().replace("_", "-"), - this.getDescription(), - EventType.ALWAYS_LOG, - FlowReconcileQueryDebugEvent.class, - 500); - } catch (MaxEventsRegistered e) { - throw e; - } - } - public IEventUpdater<FlowReconcileQueryDebugEvent> getDebugEvent() { - return evReconcileQueryDebugEvent; - } - } - public FlowReconcileQuery(ReconcileQueryEvType evType) { - this.evType = evType; - this.evPriority = evType.getPriority(); - } - - @Override - public String toString() { - return "FlowReconcileQuery [evType=" - + evType + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((evType == null) ? 0 : evType.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - FlowReconcileQuery other = (FlowReconcileQuery) obj; - if (evType != other.evType) return false; - return true; - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java deleted file mode 100644 index 245ebdf3993233397e808ec0d8c42a442daca5ef..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.Arrays; - -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.util.MACAddress; - -/** - * The Class for FlowReconcileQuery for device move event. - */ -public class FlowReconcileQueryDeviceMove extends FlowReconcileQuery { - /* The moved device. */ - public IDevice deviceMoved; - /*the oldAP the device moved from*/ - public SwitchPort[] oldAp; - public FlowReconcileQueryDeviceMove() { - super(ReconcileQueryEvType.DEVICE_MOVED); - } - - public FlowReconcileQueryDeviceMove(IDevice deviceMoved, SwitchPort[] oldAp) { - this(); - this.deviceMoved = deviceMoved; - this.oldAp = oldAp.clone(); - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + deviceMoved.getDeviceKey().hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FlowReconcileQueryDeviceMove)) { - return false; - } - FlowReconcileQueryDeviceMove other = (FlowReconcileQueryDeviceMove) obj; - if (oldAp == null) { - if (other.oldAp != null) return false; - } else if (!Arrays.equals(oldAp, other.oldAp)) return false; - if (deviceMoved == null) { - if (other.deviceMoved != null) return false; - } else if (!deviceMoved.equals(other.deviceMoved)) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Device: "); - builder.append(MACAddress.valueOf(deviceMoved.getMACAddress()).toString()); - builder.append(", Old Attachment Points:"); - builder.append(Arrays.toString(oldAp)); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java deleted file mode 100644 index 23c03352383ae9f070df48d596e35860c3159d6f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import org.openflow.util.HexString; - -/** - * The Class for FlowReconcileQuery for link down event. - */ -public class FlowReconcileQueryPortDown extends FlowReconcileQuery { - /*down port switch DPID*/ - public long swId; - /*down port ID */ - public short port; - - public FlowReconcileQueryPortDown() { - super(ReconcileQueryEvType.LINK_DOWN); - } - - public FlowReconcileQueryPortDown(long swId, short portDown) { - this(); - this.swId = swId; - this.port = portDown; - } - - @Override - public int hashCode() { - final int prime = 347; - int result = super.hashCode(); - result = prime * result + (int)swId; - result = prime * result + port; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof FlowReconcileQueryPortDown)) { - return false; - } - FlowReconcileQueryPortDown other = (FlowReconcileQueryPortDown) obj; - if (swId != other.swId) return false; - if (port != other.port) return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("["); - builder.append("Switch: "); - builder.append(HexString.toHexString(swId)); - builder.append(", Port: "); - builder.append(port); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileEngineService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileEngineService.java deleted file mode 100644 index 4887555c9bb1dc05d8a9494dc267dc81b32e7c8e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileEngineService.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; -import net.floodlightcontroller.core.FloodlightContextStore; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightService; - -/** - * The Interface IFlowReconcileEngine. - * - * public interface APIs to Big Switch Flow-Reconcile Service. FlowReconcileEngine queries - * the network-level flows that are currently deployed in the underlying - * network. The flow reconcile engine can be triggered using various filters by using the - * corresponding APIs. - * - * @author MeiYang - */ -public interface IFlowReconcileEngineService extends IFloodlightService { - /** - * A FloodlightContextStore object that can be used to interact with the - * FloodlightContext information about flowCache. - */ - public static final FloodlightContextStore<String> fcStore = - new FloodlightContextStore<String>(); - public static final String FLOWRECONCILE_APP_INSTANCE_NAME = "net.floodlightcontroller.flowcache.appInstanceName"; - /** - * Submit a network flow query with query parameters specified in ReconcileQueryObj - * object. The query object can be created using one of the new ReconcileQueryObj - * helper functions in IFlowCache interface. - * - * @param query the flow cache query object as input - */ - public void submitFlowQueryEvent(FlowReconcileQuery query); - - /** - * Flush Local Counter Updates - * - */ - public void updateFlush(); - - public void init(FloodlightModuleContext fmc) throws FloodlightModuleException; - - public void startUp(FloodlightModuleContext fmc); -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java deleted file mode 100644 index f01bd0b54fa0b5063f7e4d29536817fd1c82e7e9..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import java.util.ArrayList; - -import net.floodlightcontroller.core.IListener; -import org.openflow.protocol.OFType; - -/** - * The Interface IFlowReconciler. - * - * @author subrata - */ -public interface IFlowReconcileListener extends IListener<OFType> { - /** - * Given an input OFMatch, this method applies the policy of the reconciler - * and returns a the same input OFMatch structure modified. Additional - * OFMatches, if needed, are returned in OFMatch-list. All the OFMatches - * are assumed to have "PERMIT" action. - * - * @param ofmRcList input flow matches, to be updated to be consistent with - * the policies of this reconciler - * Additional OFMatch-es can be added to the "list" as - * needed. - * For example after a new ACL application, one flow-match - * may result in multiple flow-matches - * The method must also update the ReconcileAction - * member in ofmRcList entries to indicate if the - * flow needs to be modified, deleted or left unchanged - * OR of a new entry is to be added after flow - * reconciliation - * - * - * @return Command.CONTINUE if the OFMatch should be sent to the - * next flow reconciler. - * Command.STOP if the OFMatch shouldn't be processed - * further. In this case the no reconciled flow-mods would - * be programmed - */ - public Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList); -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java deleted file mode 100644 index ea36e197c2a08b0f19d79dc2b6485deeb2b33b5c..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileService.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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. - **/ - -/** - * Provides Flow Reconcile service to other modules that need to reconcile - * flows. - */ -package net.floodlightcontroller.flowcache; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority; - -public interface IFlowReconcileService extends IFloodlightService { - /** - * Add a flow reconcile listener - * @param listener The module that can reconcile flows - */ - public void addFlowReconcileListener(IFlowReconcileListener listener); - - /** - * Remove a flow reconcile listener - * @param listener The module that no longer reconcile flows - */ - public void removeFlowReconcileListener(IFlowReconcileListener listener); - - /** - * Remove all flow reconcile listeners - */ - public void clearFlowReconcileListeners(); - - /** - * Reconcile flow. Returns false if no modified flow-mod need to be - * programmed if cluster ID is providced then pnly flows in the given - * cluster are reprogrammed - * - * @param ofmRcIn the ofm rc in - */ - public void reconcileFlow(OFMatchReconcile ofmRcIn, EventPriority priority) ; - - public void init(FloodlightModuleContext context) throws FloodlightModuleException ; - public void startUp(FloodlightModuleContext context) throws FloodlightModuleException ; -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java b/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java deleted file mode 100644 index 70b4d42a38efe6a06c6cc823ad58f0e660e89f25..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import net.floodlightcontroller.core.FloodlightContext; -import org.openflow.protocol.OFMatchWithSwDpid; - -/** - * OFMatchReconcile class to indicate result of a flow-reconciliation. - */ -public class OFMatchReconcile { - - /** - * The enum ReconcileAction. Specifies the result of reconciliation of a - * flow. - */ - public enum ReconcileAction { - - /** Delete the flow-mod from the switch */ - DROP, - /** Leave the flow-mod as-is. */ - NO_CHANGE, - /** Program this new flow mod. */ - NEW_ENTRY, - /** - * Reprogram the flow mod as the path of the flow might have changed, - * for example when a host is moved or when a link goes down. */ - UPDATE_PATH, - /* Flow is now in a different BVS */ - APP_INSTANCE_CHANGED, - /* Delete the flow-mod - used to delete, for example, drop flow-mods - * when the source and destination are in the same BVS after a - * configuration change */ - DELETE - } - - /** The open flow match after reconciliation. */ - public OFMatchWithSwDpid ofmWithSwDpid; - /** flow mod. priority */ - public short priority; - /** Action of this flow-mod PERMIT or DENY */ - public byte action; - /** flow mod. cookie */ - public long cookie; - /** The application instance name. */ - public String appInstName; - /** - * The new application instance name. This is null unless the flow - * has moved to a different BVS due to BVS config change or device - * move to a different switch port etc.*/ - public String newAppInstName; - /** The reconcile action. */ - public ReconcileAction rcAction; - /** Outport in the event of UPDATE_PATH action**/ - public short outPort; - - // The context for the reconcile action - public FloodlightContext cntx; - - // The original flow reconcile query event that triggered this flow - // to be reconciled - public FlowReconcileQuery origReconcileQueryEvent; - - /** - * Instantiates a new oF match reconcile object. - */ - public OFMatchReconcile() { - ofmWithSwDpid = new OFMatchWithSwDpid(); - rcAction = ReconcileAction.NO_CHANGE; - cntx = new FloodlightContext(); - } - - public OFMatchReconcile(OFMatchReconcile copy) { - ofmWithSwDpid = - new OFMatchWithSwDpid(copy.ofmWithSwDpid.getOfMatch(), - copy.ofmWithSwDpid.getSwitchDataPathId()); - priority = copy.priority; - action = copy.action; - cookie = copy.cookie; - appInstName = copy.appInstName; - newAppInstName = copy.newAppInstName; - rcAction = copy.rcAction; - outPort = copy.outPort; - cntx = new FloodlightContext(); - origReconcileQueryEvent = copy.origReconcileQueryEvent; - } - - @Override - public String toString() { - return "OFMatchReconcile [" + ofmWithSwDpid + " priority=" + priority + " action=" + action + - " cookie=" + cookie + " appInstName=" + appInstName + " newAppInstName=" + newAppInstName + - " ReconcileAction=" + rcAction + "outPort=" + outPort + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + action; - result = prime * result - + ((appInstName == null) ? 0 : appInstName.hashCode()); - result = prime * result + (int) (cookie ^ (cookie >>> 32)); - result = prime - * result - + ((newAppInstName == null) ? 0 : newAppInstName.hashCode()); - result = prime * result - + ((ofmWithSwDpid == null) ? 0 : ofmWithSwDpid.hashCode()); - result = prime * result + outPort; - result = prime * result + priority; - result = prime * result - + ((rcAction == null) ? 0 : rcAction.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof OFMatchReconcile)) { - return false; - } - OFMatchReconcile other = (OFMatchReconcile) obj; - if (action != other.action) { - return false; - } - if (appInstName == null) { - if (other.appInstName != null) { - return false; - } - } else if (!appInstName.equals(other.appInstName)) { - return false; - } - if (cookie != other.cookie) { - return false; - } - if (newAppInstName == null) { - if (other.newAppInstName != null) { - return false; - } - } else if (!newAppInstName.equals(other.newAppInstName)) { - return false; - } - if (ofmWithSwDpid == null) { - if (other.ofmWithSwDpid != null) { - return false; - } - } else if (!ofmWithSwDpid.equals(other.ofmWithSwDpid)) { - return false; - } - if (outPort != other.outPort) { - return false; - } - if (priority != other.priority) { - return false; - } - if (rcAction != other.rcAction) { - return false; - } - return true; - } - -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java b/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java deleted file mode 100644 index 31e7a1f3a23bfbdd23c6a5d6aee22d57959dd45e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/PendingSwRespKey.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -public class PendingSwRespKey { - long swDpid; - int transId; - - public PendingSwRespKey(long swDpid, int transId) { - this.swDpid = swDpid; - this.transId = transId; - } - - @Override - public int hashCode() { - final int prime = 97; - Long dpid = swDpid; - Integer tid = transId; - return (tid.hashCode()*prime + dpid.hashCode()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof PendingSwRespKey)) { - return false; - } - PendingSwRespKey other = (PendingSwRespKey) obj; - if ((swDpid != other.swDpid) || (transId != other.transId)) { - return false; - } - return true; - } - - @Override - public String toString() { - return Long.toHexString(swDpid)+","+Integer.toString(transId); - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java b/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java deleted file mode 100644 index a2f57bb9cc166e073e2ebacf4b950fdc292b6a12..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java +++ /dev/null @@ -1,493 +0,0 @@ -/** - * Copyright 2012, Jason Parraga, Marist College - * - * 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.flowcache; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMatchWithSwDpid; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFStatisticsRequest; -import org.openflow.protocol.OFType; -import org.openflow.protocol.statistics.OFFlowStatisticsReply; -import org.openflow.protocol.statistics.OFFlowStatisticsRequest; -import org.openflow.protocol.statistics.OFStatistics; -import org.openflow.protocol.statistics.OFStatisticsType; -import org.openflow.util.HexString; -import org.openflow.util.U16; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.flowcache.IFlowReconcileListener; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.flowcache.OFMatchReconcile; -import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.topology.ITopologyListener; -import net.floodlightcontroller.topology.ITopologyService; - -/** - * Flow reconciliation module that is triggered by PORT_DOWN events. This module - * will recursively trace back all flows from the immediately affected switch - * and remove them (specifically flows with an idle timeout that would not be - * exhausted). Once the flows are deleted Floodlight will re-evaluate the path - * the traffic should take with it's updated topology map. - * - * @author Jason Parraga - */ - -public class PortDownReconciliation implements IFloodlightModule, - ITopologyListener, IFlowReconcileListener { - protected static Logger log = LoggerFactory.getLogger(PortDownReconciliation.class); - - protected ITopologyService topology; - protected IFloodlightProviderService floodlightProvider; - protected IFlowReconcileService frm; - protected ILinkDiscoveryService lds; - protected Map<Link, LinkInfo> links; - protected FloodlightContext cntx; - protected static boolean waiting = false; - protected int statsQueryXId; - protected static List<OFFlowStatisticsReply> statsReply; - - // ITopologyListener - @Override - public void topologyChanged(List<LDUpdate> appliedUpdates) { - for (LDUpdate ldu : appliedUpdates) { - if (ldu.getOperation() - .equals(ILinkDiscovery.UpdateOperation.PORT_DOWN)) { - - // Get the switch ID for the OFMatchWithSwDpid object - long affectedSwitch = floodlightProvider.getSwitch(ldu.getSrc()) - .getId(); - - // Create an OFMatchReconcile object - OFMatchReconcile ofmr = new OFMatchReconcile(); - - // Generate an OFMatch objects for the OFMatchWithSwDpid object - OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL); - - // Generate the OFMatchWithSwDpid - OFMatchWithSwDpid ofmatchsw = new OFMatchWithSwDpid(match, - affectedSwitch); - - // Set the action to update the path to remove flows routing - // towards the downed port - ofmr.rcAction = OFMatchReconcile.ReconcileAction.UPDATE_PATH; - - // Set the match, with the switch dpid - ofmr.ofmWithSwDpid = ofmatchsw; - - // Assign the downed port to the OFMatchReconcile's outPort data - // member (I added this to - // the OFMatchReconcile class) - ofmr.outPort = ldu.getSrcPort(); - - // Tell the reconcile manager to reconcile matching flows - frm.reconcileFlow(ofmr, EventPriority.HIGH); - } - } - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleServices() { - return null; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - return null; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(ITopologyService.class); - l.add(IFlowReconcileService.class); - l.add(ILinkDiscoveryService.class); - return l; - } - - @Override - public - void - init(FloodlightModuleContext context) - throws FloodlightModuleException { - floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); - topology = context.getServiceImpl(ITopologyService.class); - frm = context.getServiceImpl(IFlowReconcileService.class); - lds = context.getServiceImpl(ILinkDiscoveryService.class); - cntx = new FloodlightContext(); - } - - @Override - public void startUp(FloodlightModuleContext context) { - topology.addListener(this); - frm.addFlowReconcileListener(this); - } - - @Override - public String getName() { - return "portdownreconciliation"; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return true; - } - - /** - * Base case for the reconciliation of flows. This is triggered at the - * switch which is immediately affected by the PORT_DOWN event - * - * @return the Command whether to STOP or Continue - */ - @Override - public net.floodlightcontroller.core.IListener.Command - reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) { - if (lds != null) { - links = new HashMap<Link, LinkInfo>(); - // Get all the switch links from the topology - if (lds.getLinks() != null) links.putAll(lds.getLinks()); - - for (OFMatchReconcile ofmr : ofmRcList) { - // We only care about OFMatchReconcile objects that wish to - // update the path to a switch - if (ofmr.rcAction.equals(OFMatchReconcile.ReconcileAction.UPDATE_PATH)) { - // Get the switch object from the OFMatchReconcile - IOFSwitch sw = floodlightProvider - .getSwitch(ofmr.ofmWithSwDpid.getSwitchDataPathId()); - - // Map data structure that holds the invalid matches and the - // ingress ports of those matches - Map<Short, List<OFMatch>> invalidBaseIngressAndMatches = new HashMap<Short, List<OFMatch>>(); - - // Get the invalid flows - List<OFFlowStatisticsReply> flows = getFlows(sw, - ofmr.outPort); - - // Analyze all the flows with outPorts equaling the downed - // port and extract OFMatch's to trace back to neighbors - for (OFFlowStatisticsReply flow : flows) { - // Create a reference to the match for ease - OFMatch match = flow.getMatch(); - - // Here we utilize an index of input ports which point - // to multiple invalid matches - if (invalidBaseIngressAndMatches.containsKey(match.getInputPort())) - // If the input port is already in the index, add - // the match to it's list - invalidBaseIngressAndMatches.get(match.getInputPort()) - .add(match); - else { - // Otherwise create a new list and add it to the - // index - List<OFMatch> matches = new ArrayList<OFMatch>(); - matches.add(match); - invalidBaseIngressAndMatches.put(match.getInputPort(), - matches); - } - } - - // Remove invalid flows from the base switch, if they exist - if (!flows.isEmpty()) { - log.debug("Removing flows on switch : " + sw.getId() - + " with outport: " + ofmr.outPort); - clearFlowMods(sw, ofmr.outPort); - } - - // Create a list of neighboring switches we need to remove - // invalid flows from - Map<IOFSwitch, Map<Short, List<OFMatch>>> neighborSwitches = new HashMap<IOFSwitch, Map<Short, List<OFMatch>>>(); - - // Loop through all the links - for (Link link : links.keySet()) { - // Filter out links we care about - if (link.getDst() == sw.getId()) { - // Loop through the links to neighboring switches - // which have invalid flows - for (Entry<Short, List<OFMatch>> invalidBaseIngressAndMatch : invalidBaseIngressAndMatches.entrySet()) { - // Find links on the network which link to the - // ingress ports that have invalidly routed - // flows - if (link.getDstPort() == invalidBaseIngressAndMatch.getKey()) { - Map<Short, List<OFMatch>> invalidNeighborOutportAndMatch = new HashMap<Short, List<OFMatch>>(); - // Insert the neighbor's outPort to the base - // switch and the invalid match - invalidNeighborOutportAndMatch.put(link.getSrcPort(), - invalidBaseIngressAndMatch.getValue()); - // Link a neighbor switch's invalid match - // and outport to their Switch object - neighborSwitches.put(floodlightProvider.getSwitch(link.getSrc()), - invalidNeighborOutportAndMatch); - } - } - } - } - log.debug("We have " + neighborSwitches.size() - + " neighboring switches to deal with!"); - // Loop through all the switches we found to have potential - // issues - for (IOFSwitch neighborSwitch : neighborSwitches.keySet()) { - log.debug("NeighborSwitch ID : " - + neighborSwitch.getId()); - if (neighborSwitches.get(neighborSwitch) != null) - deleteInvalidFlows(neighborSwitch, - neighborSwitches.get(neighborSwitch)); - } - } - return Command.CONTINUE; - } - } else { - log.error("Link Discovery Service Is Null"); - } - return Command.CONTINUE; - } - - /** - * @param sw - * the switch object that we wish to get flows from - * @param outPort - * the output action port we wish to find flows with - * @return a list of OFFlowStatisticsReply objects or essentially flows - */ - public List<OFFlowStatisticsReply> getFlows(IOFSwitch sw, Short outPort) { - - statsReply = new ArrayList<OFFlowStatisticsReply>(); - List<OFStatistics> values = null; - Future<List<OFStatistics>> future; - - // Statistics request object for getting flows - OFStatisticsRequest req = new OFStatisticsRequest(); - req.setStatisticType(OFStatisticsType.FLOW); - int requestLength = req.getLengthU(); - OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest(); - specificReq.setMatch(new OFMatch().setWildcards(0xffffffff)); - specificReq.setOutPort(outPort); - specificReq.setTableId((byte) 0xff); - req.setStatistics(Collections.singletonList((OFStatistics) specificReq)); - requestLength += specificReq.getLength(); - req.setLengthU(requestLength); - - try { - // System.out.println(sw.getStatistics(req)); - future = sw.queryStatistics(req); - values = future.get(10, TimeUnit.SECONDS); - if (values != null) { - for (OFStatistics stat : values) { - statsReply.add((OFFlowStatisticsReply) stat); - } - } - } catch (Exception e) { - log.error("Failure retrieving statistics from switch " + sw, e); - } - - return statsReply; - } - - /** - * @param sw - * The switch we wish to remove flows from - * @param outPort - * The specific Output Action OutPort of specific flows we wish - * to delete - */ - public void clearFlowMods(IOFSwitch sw, Short outPort) { - // Delete all pre-existing flows with the same output action port or - // outPort - OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL); - OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD)).setMatch(match) - .setCommand(OFFlowMod.OFPFC_DELETE) - .setOutPort(outPort) - .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH)); - try { - List<OFMessage> msglist = new ArrayList<OFMessage>(1); - msglist.add(fm); - sw.write(msglist, cntx); - } catch (Exception e) { - log.error("Failed to clear flows on switch {} - {}", this, e); - } - } - - /** - * @param sw - * The switch we wish to remove flows from - * @param match - * The specific OFMatch object of specific flows we wish to - * delete - * @param outPort - * The specific Output Action OutPort of specific flows we wish - * to delete - */ - public void clearFlowMods(IOFSwitch sw, OFMatch match, Short outPort) { - // Delete pre-existing flows with the same match, and output action port - // or outPort - match.setWildcards(OFMatch.OFPFW_ALL); - OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD)).setMatch(match) - .setCommand(OFFlowMod.OFPFC_DELETE) - .setOutPort(outPort) - .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH)); - try { - List<OFMessage> msglist = new ArrayList<OFMessage>(1); - msglist.add(fm); - sw.write(msglist, cntx); - } catch (Exception e) { - log.error("Failed to clear flows on switch {} - {}", this, e); - } - } - - /** - * Deletes flows with similar matches and output action ports on the - * specified switch - * - * @param sw - * the switch to query flows on - * @param match - * the problematic OFMatch from the base switch which we wish to - * find and remove - * @param outPort - * the output action port wanted from the flows, which follows - * the route to the base switch - */ - public - void - deleteInvalidFlows(IOFSwitch sw, - Map<Short, List<OFMatch>> invalidOutportAndMatch) { - log.debug("Deleting invalid flows on switch : " + sw.getId()); - - // A map that holds the input ports and invalid matches on a switch - Map<Short, List<OFMatch>> invalidNeighborIngressAndMatches = new HashMap<Short, List<OFMatch>>(); - - for (Short outPort : invalidOutportAndMatch.keySet()) { - // Get the flows on the switch - List<OFFlowStatisticsReply> flows = getFlows(sw, outPort); - - // Analyze all the flows with outPorts pointing to problematic route - for (OFFlowStatisticsReply flow : flows) { - // Loop through all the problematic matches - for (OFMatch match : invalidOutportAndMatch.get(outPort)) { - // Compare the problematic matches with the match of the - // flow on the switch - if (HexString.toHexString(flow.getMatch() - .getDataLayerDestination()) - .equals(HexString.toHexString(match.getDataLayerDestination())) - && HexString.toHexString(flow.getMatch() - .getDataLayerSource()) - .equals(HexString.toHexString(match.getDataLayerSource())) - && flow.getMatch().getDataLayerType() == match.getDataLayerType() - && flow.getMatch().getDataLayerVirtualLan() == match.getDataLayerVirtualLan() - && flow.getMatch().getNetworkDestination() == match.getNetworkDestination() - && flow.getMatch().getNetworkDestinationMaskLen() == match.getNetworkDestinationMaskLen() - && flow.getMatch().getNetworkProtocol() == match.getNetworkProtocol() - && flow.getMatch().getNetworkSource() == match.getNetworkSource() - && flow.getMatch().getNetworkSourceMaskLen() == match.getNetworkSourceMaskLen() - && flow.getMatch().getNetworkTypeOfService() == match.getNetworkTypeOfService()) { - - // Here we utilize an index of input ports which point - // to multiple invalid matches - if (invalidNeighborIngressAndMatches.containsKey(match.getInputPort())) - // If the input port is already in the index, add - // the match to it's list - invalidNeighborIngressAndMatches.get(match.getInputPort()) - .add(match); - else { - // Otherwise create a new list and add it to the - // index - List<OFMatch> matches = new ArrayList<OFMatch>(); - matches.add(match); - invalidNeighborIngressAndMatches.put(match.getInputPort(), - matches); - } - // Remove flows from the switch with the invalid match - // and outPort - clearFlowMods(sw, flow.getMatch(), outPort); - } - } - } - - // Create a list of neighboring switches we need to check for - // invalid flows - Map<IOFSwitch, Map<Short, List<OFMatch>>> neighborSwitches = new HashMap<IOFSwitch, Map<Short, List<OFMatch>>>(); - - // Loop through all the links - for (Link link : links.keySet()) { - // Filter out links we care about - if (link.getDst() == sw.getId()) { - // Loop through the ingressPorts that are involved in - // invalid flows on neighboring switches - for (Entry<Short, List<OFMatch>> ingressPort : invalidNeighborIngressAndMatches.entrySet()) { - // Filter out invalid links by matching the link - // destination port to our invalid flows ingress port - if (link.getDstPort() == ingressPort.getKey()) { - // Generate a match and outPort map since I don't - // want to create an object - Map<Short, List<OFMatch>> invalidNeighborOutportAndMatch = new HashMap<Short, List<OFMatch>>(); - invalidNeighborOutportAndMatch.put(link.getSrcPort(), - ingressPort.getValue()); - // Link a neighbor switch's invalid match and - // outport to their Switch object - neighborSwitches.put(floodlightProvider.getSwitch(link.getSrc()), - invalidNeighborOutportAndMatch); - } - } - } - } - log.debug("We have " + neighborSwitches.size() - + " neighbors to deal with!"); - - // Loop through all the neighbor switches we found to have - // invalid matches - for (IOFSwitch neighborSwitch : neighborSwitches.keySet()) { - log.debug("NeighborSwitch ID : " + neighborSwitch.getId()); - // Recursively seek out and delete invalid flows on the - // neighbor switch - deleteInvalidFlows(neighborSwitch, - neighborSwitches.get(neighborSwitch)); - } - } - } -} diff --git a/src/main/java/net/floodlightcontroller/flowcache/PriorityPendingQueue.java b/src/main/java/net/floodlightcontroller/flowcache/PriorityPendingQueue.java deleted file mode 100644 index 5f90a24e50ac429ebe3f4713b68807589865a32e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/flowcache/PriorityPendingQueue.java +++ /dev/null @@ -1,198 +0,0 @@ -package net.floodlightcontroller.flowcache; - -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * PriorityPendingQueue class - This class is a variant implementation for PriorityBlockingQueue - * PriorityBlockingQueue implementation has two problems: - * 1. service for events with the same priority has no guarantee of FIFO sequence. This can be solved by override of comparator though. - * 2. PriorityBlockingQueue is implemented through heap, which has a O(log(n)) complexity for enqueue and dequeue operations. - * to get a O(1) complexity with enqueue and dequeue operations, we propose this PriorityPendingList class. - * <p> - * PriorityPendingQueue has three separate queues: High Priority, Medium Priority and Low Priority. - * the requirements here are: - * 1. dequeue from the Queue will always return the event with the highest priority - * 2. events with the same priority will be dequeued in their inserting order - * 3. enqueue and dequeue have O(1) complexity - * - * current only support offer() and take() methods - * - * @author meiyang - * - */ -public class PriorityPendingQueue<E> { - private LinkedBlockingQueue<E> highPriorityQueue; - private LinkedBlockingQueue<E> mediumPriorityQueue; - private LinkedBlockingQueue<E> lowPriorityQueue; - private final AtomicInteger count = new AtomicInteger(0); - private final ReentrantLock takeLock = new ReentrantLock(); - private final Condition notEmpty = takeLock.newCondition(); - private final ReentrantLock putLock = new ReentrantLock(); - private final Condition notFull = putLock.newCondition(); - private final int capacity; - public enum EventPriority { - HIGH, - MEDIUM, - LOW, - } - public PriorityPendingQueue() { - highPriorityQueue= new LinkedBlockingQueue<E>(); - mediumPriorityQueue= new LinkedBlockingQueue<E>(); - lowPriorityQueue= new LinkedBlockingQueue<E>(); - capacity= Integer.MAX_VALUE; - } - - public E take() throws InterruptedException { - E x; - int c = -1; - final AtomicInteger count = this.count; - final ReentrantLock takeLock = this.takeLock; - takeLock.lockInterruptibly(); - try { - try { - while (count.get() == 0) - notEmpty.await(); - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to a non-interrupted thread - throw ie; - } - x = extract(); - c = count.getAndDecrement(); - if (c > 1) - notEmpty.signal(); - } finally { - takeLock.unlock(); - } - if (c == capacity) - signalNotFull(); - return x; - } - - public E poll() { - final AtomicInteger count = this.count; - if (count.get() == 0) - return null; - E x = null; - int c = -1; - final ReentrantLock takeLock = this.takeLock; - takeLock.lock(); - try { - if (count.get() > 0) { - x = extract(); - c = count.getAndDecrement(); - if (c > 1) - notEmpty.signal(); - } - } finally { - takeLock.unlock(); - } - if (c == capacity) - signalNotFull(); - return x; - } - - public E peek() { - //todo - return null; - } - - public boolean offer(E e, EventPriority p) { - if (e == null) throw new NullPointerException(); - final AtomicInteger count = this.count; - if (count.get() == capacity) - return false; - int c = -1; - final ReentrantLock putLock = this.putLock; - putLock.lock(); - try { - if (count.get() < capacity) { - insert(e,p); - c = count.getAndIncrement(); - if (c + 1 < capacity) - notFull.signal(); - } - } finally { - putLock.unlock(); - } - if (c == 0) - signalNotEmpty(); - return c >= 0; - } - - public boolean offer(E e) { - return false; - } - - private E extract() { - E first = highPriorityQueue.poll(); - if (first==null) - first = mediumPriorityQueue.poll(); - if (first==null) - first = lowPriorityQueue.poll(); - return first; - } - - private boolean insert(E e, EventPriority p) { - boolean result = false; - switch (p) { - case HIGH: - result = highPriorityQueue.offer(e); - break; - case MEDIUM: - result = mediumPriorityQueue.offer(e); - break; - case LOW: - result = lowPriorityQueue.offer(e); - break; - } - return result; - } - - private void signalNotFull() { - final ReentrantLock putLock = this.putLock; - putLock.lock(); - try { - notFull.signal(); - } finally { - putLock.unlock(); - } - } - - private void signalNotEmpty() { - final ReentrantLock takeLock = this.takeLock; - takeLock.lock(); - try { - notEmpty.signal(); - } finally { - takeLock.unlock(); - } - } - private void fullyLock() { - putLock.lock(); - takeLock.lock(); - } - private void fullyUnlock() { - takeLock.unlock(); - putLock.unlock(); - } - public int size() { - return count.get(); - } - public void clear() { - fullyLock(); - try { - highPriorityQueue.clear(); - mediumPriorityQueue.clear(); - lowPriorityQueue.clear(); - count.set(0); - } finally { - fullyUnlock(); - } - } - public boolean isEmpty() { - return count.get() == 0; - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java deleted file mode 100644 index 40fc77bcf04734639005148fc7c98a81ea555f9a..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java +++ /dev/null @@ -1,454 +0,0 @@ -/** -* 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; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.annotations.LogMessageDocs; -import net.floodlightcontroller.core.internal.IOFSwitchService; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.AppCookie; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.routing.ForwardingBase; -import net.floodlightcontroller.routing.IRoutingDecision; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.topology.ITopologyService; - -import org.projectfloodlight.openflow.protocol.OFFlowMod; -import org.projectfloodlight.openflow.protocol.OFFlowModCommand; -import org.projectfloodlight.openflow.protocol.OFFlowModFlags; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFPacketOut; -import org.projectfloodlight.openflow.protocol.OFPortDesc; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.protocol.match.Match; -import org.projectfloodlight.openflow.protocol.match.MatchField; -import org.projectfloodlight.openflow.protocol.action.OFAction; -import org.projectfloodlight.openflow.protocol.action.OFActionOutput; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.IPv4Address; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.types.OFVlanVidMatch; -import org.projectfloodlight.openflow.types.VlanVid; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@LogMessageCategory("Flow Programming") -public class Forwarding extends ForwardingBase implements IFloodlightModule { - protected static Logger log = LoggerFactory.getLogger(Forwarding.class); - - @Override - @LogMessageDoc(level="ERROR", - message="Unexpected decision made for this packet-in={}", - explanation="An unsupported PacketIn decision has been " + - "passed to the flow programming component", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, - FloodlightContext cntx) { - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - // If a decision has been made we obey it - // otherwise we just forward - if (decision != null) { - if (log.isTraceEnabled()) { - log.trace("Forwaring decision={} was made for PacketIn={}", - decision.getRoutingAction().toString(), - pi); - } - - switch(decision.getRoutingAction()) { - case NONE: - // don't do anything - return Command.CONTINUE; - case FORWARD_OR_FLOOD: - case FORWARD: - doForwardFlow(sw, pi, cntx, false); - return Command.CONTINUE; - case MULTICAST: - // treat as broadcast - doFlood(sw, pi, cntx); - return Command.CONTINUE; - case DROP: - doDropFlow(sw, pi, decision, cntx); - return Command.CONTINUE; - default: - log.error("Unexpected decision made for this packet-in={}", - pi, decision.getRoutingAction()); - return Command.CONTINUE; - } - } else { - if (log.isTraceEnabled()) { - log.trace("No decision was made for PacketIn={}, forwarding", - pi); - } - - if (eth.isBroadcast() || eth.isMulticast()) { - // For now we treat multicast as broadcast - doFlood(sw, pi, cntx); - } else { - doForwardFlow(sw, pi, cntx, false); - } - } - - return Command.CONTINUE; - } - - @LogMessageDoc(level="ERROR", - message="Failure writing drop flow mod", - explanation="An I/O error occured while trying to write a " + - "drop flow mod to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) { - // initialize match structure and populate it using the packet - OFMatch match = new OFMatch(); - match.loadFromPacket(pi.getPacketData(), pi.getInPort()); - if (decision.getWildcards() != null) { - match.setWildcards(decision.getWildcards()); - } - - // Create flow-mod based on packet-in and src-switch - OFFlowMod fm = - (OFFlowMod) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD); - List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to - // drop - long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); - - fm.setCookie(cookie) - .setHardTimeout((short) 0) - .setIdleTimeout((short) 5) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setMatch(match) - .setActions(actions) - .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH); - - try { - if (log.isDebugEnabled()) { - log.debug("write drop flow-mod sw={} match={} flow-mod={}", - new Object[] { sw, match, fm }); - } - messageDamper.write(sw, fm, cntx); - } catch (IOException e) { - log.error("Failure writing drop flow mod", e); - } - } - - protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, - FloodlightContext cntx, - boolean requestFlowRemovedNotifn) { - //OFMatch match = new OFMatch(); - //match.loadFromPacket(pi.getData(), pi.getInPort()); - //Match.Builder matchBuilder = sw.getOFFactory().buildMatch(); - Match match = pi.getMatch(); - // Check if we have the location of the destination - IDevice dstDevice = - IDeviceService.fcStore. - get(cntx, IDeviceService.CONTEXT_DST_DEVICE); - - // DESTINATION DEVICE = KNOWN - if (dstDevice != null) { - IDevice srcDevice = - IDeviceService.fcStore. - get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); - DatapathId srcIsland = topology.getL2DomainId(sw.getId()); - - // If we can't find the source device, that's no good - if (srcDevice == null) { - log.debug("No device entry found for source device"); - return; - } - - // If the source isn't connected to an OF island we control, then that's not good either - if (srcIsland == null) { - log.debug("No openflow island found for source {}/{}", - sw.getStringId(), pi.getInPort()); - return; - } - - // Validate that we have a destination known on the same island - // Validate that the source and destination are not on the same switch port - boolean on_same_island = false; - boolean on_same_if = false; - for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) { - DatapathId dstSwDpid = dstDap.getSwitchDPID(); - DatapathId dstIsland = topology.getL2DomainId(dstSwDpid); - if ((dstIsland != null) && dstIsland.equals(srcIsland)) { - on_same_island = true; - if ((sw.getId().equals(dstSwDpid)) && - (pi.getInPort().equals(dstDap.getPort()))) { - on_same_if = true; - } - break; - } - } - - // If the two devices are not on the same L2 network, find out how to get to the destination via flooding - if (!on_same_island) { - if (log.isTraceEnabled()) { - log.trace("No first hop island found for destination " + - "device {}, Action = flooding", dstDevice); - } - doFlood(sw, pi, cntx); - return; - } - - // If the two devices are on the same switch port number, they should be able to communicate w/o further flows - if (on_same_if) { - if (log.isTraceEnabled()) { - log.trace("Both source and destination are on the same " + - "switch/port {}/{}, Action = NOP", - sw.toString(), pi.getInPort()); - } - return; - } - - // Install all the routes where both src and dst have attachment - // points. Since the lists are stored in sorted order we can - // traverse the attachment points in O(m+n) time - SwitchPort[] srcDaps = srcDevice.getAttachmentPoints(); - Arrays.sort(srcDaps, clusterIdComparator); - SwitchPort[] dstDaps = dstDevice.getAttachmentPoints(); - Arrays.sort(dstDaps, clusterIdComparator); - - int iSrcDaps = 0, iDstDaps = 0; - - while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) { - SwitchPort srcDap = srcDaps[iSrcDaps]; - SwitchPort dstDap = dstDaps[iDstDaps]; - - // srcCluster and dstCluster here cannot be null as - // every switch will be at least in its own L2 domain. - DatapathId srcCluster = - topology.getL2DomainId(srcDap.getSwitchDPID()); - DatapathId dstCluster = - topology.getL2DomainId(dstDap.getSwitchDPID()); - - int srcVsDest = srcCluster.compareTo(dstCluster); - if (srcVsDest == 0) { - if (!srcDap.equals(dstDap)) { - Route route = - routingEngine.getRoute(srcDap.getSwitchDPID(), - srcDap.getPort(), - dstDap.getSwitchDPID(), - dstDap.getPort(), 0); //cookie = 0, i.e., default route - if (route != null) { - if (log.isTraceEnabled()) { - log.trace("pushRoute match={} route={} " + - "destination={}:{}", - new Object[] {match, route, - dstDap.getSwitchDPID(), - dstDap.getPort()}); - } - long cookie = - AppCookie.makeCookie(FORWARDING_APP_ID, 0); - - // if there is prior routing decision use wildcard - Match.Builder wildcard_hints; - IRoutingDecision decision = null; - if (cntx != null) { - decision = IRoutingDecision.rtStore - .get(cntx, - IRoutingDecision.CONTEXT_DECISION); - } - if (decision != null) { - wildcard_hints = decision.getWildcards(); - } else { - // L2 only wildcard if there is no prior route decision - /*wildcard_hints = ((Integer) sw - .getAttribute(IOFSwitch.PROP_FASTWILDCARDS)) - .intValue() - & ~OFMatch.OFPFW_IN_PORT - & ~OFMatch.OFPFW_DL_VLAN - & ~OFMatch.OFPFW_DL_SRC - & ~OFMatch.OFPFW_DL_DST - & ~OFMatch.OFPFW_NW_SRC_MASK - & ~OFMatch.OFPFW_NW_DST_MASK;*/ - //TODO @Ryan does the use of NO_MASK here automatically assume isFullyWildcarded is true? - // dummy values set to not trigger isFullyWildcarded - wildcard_hints = sw.getOFFactory().buildMatch(); - wildcard_hints.setExact(MatchField.IN_PORT, OFPort.of(1)); - wildcard_hints.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(1)); - wildcard_hints.setExact(MatchField.ETH_SRC, MacAddress.BROADCAST); - wildcard_hints.setExact(MatchField.ETH_DST, MacAddress.BROADCAST); - wildcard_hints.setExact(MatchField.IPV4_SRC, IPv4Address.FULL_MASK); - wildcard_hints.setExact(MatchField.IPV4_DST, IPv4Address.FULL_MASK); - } - - pushRoute(route, match, wildcard_hints, pi, sw.getId(), cookie, - cntx, requestFlowRemovedNotifn, false, - OFFlowModCommand.ADD); - } - } - iSrcDaps++; - iDstDaps++; - } else if (srcVsDest < 0) { - iSrcDaps++; - } else { - iDstDaps++; - } - } - // END DESTINATION DEVICE = KNOWN - } else { - // DESTINATION DEVICE = UNKNOWN, thus flood to hopefully/eventually find out where the destination is - doFlood(sw, pi, cntx); - } - } - - /** - * Creates a OFPacketOut with the OFPacketIn data that is flooded on all ports unless - * the port is blocked, in which case the packet will be dropped. - * @param sw The switch that receives the OFPacketIn - * @param pi The OFPacketIn that came to the switch - * @param cntx The FloodlightContext associated with this OFPacketIn - */ - @LogMessageDoc(level="ERROR", - message="Failure writing PacketOut " + - "switch={switch} packet-in={packet-in} " + - "packet-out={packet-out}", - explanation="An I/O error occured while writing a packet " + - "out message to the switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - protected void doFlood(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { - if (topology.isIncomingBroadcastAllowed(sw.getId(), - pi.getInPort()) == false) { - if (log.isTraceEnabled()) { - log.trace("doFlood, drop broadcast packet, pi={}, " + - "from a blocked port, srcSwitch=[{},{}], linkInfo={}", - new Object[] {pi, sw.getId(),pi.getInPort()}); - } - return; - } - - // Set Action to flood - OFPacketOut po = - (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); - List<OFAction> actions = new ArrayList<OFAction>(); - if (sw.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) { - actions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(), - (short)0xFFFF)); - } else { - actions.add(new OFActionOutput(OFPort.OFPP_ALL.getValue(), - (short)0xFFFF)); - } - po.setActions(actions); - po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); - - // set buffer-id, in-port and packet-data based on packet-in - short poLength = (short)(po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); - po.setBufferId(OFPacketOut.BUFFER_ID_NONE); - po.setInPort(pi.getInPort()); - byte[] packetData = pi.getPacketData(); - poLength += packetData.length; - po.setPacketData(packetData); - po.setLength(poLength); - - try { - if (log.isTraceEnabled()) { - log.trace("Writing flood PacketOut switch={} packet-in={} packet-out={}", - new Object[] {sw, pi, po}); - } - messageDamper.write(sw, po, cntx); - } catch (IOException e) { - log.error("Failure writing PacketOut switch={} packet-in={} packet-out={}", - new Object[] {sw, pi, po}, e); - } - - return; - } - - // IFloodlightModule methods - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - // We don't export any services - return null; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - // We don't have any services - return null; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IOFSwitchService.class); - l.add(IDeviceService.class); - l.add(IRoutingService.class); - l.add(ITopologyService.class); - l.add(ICounterStoreService.class); - return l; - } - - @Override - @LogMessageDocs({ - @LogMessageDoc(level="WARN", - message="Error parsing flow idle timeout, " + - "using default of {number} seconds", - explanation="The properties file contains an invalid " + - "flow idle timeout", - recommendation="Correct the idle timeout in the " + - "properties file."), - @LogMessageDoc(level="WARN", - message="Error parsing flow hard timeout, " + - "using default of {number} seconds", - explanation="The properties file contains an invalid " + - "flow hard timeout", - recommendation="Correct the hard timeout in the " + - "properties file.") - }) - public void init(FloodlightModuleContext context) throws FloodlightModuleException { - super.init(); - this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); - this.switchService = context.getServiceImpl(IOFSwitchService.class); - this.deviceManager = context.getServiceImpl(IDeviceService.class); - this.routingEngine = context.getServiceImpl(IRoutingService.class); - this.topology = context.getServiceImpl(ITopologyService.class); - this.counterStore = context.getServiceImpl(ICounterStoreService.class); - } - - @Override - public void startUp(FloodlightModuleContext context) { - super.startUp(); - } -} diff --git a/src/main/java/net/floodlightcontroller/hub/Hub.java b/src/main/java/net/floodlightcontroller/hub/Hub.java index e683fa917443d2c7abe24a3b331f13ecbce0fbfb..5de64574dfda5b7391a9d84992578642d39bcd4e 100644 --- a/src/main/java/net/floodlightcontroller/hub/Hub.java +++ b/src/main/java/net/floodlightcontroller/hub/Hub.java @@ -26,18 +26,20 @@ import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.LogicalOFMessageCategory; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; +import org.projectfloodlight.openflow.protocol.OFFactories; import org.projectfloodlight.openflow.protocol.OFMessage; import org.projectfloodlight.openflow.protocol.OFPacketIn; import org.projectfloodlight.openflow.protocol.OFPacketOut; import org.projectfloodlight.openflow.protocol.OFType; +import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.match.MatchField; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import org.slf4j.Logger; @@ -64,24 +66,22 @@ public class Hub implements IFloodlightModule, IOFMessageListener { return Hub.class.getPackage().getName(); } - //TODO @Ryan this is a good example (my first try) at using the builders. Might be good reference later. public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { OFPacketIn pi = (OFPacketIn) msg; - OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut(); - pob.setBufferId(pi.getBufferId()).setInPort(pi.getInPort()); + OFPacketOut.Builder pob = /*sw.getOFFactory()*/OFFactories.getFactory(OFVersion.OF_13).buildPacketOut(); + pob.setBufferId(pi.getBufferId()).setXid(pi.getXid()).setInPort(pi.getMatch().get(MatchField.IN_PORT)); // set actions - OFActionOutput.Builder actionBuilder = sw.getOFFactory().actions().buildOutput(); - actionBuilder.setPort(OFPort.FLOOD); + OFActionOutput.Builder actionBuilder = /*sw.getOFFactory()*/OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput(); + actionBuilder.setPort(OFPort.FLOOD); pob.setActions(Collections.singletonList((OFAction) actionBuilder.build())); - // pob.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); @Ryan setting of lengths is taken care of now, I think // set data if is is included in the packetin if (pi.getBufferId() == OFBufferId.NO_BUFFER) { byte[] packetData = pi.getData(); pob.setData(packetData); } - sw.write(pob.build(), LogicalOFMessageCategory.MAIN); + sw.write(pob.build()); return Command.CONTINUE; } diff --git a/src/main/java/net/floodlightcontroller/jython/JythonDebugInterface.java b/src/main/java/net/floodlightcontroller/jython/JythonDebugInterface.java deleted file mode 100644 index f76e3db5e594a75e30587a0db1430b2f16f7b570..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/jython/JythonDebugInterface.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.jython; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.internal.FloodlightProvider; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; - -public class JythonDebugInterface implements IFloodlightModule { - protected static Logger log = LoggerFactory.getLogger(JythonDebugInterface.class); - protected JythonServer debug_server; - protected String jythonHost = null; - protected int jythonPort = 6655; - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - // We don't export services - return null; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - // We don't export services - return null; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - // We don't have any dependencies - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - // no-op - } - - @Override - public void startUp(FloodlightModuleContext context) { - Map<String, Object> locals = new HashMap<String, Object>(); - // add all existing module references to the debug server - for (Class<? extends IFloodlightService> s : context.getAllServices()) { - // Put only the last part of the name - String[] bits = s.getCanonicalName().split("\\."); - String name = bits[bits.length-1]; - locals.put(name, context.getServiceImpl(s)); - } - - // read our config options - Map<String, String> configOptions = context.getConfigParams(this); - jythonHost = configOptions.get("host"); - if (jythonHost == null) { - Map<String, String> providerConfigOptions = context.getConfigParams( - FloodlightProvider.class); - jythonHost = providerConfigOptions.get("openflowhost"); - } - if (jythonHost != null) { - log.debug("Jython host set to {}", jythonHost); - } - String port = configOptions.get("port"); - if (port != null) { - jythonPort = Integer.parseInt(port); - } - log.debug("Jython port set to {}", jythonPort); - - JythonServer debug_server = new JythonServer(jythonHost, jythonPort, locals); - debug_server.start(); - } -} diff --git a/src/main/java/net/floodlightcontroller/jython/JythonServer.java b/src/main/java/net/floodlightcontroller/jython/JythonServer.java deleted file mode 100644 index 2eb28e817c44de4e0d7a15b07375252e002c8c03..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/jython/JythonServer.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.jython; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import org.python.util.PythonInterpreter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class starts a thread that runs a jython interpreter that - * can be used for debug (or even development). - * - * @author mandeepdhami - * - */ -public class JythonServer extends Thread { - protected static Logger log = LoggerFactory.getLogger(JythonServer.class); - - String host; - int port; - Map<String, Object> locals; - - /** - * @param host_ Host to use for jython server - * @param port_ Port to use for jython server - * @param locals_ Locals to add to the interpreters top level name space - */ - public JythonServer(String host_, int port_, Map<String, Object> locals_) { - this.host = host_; - this.port = port_; - this.locals = locals_; - if (this.locals == null) { - this.locals = new HashMap<String, Object>(); - } - this.locals.put("log", JythonServer.log); - this.setName("debugserver"); - } - - /** - * The main thread for this class invoked by Thread.run() - * - * @see java.lang.Thread#run() - */ - public void run() { - PythonInterpreter p = new PythonInterpreter(); - for (String name : this.locals.keySet()) { - p.set(name, this.locals.get(name)); - } - - URL jarUrl = JythonServer.class.getProtectionDomain().getCodeSource().getLocation(); - String jarPath = jarUrl.getPath(); - if (jarUrl.getProtocol().equals("file")) { - // If URL is of type file, assume that we are in dev env and set path to python dir. - // else use the jar file as is - jarPath = jarPath + "../../src/main/python/"; - } - - p.exec("import sys"); - p.exec("sys.path.append('" + jarPath + "')"); - p.exec("from debugserver import run_server"); - if (this.host == null) { - p.exec("run_server(port=" + this.port + ", locals=locals())"); - } else { - p.exec("run_server(port=" + this.port + ", host='" + this.host + "', locals=locals())"); - } - } -} diff --git a/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java b/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java deleted file mode 100644 index 92352e93d60a5cfbe063e09c98af66902a9e190d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.learningswitch; - -import java.util.Map; - -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.types.MacVlanPair; - -public interface ILearningSwitchService extends IFloodlightService { - /** - * Returns the LearningSwitch's learned host table - * @return The learned host table - */ - public Map<IOFSwitch, Map<MacVlanPair,Short>> getTable(); -} diff --git a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java deleted file mode 100644 index 2e8ce6f1baf678771543273e80e0f3dad0277054..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java +++ /dev/null @@ -1,624 +0,0 @@ -/** -* 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. -**/ - -/** - * Floodlight - * A BSD licensed, Java based OpenFlow controller - * - * Floodlight is a Java based OpenFlow controller originally written by David Erickson at Stanford - * University. It is available under the BSD license. - * - * For documentation, forums, issue tracking and more visit: - * - * http://www.openflowhub.org/display/Floodlight/Floodlight+Home - **/ - -package net.floodlightcontroller.learningswitch; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.types.MacVlanPair; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.restserver.IRestApiService; - -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFFlowRemoved; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.util.HexString; -import org.openflow.util.LRULinkedHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LearningSwitch - implements IFloodlightModule, ILearningSwitchService, IOFMessageListener { - protected static Logger log = LoggerFactory.getLogger(LearningSwitch.class); - - // Module dependencies - protected IFloodlightProviderService floodlightProvider; - protected ICounterStoreService counterStore; - protected IRestApiService restApi; - - // Stores the learned state for each switch - protected Map<IOFSwitch, Map<MacVlanPair,Short>> macVlanToSwitchPortMap; - - // flow-mod - for use in the cookie - public static final int LEARNING_SWITCH_APP_ID = 1; - // LOOK! This should probably go in some class that encapsulates - // the app cookie management - public static final int APP_ID_BITS = 12; - public static final int APP_ID_SHIFT = (64 - APP_ID_BITS); - public static final long LEARNING_SWITCH_COOKIE = (long) (LEARNING_SWITCH_APP_ID & ((1 << APP_ID_BITS) - 1)) << APP_ID_SHIFT; - - // more flow-mod defaults - protected static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds - protected static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite - protected static short FLOWMOD_PRIORITY = 100; - - // for managing our map sizes - protected static final int MAX_MACS_PER_SWITCH = 1000; - - // normally, setup reverse flow as well. Disable only for using cbench for comparison with NOX etc. - protected static final boolean LEARNING_SWITCH_REVERSE_FLOW = true; - - /** - * @param floodlightProvider the floodlightProvider to set - */ - public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) { - this.floodlightProvider = floodlightProvider; - } - - @Override - public String getName() { - return "learningswitch"; - } - - /** - * Adds a host to the MAC/VLAN->SwitchPort mapping - * @param sw The switch to add the mapping to - * @param mac The MAC address of the host to add - * @param vlan The VLAN that the host is on - * @param portVal The switchport that the host is on - */ - protected void addToPortMap(IOFSwitch sw, long mac, short vlan, short portVal) { - Map<MacVlanPair,Short> swMap = macVlanToSwitchPortMap.get(sw); - - if (vlan == (short) 0xffff) { - // OFMatch.loadFromPacket sets VLAN ID to 0xffff if the packet contains no VLAN tag; - // for our purposes that is equivalent to the default VLAN ID 0 - vlan = 0; - } - - if (swMap == null) { - // May be accessed by REST API so we need to make it thread safe - swMap = Collections.synchronizedMap(new LRULinkedHashMap<MacVlanPair,Short>(MAX_MACS_PER_SWITCH)); - macVlanToSwitchPortMap.put(sw, swMap); - } - swMap.put(new MacVlanPair(mac, vlan), portVal); - } - - /** - * Removes a host from the MAC/VLAN->SwitchPort mapping - * @param sw The switch to remove the mapping from - * @param mac The MAC address of the host to remove - * @param vlan The VLAN that the host is on - */ - protected void removeFromPortMap(IOFSwitch sw, long mac, short vlan) { - if (vlan == (short) 0xffff) { - vlan = 0; - } - Map<MacVlanPair,Short> swMap = macVlanToSwitchPortMap.get(sw); - if (swMap != null) - swMap.remove(new MacVlanPair(mac, vlan)); - } - - /** - * Get the port that a MAC/VLAN pair is associated with - * @param sw The switch to get the mapping from - * @param mac The MAC address to get - * @param vlan The VLAN number to get - * @return The port the host is on - */ - public Short getFromPortMap(IOFSwitch sw, long mac, short vlan) { - if (vlan == (short) 0xffff) { - vlan = 0; - } - Map<MacVlanPair,Short> swMap = macVlanToSwitchPortMap.get(sw); - if (swMap != null) - return swMap.get(new MacVlanPair(mac, vlan)); - - // if none found - return null; - } - - /** - * Clears the MAC/VLAN -> SwitchPort map for all switches - */ - public void clearLearnedTable() { - macVlanToSwitchPortMap.clear(); - } - - /** - * Clears the MAC/VLAN -> SwitchPort map for a single switch - * @param sw The switch to clear the mapping for - */ - public void clearLearnedTable(IOFSwitch sw) { - Map<MacVlanPair, Short> swMap = macVlanToSwitchPortMap.get(sw); - if (swMap != null) - swMap.clear(); - } - - @Override - public synchronized Map<IOFSwitch, Map<MacVlanPair,Short>> getTable() { - return macVlanToSwitchPortMap; - } - - /** - * Writes a OFFlowMod to a switch. - * @param sw The switch tow rite the flowmod to. - * @param command The FlowMod actions (add, delete, etc). - * @param bufferId The buffer ID if the switch has buffered the packet. - * @param match The OFMatch structure to write. - * @param outPort The switch port to output it to. - */ - private void writeFlowMod(IOFSwitch sw, short command, int bufferId, - OFMatch match, short outPort) { - // from openflow 1.0 spec - need to set these on a struct ofp_flow_mod: - // struct ofp_flow_mod { - // struct ofp_header header; - // struct ofp_match match; /* Fields to match */ - // uint64_t cookie; /* Opaque controller-issued identifier. */ - // - // /* Flow actions. */ - // uint16_t command; /* One of OFPFC_*. */ - // uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - // uint16_t hard_timeout; /* Max time before discarding (seconds). */ - // uint16_t priority; /* Priority level of flow entry. */ - // uint32_t buffer_id; /* Buffered packet to apply to (or -1). - // Not meaningful for OFPFC_DELETE*. */ - // uint16_t out_port; /* For OFPFC_DELETE* commands, require - // matching entries to include this as an - // output port. A value of OFPP_NONE - // indicates no restriction. */ - // uint16_t flags; /* One of OFPFF_*. */ - // struct ofp_action_header actions[0]; /* The action length is inferred - // from the length field in the - // header. */ - // }; - - OFFlowMod flowMod = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); - flowMod.setMatch(match); - flowMod.setCookie(LearningSwitch.LEARNING_SWITCH_COOKIE); - flowMod.setCommand(command); - flowMod.setIdleTimeout(LearningSwitch.FLOWMOD_DEFAULT_IDLE_TIMEOUT); - flowMod.setHardTimeout(LearningSwitch.FLOWMOD_DEFAULT_HARD_TIMEOUT); - flowMod.setPriority(LearningSwitch.FLOWMOD_PRIORITY); - flowMod.setBufferId(bufferId); - flowMod.setOutPort((command == OFFlowMod.OFPFC_DELETE) ? outPort : OFPort.OFPP_NONE.getValue()); - flowMod.setFlags((command == OFFlowMod.OFPFC_DELETE) ? 0 : (short) (1 << 0)); // OFPFF_SEND_FLOW_REM - - // set the ofp_action_header/out actions: - // from the openflow 1.0 spec: need to set these on a struct ofp_action_output: - // uint16_t type; /* OFPAT_OUTPUT. */ - // uint16_t len; /* Length is 8. */ - // uint16_t port; /* Output port. */ - // uint16_t max_len; /* Max length to send to controller. */ - // type/len are set because it is OFActionOutput, - // and port, max_len are arguments to this constructor - flowMod.setActions(Arrays.asList((OFAction) new OFActionOutput(outPort, (short) 0xffff))); - flowMod.setLength((short) (OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH)); - - if (log.isTraceEnabled()) { - log.trace("{} {} flow mod {}", - new Object[]{ sw, (command == OFFlowMod.OFPFC_DELETE) ? "deleting" : "adding", flowMod }); - } - - counterStore.updatePktOutFMCounterStoreLocal(sw, flowMod); - - // and write it out - try { - sw.write(flowMod, null); - } catch (IOException e) { - log.error("Failed to write {} to switch {}", new Object[]{ flowMod, sw }, e); - } - } - - /** - * Pushes a packet-out to a switch. The assumption here is that - * the packet-in was also generated from the same switch. Thus, if the input - * port of the packet-in and the outport are the same, the function will not - * push the packet-out. - * @param sw switch that generated the packet-in, and from which packet-out is sent - * @param match OFmatch - * @param pi packet-in - * @param outport output port - */ - private void pushPacket(IOFSwitch sw, OFMatch match, OFPacketIn pi, short outport) { - if (pi == null) { - return; - } - - // The assumption here is (sw) is the switch that generated the - // packet-in. If the input port is the same as output port, then - // the packet-out should be ignored. - if (pi.getInPort() == outport) { - if (log.isDebugEnabled()) { - log.debug("Attempting to do packet-out to the same " + - "interface as packet-in. Dropping packet. " + - " SrcSwitch={}, match = {}, pi={}", - new Object[]{sw, match, pi}); - return; - } - } - - if (log.isTraceEnabled()) { - log.trace("PacketOut srcSwitch={} match={} pi={}", - new Object[] {sw, match, pi}); - } - - OFPacketOut po = - (OFPacketOut) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.PACKET_OUT); - - // set actions - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(new OFActionOutput(outport, (short) 0xffff)); - - po.setActions(actions) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); - short poLength = - (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); - - // If the switch doens't support buffering set the buffer id to be none - // otherwise it'll be the the buffer id of the PacketIn - if (sw.getBuffers() == 0) { - // We set the PI buffer id here so we don't have to check again below - pi.setBufferId(OFPacketOut.BUFFER_ID_NONE); - po.setBufferId(OFPacketOut.BUFFER_ID_NONE); - } else { - po.setBufferId(pi.getBufferId()); - } - - po.setInPort(pi.getInPort()); - - // If the buffer id is none or the switch doesn's support buffering - // we send the data with the packet out - if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { - byte[] packetData = pi.getPacketData(); - poLength += packetData.length; - po.setPacketData(packetData); - } - - po.setLength(poLength); - - try { - counterStore.updatePktOutFMCounterStoreLocal(sw, po); - sw.write(po, null); - } catch (IOException e) { - log.error("Failure writing packet out", e); - } - } - - /** - * Writes an OFPacketOut message to a switch. - * @param sw The switch to write the PacketOut to. - * @param packetInMessage The corresponding PacketIn. - * @param egressPort The switchport to output the PacketOut. - */ - private void writePacketOutForPacketIn(IOFSwitch sw, - OFPacketIn packetInMessage, - short egressPort) { - // from openflow 1.0 spec - need to set these on a struct ofp_packet_out: - // uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ - // uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ - // uint16_t actions_len; /* Size of action array in bytes. */ - // struct ofp_action_header actions[0]; /* Actions. */ - /* uint8_t data[0]; */ /* Packet data. The length is inferred - from the length field in the header. - (Only meaningful if buffer_id == -1.) */ - - OFPacketOut packetOutMessage = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); - short packetOutLength = (short)OFPacketOut.MINIMUM_LENGTH; // starting length - - // Set buffer_id, in_port, actions_len - packetOutMessage.setBufferId(packetInMessage.getBufferId()); - packetOutMessage.setInPort(packetInMessage.getInPort()); - packetOutMessage.setActionsLength((short)OFActionOutput.MINIMUM_LENGTH); - packetOutLength += OFActionOutput.MINIMUM_LENGTH; - - // set actions - List<OFAction> actions = new ArrayList<OFAction>(1); - actions.add(new OFActionOutput(egressPort, (short) 0)); - packetOutMessage.setActions(actions); - - // set data - only if buffer_id == -1 - if (packetInMessage.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { - byte[] packetData = packetInMessage.getPacketData(); - packetOutMessage.setPacketData(packetData); - packetOutLength += (short)packetData.length; - } - - // finally, set the total length - packetOutMessage.setLength(packetOutLength); - - // and write it out - try { - counterStore.updatePktOutFMCounterStoreLocal(sw, packetOutMessage); - sw.write(packetOutMessage, null); - } catch (IOException e) { - log.error("Failed to write {} to switch {}: {}", new Object[]{ packetOutMessage, sw, e }); - } - } - - /** - * Processes a OFPacketIn message. If the switch has learned the MAC/VLAN to port mapping - * for the pair it will write a FlowMod for. If the mapping has not been learned the - * we will flood the packet. - * @param sw - * @param pi - * @param cntx - * @return - */ - private Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { - // Read in packet data headers by using OFMatch - OFMatch match = new OFMatch(); - match.loadFromPacket(pi.getPacketData(), pi.getInPort()); - Long sourceMac = Ethernet.toLong(match.getDataLayerSource()); - Long destMac = Ethernet.toLong(match.getDataLayerDestination()); - Short vlan = match.getDataLayerVirtualLan(); - if ((destMac & 0xfffffffffff0L) == 0x0180c2000000L) { - if (log.isTraceEnabled()) { - log.trace("ignoring packet addressed to 802.1D/Q reserved addr: switch {} vlan {} dest MAC {}", - new Object[]{ sw, vlan, HexString.toHexString(destMac) }); - } - return Command.STOP; - } - if ((sourceMac & 0x010000000000L) == 0) { - // If source MAC is a unicast address, learn the port for this MAC/VLAN - this.addToPortMap(sw, sourceMac, vlan, pi.getInPort()); - } - - // Now output flow-mod and/or packet - Short outPort = getFromPortMap(sw, destMac, vlan); - if (outPort == null) { - // If we haven't learned the port for the dest MAC/VLAN, flood it - // Don't flood broadcast packets if the broadcast is disabled. - // XXX For LearningSwitch this doesn't do much. The sourceMac is removed - // from port map whenever a flow expires, so you would still see - // a lot of floods. - this.writePacketOutForPacketIn(sw, pi, OFPort.OFPP_FLOOD.getValue()); - } else if (outPort == match.getInputPort()) { - log.trace("ignoring packet that arrived on same port as learned destination:" - + " switch {} vlan {} dest MAC {} port {}", - new Object[]{ sw, vlan, HexString.toHexString(destMac), outPort }); - } else { - // Add flow table entry matching source MAC, dest MAC, VLAN and input port - // that sends to the port we previously learned for the dest MAC/VLAN. Also - // add a flow table entry with source and destination MACs reversed, and - // input and output ports reversed. When either entry expires due to idle - // timeout, remove the other one. This ensures that if a device moves to - // a different port, a constant stream of packets headed to the device at - // its former location does not keep the stale entry alive forever. - // FIXME: current HP switches ignore DL_SRC and DL_DST fields, so we have to match on - // NW_SRC and NW_DST as well - match.setWildcards(((Integer)sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue() - & ~OFMatch.OFPFW_IN_PORT - & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST - & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK); - // We write FlowMods with Buffer ID none then explicitly PacketOut the buffered packet - this.pushPacket(sw, match, pi, outPort); - this.writeFlowMod(sw, OFFlowMod.OFPFC_ADD, OFPacketOut.BUFFER_ID_NONE, match, outPort); - if (LEARNING_SWITCH_REVERSE_FLOW) { - this.writeFlowMod(sw, OFFlowMod.OFPFC_ADD, -1, match.clone() - .setDataLayerSource(match.getDataLayerDestination()) - .setDataLayerDestination(match.getDataLayerSource()) - .setNetworkSource(match.getNetworkDestination()) - .setNetworkDestination(match.getNetworkSource()) - .setTransportSource(match.getTransportDestination()) - .setTransportDestination(match.getTransportSource()) - .setInputPort(outPort), - match.getInputPort()); - } - } - return Command.CONTINUE; - } - - /** - * Processes a flow removed message. We will delete the learned MAC/VLAN mapping from - * the switch's table. - * @param sw The switch that sent the flow removed message. - * @param flowRemovedMessage The flow removed message. - * @return Whether to continue processing this message or stop. - */ - private Command processFlowRemovedMessage(IOFSwitch sw, OFFlowRemoved flowRemovedMessage) { - if (flowRemovedMessage.getCookie() != LearningSwitch.LEARNING_SWITCH_COOKIE) { - return Command.CONTINUE; - } - if (log.isTraceEnabled()) { - log.trace("{} flow entry removed {}", sw, flowRemovedMessage); - } - OFMatch match = flowRemovedMessage.getMatch(); - // When a flow entry expires, it means the device with the matching source - // MAC address and VLAN either stopped sending packets or moved to a different - // port. If the device moved, we can't know where it went until it sends - // another packet, allowing us to re-learn its port. Meanwhile we remove - // it from the macVlanToPortMap to revert to flooding packets to this device. - this.removeFromPortMap(sw, Ethernet.toLong(match.getDataLayerSource()), - match.getDataLayerVirtualLan()); - - // Also, if packets keep coming from another device (e.g. from ping), the - // corresponding reverse flow entry will never expire on its own and will - // send the packets to the wrong port (the matching input port of the - // expired flow entry), so we must delete the reverse entry explicitly. - this.writeFlowMod(sw, OFFlowMod.OFPFC_DELETE, -1, match.clone() - .setWildcards(((Integer)sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue() - & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST - & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK) - .setDataLayerSource(match.getDataLayerDestination()) - .setDataLayerDestination(match.getDataLayerSource()) - .setNetworkSource(match.getNetworkDestination()) - .setNetworkDestination(match.getNetworkSource()) - .setTransportSource(match.getTransportDestination()) - .setTransportDestination(match.getTransportSource()), - match.getInputPort()); - return Command.CONTINUE; - } - - // IOFMessageListener - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx); - case FLOW_REMOVED: - return this.processFlowRemovedMessage(sw, (OFFlowRemoved) msg); - case ERROR: - log.info("received an error {} from switch {}", msg, sw); - return Command.CONTINUE; - default: - break; - } - log.error("received an unexpected message {} from switch {}", msg, sw); - return Command.CONTINUE; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return false; - } - - // IFloodlightModule - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(ILearningSwitchService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(ILearningSwitchService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(ICounterStoreService.class); - l.add(IRestApiService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - macVlanToSwitchPortMap = - new ConcurrentHashMap<IOFSwitch, Map<MacVlanPair,Short>>(); - floodlightProvider = - context.getServiceImpl(IFloodlightProviderService.class); - counterStore = - context.getServiceImpl(ICounterStoreService.class); - restApi = - context.getServiceImpl(IRestApiService.class); - } - - @Override - public void startUp(FloodlightModuleContext context) { - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this); - floodlightProvider.addOFMessageListener(OFType.ERROR, this); - restApi.addRestletRoutable(new LearningSwitchWebRoutable()); - - // read our config options - Map<String, String> configOptions = context.getConfigParams(this); - try { - String idleTimeout = configOptions.get("idletimeout"); - if (idleTimeout != null) { - FLOWMOD_DEFAULT_IDLE_TIMEOUT = Short.parseShort(idleTimeout); - } - } catch (NumberFormatException e) { - log.warn("Error parsing flow idle timeout, " + - "using default of {} seconds", - FLOWMOD_DEFAULT_IDLE_TIMEOUT); - } - try { - String hardTimeout = configOptions.get("hardtimeout"); - if (hardTimeout != null) { - FLOWMOD_DEFAULT_HARD_TIMEOUT = Short.parseShort(hardTimeout); - } - } catch (NumberFormatException e) { - log.warn("Error parsing flow hard timeout, " + - "using default of {} seconds", - FLOWMOD_DEFAULT_HARD_TIMEOUT); - } - try { - String priority = configOptions.get("priority"); - if (priority != null) { - FLOWMOD_PRIORITY = Short.parseShort(priority); - } - } catch (NumberFormatException e) { - log.warn("Error parsing flow priority, " + - "using default of {}", - FLOWMOD_PRIORITY); - } - log.debug("FlowMod idle timeout set to {} seconds", - FLOWMOD_DEFAULT_IDLE_TIMEOUT); - log.debug("FlowMod hard timeout set to {} seconds", - FLOWMOD_DEFAULT_HARD_TIMEOUT); - log.debug("FlowMod priority set to {}", - FLOWMOD_PRIORITY); - } -} diff --git a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java deleted file mode 100644 index 2eb1b914f1bc501a449d954733317d229463114e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.learningswitch; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.types.MacVlanPair; - -import org.openflow.util.HexString; -import org.restlet.data.Status; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LearningSwitchTable extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(LearningSwitchTable.class); - - protected Map<String, Object> formatTableEntry(MacVlanPair key, short port) { - Map<String, Object> entry = new HashMap<String, Object>(); - entry.put("mac", HexString.toHexString(key.mac)); - entry.put("vlan", key.vlan); - entry.put("port", port); - return entry; - } - - protected List<Map<String, Object>> getOneSwitchTable(Map<MacVlanPair, Short> switchMap) { - List<Map<String, Object>> switchTable = new ArrayList<Map<String, Object>>(); - for (Entry<MacVlanPair, Short> entry : switchMap.entrySet()) { - switchTable.add(formatTableEntry(entry.getKey(), entry.getValue())); - } - return switchTable; - } - - @Get("json") - public Map<String, List<Map<String, Object>>> getSwitchTableJson() { - ILearningSwitchService lsp = - (ILearningSwitchService)getContext().getAttributes(). - get(ILearningSwitchService.class.getCanonicalName()); - - Map<IOFSwitch, Map<MacVlanPair,Short>> table = lsp.getTable(); - Map<String, List<Map<String, Object>>> allSwitchTableJson = new HashMap<String, List<Map<String, Object>>>(); - - String switchId = (String) getRequestAttributes().get("switch"); - if (switchId.toLowerCase().equals("all")) { - for (IOFSwitch sw : table.keySet()) { - allSwitchTableJson.put(HexString.toHexString(sw.getId()), getOneSwitchTable(table.get(sw))); - } - } else { - try { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); - long dpid = HexString.toLong(switchId); - IOFSwitch sw = floodlightProvider.getSwitch(dpid); - allSwitchTableJson.put(HexString.toHexString(sw.getId()), getOneSwitchTable(table.get(sw))); - } catch (NumberFormatException e) { - log.error("Could not decode switch ID = " + switchId); - setStatus(Status.CLIENT_ERROR_BAD_REQUEST); - } - } - - return allSwitchTableJson; - } -} diff --git a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchWebRoutable.java b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchWebRoutable.java deleted file mode 100644 index bab2e59cb8fbd0b6e158574df370e621d53988e8..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchWebRoutable.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.learningswitch; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -import net.floodlightcontroller.restserver.RestletRoutable; - -public class LearningSwitchWebRoutable implements RestletRoutable { - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/table/{switch}/json", LearningSwitchTable.class); - return router; - } - - @Override - public String basePath() { - return "/wm/learningswitch"; - } -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java deleted file mode 100644 index 5025d8d6981d8c5002477a0c754de4932fb0232a..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java +++ /dev/null @@ -1,197 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -public interface ILinkDiscovery { - - @JsonSerialize(using=ToStringSerializer.class) - public enum UpdateOperation { - LINK_UPDATED("Link Updated"), - LINK_REMOVED("Link Removed"), - SWITCH_UPDATED("Switch Updated"), - SWITCH_REMOVED("Switch Removed"), - PORT_UP("Port Up"), - PORT_DOWN("Port Down"), - TUNNEL_PORT_ADDED("Tunnel Port Added"), - TUNNEL_PORT_REMOVED("Tunnel Port Removed"); - - private String value; - UpdateOperation(String v) { - value = v; - } - - @Override - public String toString() { - return value; - } - } - - public class LDUpdate { - protected DatapathId src; - protected OFPort srcPort; - protected DatapathId dst; - protected OFPort dstPort; - protected SwitchType srcType; - protected LinkType type; - protected UpdateOperation operation; - - public LDUpdate(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort, - ILinkDiscovery.LinkType type, - UpdateOperation operation) { - this.src = src; - this.srcPort = srcPort; - this.dst = dst; - this.dstPort = dstPort; - this.type = type; - this.operation = operation; - } - - public LDUpdate(LDUpdate old) { - this.src = old.src; - this.srcPort = old.srcPort; - this.dst = old.dst; - this.dstPort = old.dstPort; - this.srcType = old.srcType; - this.type = old.type; - this.operation = old.operation; - } - - // For updtedSwitch(sw) - public LDUpdate(DatapathId switchId, SwitchType stype, UpdateOperation oper ){ - this.operation = oper; - this.src = switchId; - this.srcType = stype; - } - - // For port up or port down; and tunnel port added and removed. - public LDUpdate(DatapathId sw, OFPort port, UpdateOperation operation) { - this.src = sw; - this.srcPort = port; - this.operation = operation; - } - - public DatapathId getSrc() { - return src; - } - - public OFPort getSrcPort() { - return srcPort; - } - - public DatapathId getDst() { - return dst; - } - - public OFPort getDstPort() { - return dstPort; - } - - public SwitchType getSrcType() { - return srcType; - } - - public LinkType getType() { - return type; - } - - public UpdateOperation getOperation() { - return operation; - } - - public void setOperation(UpdateOperation operation) { - this.operation = operation; - } - - @Override - public String toString() { - switch (operation) { - case LINK_REMOVED: - case LINK_UPDATED: - return "LDUpdate [operation=" + operation + - ", src=" + src.toString() - + ", srcPort=" + srcPort.toString() - + ", dst=" + dst.toString() - + ", dstPort=" + dstPort.toString() - + ", type=" + type + "]"; - case PORT_DOWN: - case PORT_UP: - return "LDUpdate [operation=" + operation + - ", src=" + src.toString() - + ", srcPort=" + srcPort.toString() + "]"; - case SWITCH_REMOVED: - case SWITCH_UPDATED: - return "LDUpdate [operation=" + operation + - ", src=" + src.toString() + "]"; - default: - return "LDUpdate: Unknown update."; - } - } - } - - public enum SwitchType { - BASIC_SWITCH, CORE_SWITCH - }; - - public enum LinkType { - INVALID_LINK { - @Override - public String toString() { - return "invalid"; - } - }, - DIRECT_LINK{ - @Override - public String toString() { - return "internal"; - } - }, - MULTIHOP_LINK { - @Override - public String toString() { - return "external"; - } - }, - TUNNEL { - @Override - public String toString() { - return "tunnel"; - } - } - }; - - public enum LinkDirection { - UNIDIRECTIONAL { - @Override - public String toString() { - return "unidirectional"; - } - }, - BIDIRECTIONAL { - @Override - public String toString() { - return "bidirectional"; - } - } - } -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryListener.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryListener.java deleted file mode 100644 index d0e895600d36bb25f605a1e4eba4d0876fae26f0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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.linkdiscovery; - -import java.util.List; - -public interface ILinkDiscoveryListener extends ILinkDiscovery{ - - public void linkDiscoveryUpdate(LDUpdate update); - - public void linkDiscoveryUpdate(List<LDUpdate> updateList); -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java deleted file mode 100644 index 2bb53727917ffba3b4138bf3d06a9e56b79db1f2..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java +++ /dev/null @@ -1,133 +0,0 @@ -/** -* 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.linkdiscovery; - -import java.util.Map; -import java.util.Set; - -import org.projectfloodlight.openflow.protocol.OFPacketOut; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.MacAddress; -import org.projectfloodlight.openflow.types.OFPort; - -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.topology.NodePortTuple; - - -public interface ILinkDiscoveryService extends IFloodlightService { - - /** - * Returns if a given switchport is a tunnel endpoint or not - */ - public boolean isTunnelPort(DatapathId sw, OFPort port); - - /** - * Retrieves a map of all known link connections between OpenFlow switches - * and the associated info (valid time, port states) for the link. - */ - public Map<Link, LinkInfo> getLinks(); - - /** - * Retrieves the link info for a given link - * @param link link for which the link info should be returned - * @return the link info for the given link - */ - public LinkInfo getLinkInfo(Link link); - - /** - * Returns link type of a given link - * @param info - * @return - */ - public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info); - - /** - * Returns OFPacketOut which contains the LLDP data corresponding - * to switchport (sw, port). PacketOut does not contain actions. - * PacketOut length includes the minimum length and data length. - */ - public OFPacketOut generateLLDPMessage(DatapathId sw, OFPort port, - boolean isStandard, - boolean isReverse); - - /** - * Returns an unmodifiable map from switch id to a set of all links with it - * as an endpoint. - */ - public Map<DatapathId, Set<Link>> getSwitchLinks(); - - /** - * Adds a listener to listen for ILinkDiscoveryService messages - * @param listener The listener that wants the notifications - */ - public void addListener(ILinkDiscoveryListener listener); - - /** - * Retrieves a set of all switch ports on which lldps are suppressed. - */ - public Set<NodePortTuple> getSuppressLLDPsInfo(); - - /** - * Adds a switch port to suppress lldp set. LLDPs and BDDPs will not be sent - * out, and if any are received on this port then they will be dropped. - */ - public void AddToSuppressLLDPs(DatapathId sw, OFPort port); - - /** - * Removes a switch port from suppress lldp set - */ - public void RemoveFromSuppressLLDPs(DatapathId sw, OFPort port); - - /** - * Get the set of quarantined ports on a switch - */ - public Set<OFPort> getQuarantinedPorts(DatapathId sw); - - /** - * Get the status of auto port fast feature. - */ - public boolean isAutoPortFastFeature(); - - /** - * Set the state for auto port fast feature. - * @param autoPortFastFeature - */ - public void setAutoPortFastFeature(boolean autoPortFastFeature); - - /** - * Get the map of node-port tuples from link DB - */ - public Map<NodePortTuple, Set<Link>> getPortLinks(); - - /** - * addMACToIgnoreList is a service provided by LinkDiscovery to ignore - * certain packets early in the packet-in processing chain. Since LinkDiscovery - * is first in the packet-in processing pipeline, it can efficiently drop these - * packets. Currently these packets are identified only by their source MAC address. - * - * Add a MAC address range to ignore list. All packet ins from this range - * will be dropped - use with care! - * @param mac The base MAC address that is to be ignored - * @param ignoreBits The number of LSBs to ignore. A value of 0 will add - * only one MAC address 'mac' to ignore list. A value of 48 will add - * ALL MAC addresses to the ignore list. This will cause a drop of - * ALL packet ins. - */ - public void addMACToIgnoreList(MacAddress mac, int ignoreBits); -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java deleted file mode 100644 index 6c2d7334e436cabe3f44eca1547d4f1425c3d440..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java +++ /dev/null @@ -1,156 +0,0 @@ -/** -* 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.linkdiscovery; - -import java.util.Date; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public class LinkInfo { - - public LinkInfo(Date firstSeenTime, - Date lastLldpReceivedTime, - Date lastBddpReceivedTime) { - super(); - this.firstSeenTime = firstSeenTime; - this.lastLldpReceivedTime = lastLldpReceivedTime; - this.lastBddpReceivedTime = lastBddpReceivedTime; - } - - /* - * Do not use this constructor. Used primarily for JSON - * Serialization/Deserialization - */ - public LinkInfo() { - this.firstSeenTime = null; - this.lastLldpReceivedTime = null; - this.lastBddpReceivedTime = null; - } - - public LinkInfo(LinkInfo fromLinkInfo) { - this.firstSeenTime = fromLinkInfo.getFirstSeenTime(); - this.lastLldpReceivedTime = fromLinkInfo.getUnicastValidTime(); - this.lastBddpReceivedTime = fromLinkInfo.getMulticastValidTime(); - } - - protected Date firstSeenTime; - protected Date lastLldpReceivedTime; /* Standard LLLDP received time */ - protected Date lastBddpReceivedTime; /* Modified LLDP received time */ - - /** The port states stored here are topology's last knowledge of - * the state of the port. This mostly mirrors the state - * maintained in the port list in IOFSwitch (i.e. the one returned - * from getPort), except that during a port status message the - * IOFSwitch port state will already have been updated with the - * new port state, so topology needs to keep its own copy so that - * it can determine if the port state has changed and therefore - * requires the new state to be written to storage. - */ - - public Date getFirstSeenTime() { - return firstSeenTime; - } - - public void setFirstSeenTime(Date firstSeenTime) { - this.firstSeenTime = firstSeenTime; - } - - public Date getUnicastValidTime() { - return lastLldpReceivedTime; - } - - public void setUnicastValidTime(Date unicastValidTime) { - this.lastLldpReceivedTime = unicastValidTime; - } - - public Date getMulticastValidTime() { - return lastBddpReceivedTime; - } - - public void setMulticastValidTime(Date multicastValidTime) { - this.lastBddpReceivedTime = multicastValidTime; - } - - @JsonIgnore - public LinkType getLinkType() { - if (lastLldpReceivedTime != null) { - return LinkType.DIRECT_LINK; - } else if (lastBddpReceivedTime != null) { - return LinkType.MULTIHOP_LINK; - } - return LinkType.INVALID_LINK; - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5557; - int result = 1; - result = prime * result + ((firstSeenTime == null) ? 0 : firstSeenTime.hashCode()); - result = prime * result + ((lastLldpReceivedTime == null) ? 0 : lastLldpReceivedTime.hashCode()); - result = prime * result + ((lastBddpReceivedTime == null) ? 0 : lastBddpReceivedTime.hashCode()); - return result; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof LinkInfo)) - return false; - LinkInfo other = (LinkInfo) obj; - - if (firstSeenTime == null) { - if (other.firstSeenTime != null) - return false; - } else if (!firstSeenTime.equals(other.firstSeenTime)) - return false; - - if (lastLldpReceivedTime == null) { - if (other.lastLldpReceivedTime != null) - return false; - } else if (!lastLldpReceivedTime.equals(other.lastLldpReceivedTime)) - return false; - - if (lastBddpReceivedTime == null) { - if (other.lastBddpReceivedTime != null) - return false; - } else if (!lastBddpReceivedTime.equals(other.lastBddpReceivedTime)) - return false; - - return true; - } - - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime.getTime()) - + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime.getTime()) - + "]"; - } -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java deleted file mode 100644 index 2dbba0a30de9a7d558e26e79d6c216b388a4c455..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java +++ /dev/null @@ -1,2254 +0,0 @@ -/** - * 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.linkdiscovery.internal; - -import java.io.IOException; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.HAListenerTypeMarker; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; -import net.floodlightcontroller.core.IHAListener; -import net.floodlightcontroller.core.IInfoProvider; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IOFSwitchListener; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.annotations.LogMessageDocs; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.SingletonTask; -import net.floodlightcontroller.debugcounter.IDebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType; -import net.floodlightcontroller.debugcounter.NullDebugCounter; -import net.floodlightcontroller.debugevent.IDebugEventService; -import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; -import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType; -import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered; -import net.floodlightcontroller.debugevent.IEventUpdater; -import net.floodlightcontroller.debugevent.NullDebugEvent; -import net.floodlightcontroller.debugevent.IDebugEventService.EventType; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.SwitchType; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.UpdateOperation; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable; -import net.floodlightcontroller.notification.INotificationManager; -import net.floodlightcontroller.notification.NotificationManagerFactory; -import net.floodlightcontroller.packet.BSN; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.LLDP; -import net.floodlightcontroller.packet.LLDPTLV; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.storage.IResultSet; -import net.floodlightcontroller.storage.IStorageSourceListener; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.OperatorPredicate; -import net.floodlightcontroller.storage.StorageException; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.NodePortTuple; - -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPhysicalPort; -import org.openflow.protocol.OFPhysicalPort.OFPortState; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.util.HexString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class sends out LLDP messages containing the sending switch's datapath - * id as well as the outgoing port number. Received LLrescDP messages that match - * a known switch cause a new LinkTuple to be created according to the invariant - * rules listed below. This new LinkTuple is also passed to routing if it exists - * to trigger updates. This class also handles removing links that are - * associated to switch ports that go down, and switches that are disconnected. - * Invariants: -portLinks and switchLinks will not contain empty Sets outside of - * critical sections -portLinks contains LinkTuples where one of the src or dst - * SwitchPortTuple matches the map key -switchLinks contains LinkTuples where - * one of the src or dst SwitchPortTuple's id matches the switch id -Each - * LinkTuple will be indexed into switchLinks for both src.id and dst.id, and - * portLinks for each src and dst -The updates queue is only added to from - * within a held write lock - */ -@LogMessageCategory("Network Topology") -public class LinkDiscoveryManager implements IOFMessageListener, - IOFSwitchListener, IStorageSourceListener, ILinkDiscoveryService, - IFloodlightModule, IInfoProvider { - protected static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class); - protected static final INotificationManager notifier = - NotificationManagerFactory.getNotificationManager(LinkDiscoveryManager.class); - - public static final String MODULE_NAME = "linkdiscovery"; - - // Names of table/fields for links in the storage API - private static final String TOPOLOGY_TABLE_NAME = "controller_topologyconfig"; - private static final String TOPOLOGY_ID = "id"; - private static final String TOPOLOGY_AUTOPORTFAST = "autoportfast"; - - private static final String LINK_TABLE_NAME = "controller_link"; - private static final String LINK_ID = "id"; - private static final String LINK_SRC_SWITCH = "src_switch_id"; - private static final String LINK_SRC_PORT = "src_port"; - private static final String LINK_DST_SWITCH = "dst_switch_id"; - private static final String LINK_DST_PORT = "dst_port"; - private static final String LINK_VALID_TIME = "valid_time"; - private static final String LINK_TYPE = "link_type"; - private static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig"; - private static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch"; - - // Event updaters for debug events - protected IEventUpdater<DirectLinkEvent> evDirectLink; - - protected IFloodlightProviderService floodlightProvider; - protected IStorageSourceService storageSource; - protected IThreadPoolService threadPool; - protected IRestApiService restApi; - protected IDebugCounterService debugCounters; - protected IDebugEventService debugEvents; - - // Role - protected Role role; - - // LLDP and BDDP fields - private static final byte[] LLDP_STANDARD_DST_MAC_STRING = - HexString.fromHexString("01:80:c2:00:00:0e"); - private static final long LINK_LOCAL_MASK = 0xfffffffffff0L; - private static final long LINK_LOCAL_VALUE = 0x0180c2000000L; - protected static int EVENT_HISTORY_SIZE = 1024; // in seconds - - // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version - // private static final String LLDP_BSN_DST_MAC_STRING = - // "5d:16:c7:00:00:01"; - private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff"; - - // Direction TLVs are used to indicate if the LLDPs were sent - // periodically or in response to a recieved LLDP - private static final byte TLV_DIRECTION_TYPE = 0x73; - private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte - private static final byte TLV_DIRECTION_VALUE_FORWARD[] = { 0x01 }; - private static final byte TLV_DIRECTION_VALUE_REVERSE[] = { 0x02 }; - private static final LLDPTLV forwardTLV = new LLDPTLV().setType(TLV_DIRECTION_TYPE) - .setLength(TLV_DIRECTION_LENGTH) - .setValue(TLV_DIRECTION_VALUE_FORWARD); - - private static final LLDPTLV reverseTLV = new LLDPTLV().setType(TLV_DIRECTION_TYPE) - .setLength(TLV_DIRECTION_LENGTH) - .setValue(TLV_DIRECTION_VALUE_REVERSE); - - // Link discovery task details. - protected SingletonTask discoveryTask; - protected final int DISCOVERY_TASK_INTERVAL = 1; - protected final int LINK_TIMEOUT = 35; // timeout as part of LLDP process. - protected final int LLDP_TO_ALL_INTERVAL = 15; // 15 seconds. - protected long lldpClock = 0; - // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL. - // If we want to identify link failures faster, we could decrease this - // value to a small number, say 1 or 2 sec. - protected final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known - // links - - protected LLDPTLV controllerTLV; - protected ReentrantReadWriteLock lock; - int lldpTimeCount = 0; - - /** - * Flag to indicate if automatic port fast is enabled or not. Default is set - * to false -- Initialized in the init method as well. - */ - protected boolean AUTOPORTFAST_DEFAULT = false; - protected boolean autoPortFastFeature = AUTOPORTFAST_DEFAULT; - - /** - * Map from link to the most recent time it was verified functioning - */ - protected Map<Link, LinkInfo> links; - - /** - * Map from switch id to a set of all links with it as an endpoint - */ - protected Map<Long, Set<Link>> switchLinks; - - /** - * Map from a id:port to the set of links containing it as an endpoint - */ - protected Map<NodePortTuple, Set<Link>> portLinks; - - protected volatile boolean shuttingDown = false; - - /* - * topology aware components are called in the order they were added to the - * the array - */ - protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware; - protected BlockingQueue<LDUpdate> updates; - protected Thread updatesThread; - - /** - * List of ports through which LLDP/BDDPs are not sent. - */ - protected Set<NodePortTuple> suppressLinkDiscovery; - - /** - * A list of ports that are quarantined for discovering links through them. - * Data traffic from these ports are not allowed until the ports are - * released from quarantine. - */ - protected LinkedBlockingQueue<NodePortTuple> quarantineQueue; - protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue; - /** - * Quarantine task - */ - protected SingletonTask bddpTask; - protected final int BDDP_TASK_INTERVAL = 100; // 100 ms. - protected final int BDDP_TASK_SIZE = 10; // # of ports per iteration - - private class MACRange { - long baseMAC; - int ignoreBits; - } - protected Set<MACRange> ignoreMACSet; - - private IHAListener haListener; - - /** - * Debug Counters - */ - private IDebugCounter ctrQuarantineDrops; - private IDebugCounter ctrIgnoreSrcMacDrops; - private IDebugCounter ctrIncoming; - private IDebugCounter ctrLinkLocalDrops; - private IDebugCounter ctrLldpEol; - - private final String PACKAGE = LinkDiscoveryManager.class.getPackage().getName(); - - - //********************* - // ILinkDiscoveryService - //********************* - - @Override - public OFPacketOut generateLLDPMessage(long sw, short port, - boolean isStandard, boolean isReverse) { - - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - ImmutablePort ofpPort = iofSwitch.getPort(port); - - if (log.isTraceEnabled()) { - log.trace("Sending LLDP packet out of swich: {}, port: {}", - HexString.toHexString(sw), port); - } - - // using "nearest customer bridge" MAC address for broadest possible - // propagation - // through provider and TPMR bridges (see IEEE 802.1AB-2009 and - // 802.1Q-2011), - // in particular the Linux bridge which behaves mostly like a provider - // bridge - byte[] chassisId = new byte[] { 4, 0, 0, 0, 0, 0, 0 }; // filled in - // later - byte[] portId = new byte[] { 2, 0, 0 }; // filled in later - byte[] ttlValue = new byte[] { 0, 0x78 }; - // OpenFlow OUI - 00-26-E1 - byte[] dpidTLVValue = new byte[] { 0x0, 0x26, (byte) 0xe1, 0, 0, 0, - 0, 0, 0, 0, 0, 0 }; - LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127) - .setLength((short) dpidTLVValue.length) - .setValue(dpidTLVValue); - - byte[] dpidArray = new byte[8]; - ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray); - ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2); - - Long dpid = sw; - dpidBB.putLong(dpid); - // set the chassis id's value to last 6 bytes of dpid - System.arraycopy(dpidArray, 2, chassisId, 1, 6); - // set the optional tlv to the full dpid - System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8); - - // TODO: Consider remove this block of code. - // It's evil to overwrite port object. The the old code always - // overwrote mac address, we now only overwrite zero macs and - // log a warning, mostly for paranoia. - byte[] srcMac = ofpPort.getHardwareAddress(); - byte[] zeroMac = { 0, 0, 0, 0, 0, 0 }; - if (Arrays.equals(srcMac, zeroMac)) { - log.warn("Port {}/{} has zero hareware address" - + "overwrite with lower 6 bytes of dpid", - HexString.toHexString(dpid), ofpPort.getPortNumber()); - System.arraycopy(dpidArray, 2, srcMac, 0, 6); - } - - // set the portId to the outgoing port - portBB.putShort(port); - if (log.isTraceEnabled()) { - log.trace("Sending LLDP out of interface: {}/{}", - HexString.toHexString(sw), port); - } - - LLDP lldp = new LLDP(); - lldp.setChassisId(new LLDPTLV().setType((byte) 1) - .setLength((short) chassisId.length) - .setValue(chassisId)); - lldp.setPortId(new LLDPTLV().setType((byte) 2) - .setLength((short) portId.length) - .setValue(portId)); - lldp.setTtl(new LLDPTLV().setType((byte) 3) - .setLength((short) ttlValue.length) - .setValue(ttlValue)); - lldp.getOptionalTLVList().add(dpidTLV); - - // Add the controller identifier to the TLV value. - lldp.getOptionalTLVList().add(controllerTLV); - if (isReverse) { - lldp.getOptionalTLVList().add(reverseTLV); - } else { - lldp.getOptionalTLVList().add(forwardTLV); - } - - Ethernet ethernet; - if (isStandard) { - ethernet = new Ethernet().setSourceMACAddress(ofpPort.getHardwareAddress()) - .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING) - .setEtherType(Ethernet.TYPE_LLDP); - ethernet.setPayload(lldp); - } else { - BSN bsn = new BSN(BSN.BSN_TYPE_BDDP); - bsn.setPayload(lldp); - - ethernet = new Ethernet().setSourceMACAddress(ofpPort.getHardwareAddress()) - .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING) - .setEtherType(Ethernet.TYPE_BSN); - ethernet.setPayload(bsn); - } - - // serialize and wrap in a packet out - byte[] data = ethernet.serialize(); - OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.PACKET_OUT); - po.setBufferId(OFPacketOut.BUFFER_ID_NONE); - po.setInPort(OFPort.OFPP_NONE); - - // set data and data length - po.setLengthU(OFPacketOut.MINIMUM_LENGTH + data.length); - po.setPacketData(data); - - return po; - } - - /** - * Get the LLDP sending period in seconds. - * - * @return LLDP sending period in seconds. - */ - public int getLldpFrequency() { - return LLDP_TO_KNOWN_INTERVAL; - } - - /** - * Get the LLDP timeout value in seconds - * - * @return LLDP timeout value in seconds - */ - public int getLldpTimeout() { - return LINK_TIMEOUT; - } - - @Override - public Map<NodePortTuple, Set<Link>> getPortLinks() { - return portLinks; - } - - @Override - public Set<NodePortTuple> getSuppressLLDPsInfo() { - return suppressLinkDiscovery; - } - - /** - * Add a switch port to the suppressed LLDP list. Remove any known links on - * the switch port. - */ - @Override - public void AddToSuppressLLDPs(long sw, short port) { - NodePortTuple npt = new NodePortTuple(sw, port); - this.suppressLinkDiscovery.add(npt); - deleteLinksOnPort(npt, "LLDP suppressed."); - } - - /** - * Remove a switch port from the suppressed LLDP list. Discover links on - * that switchport. - */ - @Override - public void RemoveFromSuppressLLDPs(long sw, short port) { - NodePortTuple npt = new NodePortTuple(sw, port); - this.suppressLinkDiscovery.remove(npt); - discover(npt); - } - - public boolean isShuttingDown() { - return shuttingDown; - } - - @Override - public boolean isTunnelPort(long sw, short port) { - return false; - } - - @Override - public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) { - if (info.getUnicastValidTime() != null) { - return ILinkDiscovery.LinkType.DIRECT_LINK; - } else if (info.getMulticastValidTime() != null) { - return ILinkDiscovery.LinkType.MULTIHOP_LINK; - } - return ILinkDiscovery.LinkType.INVALID_LINK; - } - - @Override - public Set<Short> getQuarantinedPorts(long sw) { - Set<Short> qPorts = new HashSet<Short>(); - - Iterator<NodePortTuple> iter = quarantineQueue.iterator(); - while (iter.hasNext()) { - NodePortTuple npt = iter.next(); - if (npt.getNodeId() == sw) { - qPorts.add(npt.getPortId()); - } - } - return qPorts; - } - - @Override - public Map<Long, Set<Link>> getSwitchLinks() { - return this.switchLinks; - } - - @Override - public void addMACToIgnoreList(long mac, int ignoreBits) { - MACRange range = new MACRange(); - range.baseMAC = mac; - range.ignoreBits = ignoreBits; - ignoreMACSet.add(range); - } - - @Override - public boolean isAutoPortFastFeature() { - return autoPortFastFeature; - } - - @Override - public void setAutoPortFastFeature(boolean autoPortFastFeature) { - this.autoPortFastFeature = autoPortFastFeature; - } - - @Override - public void addListener(ILinkDiscoveryListener listener) { - linkDiscoveryAware.add(listener); - } - - @Override - public Map<Link, LinkInfo> getLinks() { - lock.readLock().lock(); - Map<Link, LinkInfo> result; - try { - result = new HashMap<Link, LinkInfo>(links); - } finally { - lock.readLock().unlock(); - } - return result; - } - - @Override - public LinkInfo getLinkInfo(Link link) { - lock.readLock().lock(); - LinkInfo linkInfo = links.get(link); - LinkInfo retLinkInfo = null; - if (linkInfo != null) { - retLinkInfo = new LinkInfo(linkInfo); - } - lock.readLock().unlock(); - return retLinkInfo; - } - - @Override - public String getName() { - return MODULE_NAME; - } - - //********************* - // OFMessage Listener - //********************* - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, - FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - ctrIncoming.updateCounterNoFlush(); - return this.handlePacketIn(sw.getId(), (OFPacketIn) msg, - cntx); - default: - break; - } - return Command.CONTINUE; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return false; - } - - //*********************************** - // Internal Methods - Packet-in Processing Related - //*********************************** - - protected Command handlePacketIn(long sw, OFPacketIn pi, - FloodlightContext cntx) { - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - if (eth.getPayload() instanceof BSN) { - BSN bsn = (BSN) eth.getPayload(); - if (bsn == null) return Command.STOP; - if (bsn.getPayload() == null) return Command.STOP; - // It could be a packet other than BSN LLDP, therefore - // continue with the regular processing. - if (bsn.getPayload() instanceof LLDP == false) - return Command.CONTINUE; - return handleLldp((LLDP) bsn.getPayload(), sw, pi.getInPort(), false, cntx); - } else if (eth.getPayload() instanceof LLDP) { - return handleLldp((LLDP) eth.getPayload(), sw, pi.getInPort(), true, cntx); - } else if (eth.getEtherType() < 1500) { - long destMac = eth.getDestinationMAC().toLong(); - if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) { - ctrLinkLocalDrops.updateCounterNoFlush(); - if (log.isTraceEnabled()) { - log.trace("Ignoring packet addressed to 802.1D/Q " - + "reserved address."); - } - return Command.STOP; - } - } - - if (ignorePacketInFromSource(eth.getSourceMAC().toLong())) { - ctrIgnoreSrcMacDrops.updateCounterNoFlush(); - return Command.STOP; - } - - // If packet-in is from a quarantine port, stop processing. - NodePortTuple npt = new NodePortTuple(sw, pi.getInPort()); - if (quarantineQueue.contains(npt)) { - ctrQuarantineDrops.updateCounterNoFlush(); - return Command.STOP; - } - - return Command.CONTINUE; - } - - private boolean ignorePacketInFromSource(long srcMAC) { - Iterator<MACRange> it = ignoreMACSet.iterator(); - while (it.hasNext()) { - MACRange range = it.next(); - long mask = ~0; - if (range.ignoreBits >= 0 && range.ignoreBits <= 48) { - mask = mask << range.ignoreBits; - if ((range.baseMAC & mask) == (srcMAC & mask)) { - return true; - } - } - } - return false; - } - - private Command handleLldp(LLDP lldp, long sw, short inPort, - boolean isStandard, FloodlightContext cntx) { - // If LLDP is suppressed on this port, ignore received packet as well - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - - if (!isIncomingDiscoveryAllowed(sw, inPort, isStandard)) - return Command.STOP; - - // If this is a malformed LLDP exit - if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) { - return Command.STOP; - } - - long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong(); - long otherId = 0; - boolean myLLDP = false; - Boolean isReverse = null; - - ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue()); - portBB.position(1); - - Short remotePort = portBB.getShort(); - IOFSwitch remoteSwitch = null; - - // Verify this LLDP packet matches what we're looking for - for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) { - if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 - && lldptlv.getValue()[0] == 0x0 - && lldptlv.getValue()[1] == 0x26 - && lldptlv.getValue()[2] == (byte) 0xe1 - && lldptlv.getValue()[3] == 0x0) { - ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue()); - remoteSwitch = floodlightProvider.getSwitch(dpidBB.getLong(4)); - } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) { - otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong(); - if (myId == otherId) myLLDP = true; - } else if (lldptlv.getType() == TLV_DIRECTION_TYPE - && lldptlv.getLength() == TLV_DIRECTION_LENGTH) { - if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0]) - isReverse = false; - else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0]) - isReverse = true; - } - } - - if (myLLDP == false) { - // This is not the LLDP sent by this controller. - // If the LLDP message has multicast bit set, then we need to - // broadcast the packet as a regular packet (after checking IDs) - if (isStandard) { - if (log.isTraceEnabled()) { - log.trace("Got a standard LLDP=[{}] that was not sent by" + - " this controller. Not fowarding it.", lldp.toString()); - } - return Command.STOP; - } else if (myId < otherId) { - if (log.isTraceEnabled()) { - log.trace("Getting BDDP packets from a different controller" - + "and letting it go through normal processing chain."); - } - return Command.CONTINUE; - } - return Command.STOP; - } - - if (remoteSwitch == null) { - // Ignore LLDPs not generated by Floodlight, or from a switch that - // has recently - // disconnected, or from a switch connected to another Floodlight - // instance - if (log.isTraceEnabled()) { - log.trace("Received LLDP from remote switch not connected to the controller"); - } - return Command.STOP; - } - - if (!remoteSwitch.portEnabled(remotePort)) { - if (log.isTraceEnabled()) { - log.trace("Ignoring link with disabled source port: switch {} port {} {}", - new Object[] { remoteSwitch.getStringId(), - remotePort, - remoteSwitch.getPort(remotePort)}); - } - return Command.STOP; - } - if (suppressLinkDiscovery.contains(new NodePortTuple( - remoteSwitch.getId(), - remotePort))) { - if (log.isTraceEnabled()) { - log.trace("Ignoring link with suppressed src port: switch {} port {} {}", - new Object[] { remoteSwitch.getStringId(), - remotePort, - remoteSwitch.getPort(remotePort)}); - } - return Command.STOP; - } - if (!iofSwitch.portEnabled(inPort)) { - if (log.isTraceEnabled()) { - log.trace("Ignoring link with disabled dest port: switch {} port {} {}", - new Object[] { HexString.toHexString(sw), - inPort, - iofSwitch.getPort(inPort)}); - } - return Command.STOP; - } - - // Store the time of update to this link, and push it out to - // routingEngine - Link lt = new Link(remoteSwitch.getId(), remotePort, - iofSwitch.getId(), inPort); - - if (!isLinkAllowed(lt.getSrc(), lt.getSrcPort(), - lt.getDst(), lt.getDstPort())) - return Command.STOP; - - // Continue only if link is allowed. - Long lastLldpTime = null; - Long lastBddpTime = null; - - Long firstSeenTime = System.currentTimeMillis(); - - if (isStandard) - lastLldpTime = System.currentTimeMillis(); - else - lastBddpTime = System.currentTimeMillis(); - - LinkInfo newLinkInfo = new LinkInfo(firstSeenTime, lastLldpTime, - lastBddpTime); - - addOrUpdateLink(lt, newLinkInfo); - - // Check if reverse link exists. - // If it doesn't exist and if the forward link was seen - // first seen within a small interval, send probe on the - // reverse link. - newLinkInfo = links.get(lt); - if (newLinkInfo != null && isStandard && isReverse == false) { - Link reverseLink = new Link(lt.getDst(), lt.getDstPort(), - lt.getSrc(), lt.getSrcPort()); - LinkInfo reverseInfo = links.get(reverseLink); - if (reverseInfo == null) { - // the reverse link does not exist. - if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - - LINK_TIMEOUT) { - this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), - isStandard, true); - } - } - } - - // If the received packet is a BDDP packet, then create a reverse BDDP - // link as well. - if (!isStandard) { - Link reverseLink = new Link(lt.getDst(), lt.getDstPort(), - lt.getSrc(), lt.getSrcPort()); - - // srcPortState and dstPort state are reversed. - LinkInfo reverseInfo = new LinkInfo(firstSeenTime, lastLldpTime, - lastBddpTime); - - addOrUpdateLink(reverseLink, reverseInfo); - } - - // Remove the node ports from the quarantine and maintenance queues. - NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), - lt.getSrcPort()); - NodePortTuple nptDst = new NodePortTuple(lt.getDst(), - lt.getDstPort()); - removeFromQuarantineQueue(nptSrc); - removeFromMaintenanceQueue(nptSrc); - removeFromQuarantineQueue(nptDst); - removeFromMaintenanceQueue(nptDst); - - // Consume this message - ctrLldpEol.updateCounterNoFlush(); - return Command.STOP; - } - - //*********************************** - // Internal Methods - Port Status/ New Port Processing Related - //*********************************** - /** - * Process a new port. If link discovery is disabled on the port, then do - * nothing. If autoportfast feature is enabled and the port is a fast port, - * then do nothing. Otherwise, send LLDP message. Add the port to - * quarantine. - * - * @param sw - * @param p - */ - private void processNewPort(long sw, short p) { - if (isLinkDiscoverySuppressed(sw, p)) { - // Do nothing as link discovery is suppressed. - return; - } - - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - if (iofSwitch == null) return; - - if (autoPortFastFeature && iofSwitch.isFastPort(p)) { - // Do nothing as the port is a fast port. - return; - } - NodePortTuple npt = new NodePortTuple(sw, p); - discover(sw, p); - // if it is not a fast port, add it to quarantine. - if (!iofSwitch.isFastPort(p)) { - addToQuarantineQueue(npt); - } else { - // Add to maintenance queue to ensure that BDDP packets - // are sent out. - addToMaintenanceQueue(npt); - } - } - - //*********************************** - // Internal Methods - Discovery Related - //*********************************** - - @LogMessageDoc(level = "ERROR", - message = "Error in link discovery updates loop", - explanation = "An unknown error occured while dispatching " - + "link update notifications", - recommendation = LogMessageDoc.GENERIC_ACTION) - private void doUpdatesThread() throws InterruptedException { - do { - LDUpdate update = updates.take(); - List<LDUpdate> updateList = new ArrayList<LDUpdate>(); - updateList.add(update); - - // Add all the pending updates to the list. - while (updates.peek() != null) { - updateList.add(updates.remove()); - } - - if (linkDiscoveryAware != null) { - if (log.isTraceEnabled()) { - log.trace("Dispatching link discovery update {} {} {} {} {} for {}", - new Object[] { - update.getOperation(), - HexString.toHexString(update.getSrc()), - update.getSrcPort(), - HexString.toHexString(update.getDst()), - update.getDstPort(), - linkDiscoveryAware }); - } - try { - for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order - // maintained - lda.linkDiscoveryUpdate(updateList); - } - } catch (Exception e) { - log.error("Error in link discovery updates loop", e); - } - } - } while (updates.peek() != null); - } - - protected boolean isLinkDiscoverySuppressed(long sw, short portNumber) { - return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, - portNumber)); - } - - protected void discoverLinks() { - - // timeout known links. - timeoutLinks(); - - // increment LLDP clock - lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL; - - if (lldpClock == 0) { - if (log.isTraceEnabled()) - log.trace("Sending LLDP out on all ports."); - discoverOnAllPorts(); - } - } - - /** - * Quarantine Ports. - */ - protected class QuarantineWorker implements Runnable { - @Override - public void run() { - try { - processBDDPLists(); - } catch (Exception e) { - log.error("Error in quarantine worker thread", e); - } finally { - bddpTask.reschedule(BDDP_TASK_INTERVAL, - TimeUnit.MILLISECONDS); - } - } - } - - /** - * Add a switch port to the quarantine queue. Schedule the quarantine task - * if the quarantine queue was empty before adding this switch port. - * - * @param npt - */ - protected void addToQuarantineQueue(NodePortTuple npt) { - if (quarantineQueue.contains(npt) == false) - quarantineQueue.add(npt); - } - - /** - * Remove a switch port from the quarantine queue. - */ - protected void removeFromQuarantineQueue(NodePortTuple npt) { - // Remove all occurrences of the node port tuple from the list. - while (quarantineQueue.remove(npt)) - ; - } - - /** - * Add a switch port to maintenance queue. - * - * @param npt - */ - protected void addToMaintenanceQueue(NodePortTuple npt) { - // TODO We are not checking if the switch port tuple is already - // in the maintenance list or not. This will be an issue for - // really large number of switch ports in the network. - if (maintenanceQueue.contains(npt) == false) - maintenanceQueue.add(npt); - } - - /** - * Remove a switch port from maintenance queue. - * - * @param npt - */ - protected void removeFromMaintenanceQueue(NodePortTuple npt) { - // Remove all occurrences of the node port tuple from the queue. - while (maintenanceQueue.remove(npt)) - ; - } - - /** - * This method processes the quarantine list in bursts. The task is at most - * once per BDDP_TASK_INTERVAL. One each call, BDDP_TASK_SIZE number of - * switch ports are processed. Once the BDDP packets are sent out through - * the switch ports, the ports are removed from the quarantine list. - */ - protected void processBDDPLists() { - int count = 0; - Set<NodePortTuple> nptList = new HashSet<NodePortTuple>(); - - while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) { - NodePortTuple npt; - npt = quarantineQueue.remove(); - sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, - false); - nptList.add(npt); - count++; - } - - count = 0; - while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) { - NodePortTuple npt; - npt = maintenanceQueue.remove(); - sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, - false); - count++; - } - - for (NodePortTuple npt : nptList) { - generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId()); - } - } - - private void generateSwitchPortStatusUpdate(long sw, short port) { - UpdateOperation operation; - - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - if (iofSwitch == null) return; - - OFPhysicalPort ofp = iofSwitch.getPort(port).toOFPhysicalPort(); - if (ofp == null) return; - - int srcPortState = ofp.getState(); - boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) - != OFPortState.OFPPS_STP_BLOCK.getValue()); - - if (portUp) - operation = UpdateOperation.PORT_UP; - else - operation = UpdateOperation.PORT_DOWN; - - updates.add(new LDUpdate(sw, port, operation)); - } - - protected void discover(NodePortTuple npt) { - discover(npt.getNodeId(), npt.getPortId()); - } - - protected void discover(long sw, short port) { - sendDiscoveryMessage(sw, port, true, false); - } - - /** - * Check if incoming discovery messages are enabled or not. - * @param sw - * @param port - * @param isStandard - * @return - */ - protected boolean isIncomingDiscoveryAllowed(long sw, short port, - boolean isStandard) { - - if (isLinkDiscoverySuppressed(sw, port)) { - /* Do not process LLDPs from this port as suppressLLDP is set */ - return false; - } - - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - if (iofSwitch == null) { - return false; - } - - if (port == OFPort.OFPP_LOCAL.getValue()) return false; - - ImmutablePort ofpPort = iofSwitch.getPort(port); - if (ofpPort == null) { - if (log.isTraceEnabled()) { - log.trace("Null physical port. sw={}, port={}", - HexString.toHexString(sw), port); - } - return false; - } - - return true; - } - - /** - * Check if outgoing discovery messages are enabled or not. - * @param sw - * @param port - * @param isStandard - * @param isReverse - * @return - */ - protected boolean isOutgoingDiscoveryAllowed(long sw, short port, - boolean isStandard, - boolean isReverse) { - - if (isLinkDiscoverySuppressed(sw, port)) { - /* Dont send LLDPs out of this port as suppressLLDP is set */ - return false; - } - - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - if (iofSwitch == null) { - return false; - } - - if (port == OFPort.OFPP_LOCAL.getValue()) return false; - - ImmutablePort ofpPort = iofSwitch.getPort(port); - if (ofpPort == null) { - if (log.isTraceEnabled()) { - log.trace("Null physical port. sw={}, port={}", - HexString.toHexString(sw), port); - } - return false; - } - - // For fast ports, do not send forward LLDPs or BDDPs. - if (!isReverse && autoPortFastFeature && iofSwitch.isFastPort(port)) - return false; - return true; - } - - /** - * Get the actions for packet-out corresponding to a specific port. - * This is a placeholder for adding actions if any port-specific - * actions are desired. The default action is simply to output to - * the given port. - * @param port - * @return - */ - protected List<OFAction> getDiscoveryActions (IOFSwitch sw, OFPhysicalPort port){ - // set actions - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(new OFActionOutput(port.getPortNumber(), (short) 0)); - return actions; - } - - /** - * Send link discovery message out of a given switch port. The discovery - * message may be a standard LLDP or a modified LLDP, where the dst mac - * address is set to :ff. TODO: The modified LLDP will updated in the future - * and may use a different eth-type. - * - * @param sw - * @param port - * @param isStandard - * indicates standard or modified LLDP - * @param isReverse - * indicates whether the LLDP was sent as a response - */ - @LogMessageDoc(level = "ERROR", - message = "Failure sending LLDP out port {port} on switch {switch}", - explanation = "An I/O error occured while sending LLDP message " - + "to the switch.", - recommendation = LogMessageDoc.CHECK_SWITCH) - protected void sendDiscoveryMessage(long sw, short port, - boolean isStandard, boolean isReverse) { - - // Takes care of all checks including null pointer checks. - if (!isOutgoingDiscoveryAllowed(sw, port, isStandard, isReverse)) - return; - - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - OFPhysicalPort ofpPort = iofSwitch.getPort(port).toOFPhysicalPort(); - - if (log.isTraceEnabled()) { - log.trace("Sending LLDP packet out of swich: {}, port: {}", - HexString.toHexString(sw), port); - } - OFPacketOut po = generateLLDPMessage(sw, port, isStandard, isReverse); - - // Add actions - List<OFAction> actions = getDiscoveryActions(iofSwitch, ofpPort); - po.setActions(actions); - short actionLength = 0; - Iterator <OFAction> actionIter = actions.iterator(); - while (actionIter.hasNext()) { - actionLength += actionIter.next().getLength(); - } - po.setActionsLength(actionLength); - - // po already has the minimum length + data length set - // simply add the actions length to this. - po.setLengthU(po.getLengthU() + po.getActionsLength()); - - // send - try { - iofSwitch.write(po, null); - iofSwitch.flush(); - } catch (IOException e) { - log.error("Failure sending LLDP out port {} on switch {}", - new Object[] { port, iofSwitch.getStringId() }, e); - } - } - - /** - * Send LLDPs to all switch-ports - */ - protected void discoverOnAllPorts() { - if (log.isTraceEnabled()) { - log.trace("Sending LLDP packets out of all the enabled ports"); - } - // Send standard LLDPs - for (long sw : floodlightProvider.getAllSwitchDpids()) { - IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw); - if (iofSwitch == null) continue; - if (iofSwitch.getEnabledPorts() != null) { - for (ImmutablePort ofp : iofSwitch.getEnabledPorts()) { - if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) - continue; - if (autoPortFastFeature - && iofSwitch.isFastPort(ofp.getPortNumber())) - continue; - - // sends forward LLDP only non-fastports. - sendDiscoveryMessage(sw, ofp.getPortNumber(), true, - false); - - // If the switch port is not already in the maintenance - // queue, add it. - NodePortTuple npt = new NodePortTuple( - sw, - ofp.getPortNumber()); - addToMaintenanceQueue(npt); - } - } - } - } - - protected UpdateOperation getUpdateOperation(int srcPortState, - int dstPortState) { - boolean added = (((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) - != OFPortState.OFPPS_STP_BLOCK.getValue()) && - ((dstPortState & OFPortState.OFPPS_STP_MASK.getValue()) - != OFPortState.OFPPS_STP_BLOCK.getValue())); - - if (added) return UpdateOperation.LINK_UPDATED; - return UpdateOperation.LINK_REMOVED; - } - - protected UpdateOperation getUpdateOperation(int srcPortState) { - boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue()); - - if (portUp) - return UpdateOperation.PORT_UP; - else - return UpdateOperation.PORT_DOWN; - } - - //************************************ - // Internal Methods - Link Operations Related - //************************************ - - /** - * This method is used to specifically ignore/consider specific links. - */ - protected boolean isLinkAllowed(long src, short srcPort, - long dst, short dstPort) { - return true; - } - - private boolean addLink(Link lt, LinkInfo newInfo) { - NodePortTuple srcNpt, dstNpt; - - srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); - dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort()); - - // index it by switch source - if (!switchLinks.containsKey(lt.getSrc())) - switchLinks.put(lt.getSrc(), - new HashSet<Link>()); - switchLinks.get(lt.getSrc()).add(lt); - - // index it by switch dest - if (!switchLinks.containsKey(lt.getDst())) - switchLinks.put(lt.getDst(), - new HashSet<Link>()); - switchLinks.get(lt.getDst()).add(lt); - - // index both ends by switch:port - if (!portLinks.containsKey(srcNpt)) - portLinks.put(srcNpt, - new HashSet<Link>()); - portLinks.get(srcNpt).add(lt); - - if (!portLinks.containsKey(dstNpt)) - portLinks.put(dstNpt, - new HashSet<Link>()); - portLinks.get(dstNpt).add(lt); - - return true; - } - - protected boolean updateLink(Link lt, LinkInfo oldInfo, LinkInfo newInfo) { - boolean linkChanged = false; - // Since the link info is already there, we need to - // update the right fields. - if (newInfo.getUnicastValidTime() == null) { - // This is due to a multicast LLDP, so copy the old unicast - // value. - if (oldInfo.getUnicastValidTime() != null) { - newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime()); - } - } else if (newInfo.getMulticastValidTime() == null) { - // This is due to a unicast LLDP, so copy the old multicast - // value. - if (oldInfo.getMulticastValidTime() != null) { - newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime()); - } - } - - Long oldTime = oldInfo.getUnicastValidTime(); - Long newTime = newInfo.getUnicastValidTime(); - // the link has changed its state between openflow and - // non-openflow - // if the unicastValidTimes are null or not null - if (oldTime != null & newTime == null) { - linkChanged = true; - } else if (oldTime == null & newTime != null) { - linkChanged = true; - } - - return linkChanged; - } - - @LogMessageDocs({ - @LogMessageDoc(message="Inter-switch link detected:", - explanation="Detected a new link between two openflow switches," + - "use show link to find current status"), - @LogMessageDoc(message="Inter-switch link updated:", - explanation="Detected a link change between two openflow switches, " + - "use show link to find current status") - }) - protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) { - - boolean linkChanged = false; - - lock.writeLock().lock(); - try { - // put the new info. if an old info exists, it will be returned. - LinkInfo oldInfo = links.put(lt, newInfo); - if (oldInfo != null - && oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) - newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime()); - - if (log.isTraceEnabled()) { - log.trace("addOrUpdateLink: {} {}", - lt, - (newInfo.getMulticastValidTime() != null) ? "multicast" - : "unicast"); - } - - UpdateOperation updateOperation = null; - linkChanged = false; - - if (oldInfo == null) { - addLink(lt, newInfo); - updateOperation = UpdateOperation.LINK_UPDATED; - linkChanged = true; - - // Log direct links only. Multi-hop links may be numerous - // Add all to event history - LinkType linkType = getLinkType(lt, newInfo); - if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) { - log.info("Inter-switch link detected: {}", lt); - evDirectLink.updateEventNoFlush(new DirectLinkEvent(lt.getSrc(), - lt.getSrcPort(), lt.getDst(), lt.getDstPort(), "direct-link-added::rcvd LLDP")); - } - notifier.postNotification("Link added: " + lt.toString()); - } else { - linkChanged = updateLink(lt, oldInfo, newInfo); - if (linkChanged) { - updateOperation = UpdateOperation.LINK_UPDATED; - LinkType linkType = getLinkType(lt, newInfo); - if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) { - log.info("Inter-switch link updated: {}", lt); - evDirectLink.updateEventNoFlush(new DirectLinkEvent(lt.getSrc(), - lt.getSrcPort(), lt.getDst(), lt.getDstPort(), - "link-port-state-updated::rcvd LLDP")); - } - notifier.postNotification("Link updated: " + lt.toString()); - } - } - - // Write changes to storage. This will always write the updated - // valid time, plus the port states if they've changed (i.e. if - // they weren't set to null in the previous block of code. - writeLinkToStorage(lt, newInfo); - - if (linkChanged) { - // find out if the link was added or removed here. - updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), - lt.getDst(), lt.getDstPort(), - getLinkType(lt, newInfo), - updateOperation)); - } - } finally { - lock.writeLock().unlock(); - } - - return linkChanged; - } - - /** - * Delete a link - * - * @param link - * - link to be deleted. - * @param reason - * - reason why the link is deleted. - */ - protected void deleteLink(Link link, String reason) { - if (link == null) - return; - List<Link> linkList = new ArrayList<Link>(); - linkList.add(link); - deleteLinks(linkList, reason); - } - /** - * Removes links from memory and storage. - * - * @param links - * The List of @LinkTuple to delete. - */ - protected void deleteLinks(List<Link> links, String reason) { - deleteLinks(links, reason, null); - } - - /** - * Removes links from memory and storage. - * - * @param links - * The List of @LinkTuple to delete. - */ - @LogMessageDoc(message="Inter-switch link removed:", - explanation="A previously detected link between two openflow switches no longer exists, " + - "use show link to find current status") - protected void deleteLinks(List<Link> links, String reason, - List<LDUpdate> updateList) { - - NodePortTuple srcNpt, dstNpt; - List<LDUpdate> linkUpdateList = new ArrayList<LDUpdate>(); - lock.writeLock().lock(); - try { - for (Link lt : links) { - srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); - dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort()); - - if (switchLinks.containsKey(lt.getSrc())) { - switchLinks.get(lt.getSrc()).remove(lt); - if (switchLinks.get(lt.getSrc()).isEmpty()) - this.switchLinks.remove(lt.getSrc()); - } - if (this.switchLinks.containsKey(lt.getDst())) { - switchLinks.get(lt.getDst()).remove(lt); - if (this.switchLinks.get(lt.getDst()).isEmpty()) - this.switchLinks.remove(lt.getDst()); - } - - if (this.portLinks.get(srcNpt) != null) { - this.portLinks.get(srcNpt).remove(lt); - if (this.portLinks.get(srcNpt).isEmpty()) - this.portLinks.remove(srcNpt); - } - if (this.portLinks.get(dstNpt) != null) { - this.portLinks.get(dstNpt).remove(lt); - if (this.portLinks.get(dstNpt).isEmpty()) - this.portLinks.remove(dstNpt); - } - - LinkInfo info = this.links.remove(lt); - LinkType linkType = getLinkType(lt, info); - linkUpdateList.add(new LDUpdate(lt.getSrc(), - lt.getSrcPort(), - lt.getDst(), - lt.getDstPort(), - linkType, - UpdateOperation.LINK_REMOVED)); - - // FIXME: link type shows up as invalid now -- thus not checking if - // link type is a direct link - evDirectLink.updateEventWithFlush(new DirectLinkEvent(lt.getSrc(), - lt.getSrcPort(), lt.getDst(), lt.getDstPort(), - "link-deleted::" + reason)); - // remove link from storage. - removeLinkFromStorage(lt); - - // TODO Whenever link is removed, it has to checked if - // the switchports must be added to quarantine. - - if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) { - log.info("Inter-switch link removed: {}", lt); - notifier.postNotification("Inter-switch link removed: " + - lt.toString()); - } else if (log.isTraceEnabled()) { - log.trace("Deleted link {}", lt); - } - } - } finally { - if (updateList != null) linkUpdateList.addAll(updateList); - updates.addAll(linkUpdateList); - lock.writeLock().unlock(); - } - } - - /** - * Delete links incident on a given switch port. - * - * @param npt - * @param reason - */ - protected void deleteLinksOnPort(NodePortTuple npt, String reason) { - List<Link> eraseList = new ArrayList<Link>(); - if (this.portLinks.containsKey(npt)) { - if (log.isTraceEnabled()) { - log.trace("handlePortStatus: Switch {} port #{} " - + "removing links {}", - new Object[] { - HexString.toHexString(npt.getNodeId()), - npt.getPortId(), - this.portLinks.get(npt) }); - } - eraseList.addAll(this.portLinks.get(npt)); - deleteLinks(eraseList, reason); - } - } - - /** - * Iterates through the list of links and deletes if the last discovery - * message reception time exceeds timeout values. - */ - protected void timeoutLinks() { - List<Link> eraseList = new ArrayList<Link>(); - Long curTime = System.currentTimeMillis(); - boolean linkChanged = false; - - // reentrant required here because deleteLink also write locks - lock.writeLock().lock(); - try { - Iterator<Entry<Link, LinkInfo>> it = this.links.entrySet() - .iterator(); - while (it.hasNext()) { - Entry<Link, LinkInfo> entry = it.next(); - Link lt = entry.getKey(); - LinkInfo info = entry.getValue(); - - // Timeout the unicast and multicast LLDP valid times - // independently. - if ((info.getUnicastValidTime() != null) - && (info.getUnicastValidTime() - + (this.LINK_TIMEOUT * 1000) < curTime)) { - info.setUnicastValidTime(null); - linkChanged = true; - } - if ((info.getMulticastValidTime() != null) - && (info.getMulticastValidTime() - + (this.LINK_TIMEOUT * 1000) < curTime)) { - info.setMulticastValidTime(null); - linkChanged = true; - } - // Add to the erase list only if the unicast - // time is null. - if (info.getUnicastValidTime() == null - && info.getMulticastValidTime() == null) { - eraseList.add(entry.getKey()); - } else if (linkChanged) { - updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), - lt.getDst(), lt.getDstPort(), - getLinkType(lt, info), - UpdateOperation.LINK_UPDATED)); - } - } - - // if any link was deleted or any link was changed. - if ((eraseList.size() > 0) || linkChanged) { - deleteLinks(eraseList, "LLDP timeout"); - } - } finally { - lock.writeLock().unlock(); - } - } - - //****************** - // Internal Helper Methods - //****************** - @LogMessageDoc(level="WARN", - message="Could not get list of interfaces of local machine to " + - "encode in TLV: {detail-msg}", - explanation="Outgoing LLDP packets encode a unique hash to " + - "identify the local machine. The list of network " + - "interfaces is used as input and the controller failed " + - "to query this list", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - protected void setControllerTLV() { - // Setting the controllerTLVValue based on current nano time, - // controller's IP address, and the network interface object hash - // the corresponding IP address. - - final int prime = 7867; - - byte[] controllerTLVValue = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; // 8 - // byte - // value. - ByteBuffer bb = ByteBuffer.allocate(10); - - long result = System.nanoTime(); - try{ - // Use some data specific to the machine this controller is - // running on. In this case: the list of network interfaces - Enumeration<NetworkInterface> ifaces = - NetworkInterface.getNetworkInterfaces(); - if (ifaces != null) { - result = result * prime + ifaces.hashCode(); - } - } catch (SocketException e) { - log.warn("Could not get list of interfaces of local machine to " + - "encode in TLV: {}", e.toString()); - } - // set the first 4 bits to 0. - result = result & (0x0fffffffffffffffL); - - bb.putLong(result); - - bb.rewind(); - bb.get(controllerTLVValue, 0, 8); - - this.controllerTLV = new LLDPTLV().setType((byte) 0x0c) - .setLength((short) controllerTLVValue.length) - .setValue(controllerTLVValue); - } - - //****************** - // IOFSwitchListener - //****************** - private void handlePortDown(long switchId, short portNumber) { - NodePortTuple npt = new NodePortTuple(switchId, portNumber); - deleteLinksOnPort(npt, "Port Status Changed"); - LDUpdate update = new LDUpdate(switchId, portNumber, - UpdateOperation.PORT_DOWN); - updates.add(update); - } - /** - * We don't react the port changed notifications here. we listen for - * OFPortStatus messages directly. Might consider using this notifier - * instead - */ - @Override - public void switchPortChanged(long switchId, - ImmutablePort port, - IOFSwitch.PortChangeType type) { - - switch (type) { - case UP: - processNewPort(switchId, port.getPortNumber()); - break; - case DELETE: case DOWN: - handlePortDown(switchId, port.getPortNumber()); - break; - case OTHER_UPDATE: case ADD: - // This is something other than port add or delete. - // Topology does not worry about this. - // If for some reason the port features change, which - // we may have to react. - break; - } - } - - @Override - public void switchAdded(long switchId) { - // no-op - // We don't do anything at switch added, but we do only when the - // switch is activated. - } - - @Override - public void switchRemoved(long sw) { - List<Link> eraseList = new ArrayList<Link>(); - lock.writeLock().lock(); - try { - if (switchLinks.containsKey(sw)) { - if (log.isTraceEnabled()) { - log.trace("Handle switchRemoved. Switch {}; removing links {}", - HexString.toHexString(sw), switchLinks.get(sw)); - } - - List<LDUpdate> updateList = new ArrayList<LDUpdate>(); - updateList.add(new LDUpdate(sw, null, - UpdateOperation.SWITCH_REMOVED)); - // add all tuples with an endpoint on this switch to erase list - eraseList.addAll(switchLinks.get(sw)); - - // Sending the updateList, will ensure the updates in this - // list will be added at the end of all the link updates. - // Thus, it is not necessary to explicitly add these updates - // to the queue. - deleteLinks(eraseList, "Switch Removed", updateList); - } else { - // Switch does not have any links. - updates.add(new LDUpdate(sw, null, - UpdateOperation.SWITCH_REMOVED)); - } - } finally { - lock.writeLock().unlock(); - } - - } - - @Override - public void switchActivated(long switchId) { - IOFSwitch sw = floodlightProvider.getSwitch(switchId); - if (sw.getEnabledPortNumbers() != null) { - for (Short p : sw.getEnabledPortNumbers()) { - processNewPort(sw.getId(), p); - } - } - LDUpdate update = new LDUpdate(sw.getId(), null, - UpdateOperation.SWITCH_UPDATED); - updates.add(update); - } - - @Override - public void switchChanged(long switchId) { - // no-op - } - - - //********************* - // Storage Listener - //********************* - /** - * Sets the IStorageSource to use for Topology - * - * @param storageSource - * the storage source to use - */ - public void setStorageSource(IStorageSourceService storageSource) { - this.storageSource = storageSource; - } - - /** - * Gets the storage source for this ITopology - * - * @return The IStorageSource ITopology is writing to - */ - public IStorageSourceService getStorageSource() { - return storageSource; - } - - @Override - public void rowsModified(String tableName, Set<Object> rowKeys) { - - if (tableName.equals(TOPOLOGY_TABLE_NAME)) { - readTopologyConfigFromStorage(); - return; - } - - ArrayList<IOFSwitch> updated_switches = new ArrayList<IOFSwitch>(); - for (Object key : rowKeys) { - Long swId = new Long(HexString.toLong((String) key)); - IOFSwitch sw = floodlightProvider.getSwitch(swId); - if (sw != null) { - boolean curr_status = sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH); - boolean new_status = false; - IResultSet resultSet = null; - - try { - resultSet = storageSource.getRow(tableName, key); - for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) { - // In case of multiple rows, use the status in last row? - Map<String, Object> row = it.next().getRow(); - if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) { - new_status = ((String) row.get(SWITCH_CONFIG_CORE_SWITCH)).equals("true"); - } - } - } finally { - if (resultSet != null) resultSet.close(); - } - - if (curr_status != new_status) { - updated_switches.add(sw); - } - } else { - if (log.isTraceEnabled()) { - log.trace("Update for switch which has no entry in switch " - + "list (dpid={}), a delete action.", - key); - } - } - } - - for (IOFSwitch sw : updated_switches) { - // Set SWITCH_IS_CORE_SWITCH to it's inverse value - if (sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH)) { - sw.removeAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH); - if (log.isTraceEnabled()) { - log.trace("SWITCH_IS_CORE_SWITCH set to False for {}", - sw); - } - updates.add(new LDUpdate(sw.getId(), - SwitchType.BASIC_SWITCH, - UpdateOperation.SWITCH_UPDATED)); - } else { - sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, - new Boolean(true)); - if (log.isTraceEnabled()) { - log.trace("SWITCH_IS_CORE_SWITCH set to True for {}", sw); - } - updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH, - UpdateOperation.SWITCH_UPDATED)); - } - } - } - - @Override - public void rowsDeleted(String tableName, Set<Object> rowKeys) { - // Ignore delete events, the switch delete will do the - // right thing on it's own. - readTopologyConfigFromStorage(); - } - - - //****************************** - // Internal methods - Config Related - //****************************** - - protected void readTopologyConfigFromStorage() { - IResultSet topologyResult = storageSource.executeQuery(TOPOLOGY_TABLE_NAME, - null, null, - null); - - if (topologyResult.next()) { - boolean apf = topologyResult.getBoolean(TOPOLOGY_AUTOPORTFAST); - autoPortFastFeature = apf; - } else { - this.autoPortFastFeature = AUTOPORTFAST_DEFAULT; - } - - if (autoPortFastFeature) - log.info("Setting autoportfast feature to ON"); - else - log.info("Setting autoportfast feature to OFF"); - } - - /** - * Deletes all links from storage - */ - void clearAllLinks() { - storageSource.deleteRowsAsync(LINK_TABLE_NAME, null); - } - - /** - * Writes a LinkTuple and corresponding LinkInfo to storage - * - * @param lt - * The LinkTuple to write - * @param linkInfo - * The LinkInfo to write - */ - protected void writeLinkToStorage(Link lt, LinkInfo linkInfo) { - LinkType type = getLinkType(lt, linkInfo); - - // Write only direct links. Do not write links to external - // L2 network. - // if (type != LinkType.DIRECT_LINK && type != LinkType.TUNNEL) { - // return; - // } - - Map<String, Object> rowValues = new HashMap<String, Object>(); - String id = getLinkId(lt); - rowValues.put(LINK_ID, id); - rowValues.put(LINK_VALID_TIME, linkInfo.getUnicastValidTime()); - String srcDpid = HexString.toHexString(lt.getSrc()); - rowValues.put(LINK_SRC_SWITCH, srcDpid); - rowValues.put(LINK_SRC_PORT, lt.getSrcPort()); - - if (type == LinkType.DIRECT_LINK) - rowValues.put(LINK_TYPE, "internal"); - else if (type == LinkType.MULTIHOP_LINK) - rowValues.put(LINK_TYPE, "external"); - else if (type == LinkType.TUNNEL) - rowValues.put(LINK_TYPE, "tunnel"); - else - rowValues.put(LINK_TYPE, "invalid"); - - String dstDpid = HexString.toHexString(lt.getDst()); - rowValues.put(LINK_DST_SWITCH, dstDpid); - rowValues.put(LINK_DST_PORT, lt.getDstPort()); - - storageSource.updateRowAsync(LINK_TABLE_NAME, rowValues); - } - - /** - * Removes a link from storage using an asynchronous call. - * - * @param lt - * The LinkTuple to delete. - */ - protected void removeLinkFromStorage(Link lt) { - String id = getLinkId(lt); - storageSource.deleteRowAsync(LINK_TABLE_NAME, id); - } - - public Long readLinkValidTime(Link lt) { - // FIXME: We're not currently using this right now, but if we start - // to use this again, we probably shouldn't use it in its current - // form, because it's doing synchronous storage calls. Depending - // on the context this may still be OK, but if it's being called - // on the packet in processing thread it should be reworked to - // use asynchronous storage calls. - Long validTime = null; - IResultSet resultSet = null; - try { - String[] columns = { LINK_VALID_TIME }; - String id = getLinkId(lt); - resultSet = storageSource.executeQuery(LINK_TABLE_NAME, - columns, - new OperatorPredicate( - LINK_ID, - OperatorPredicate.Operator.EQ, - id), - null); - if (resultSet.next()) - validTime = resultSet.getLong(LINK_VALID_TIME); - } finally { - if (resultSet != null) resultSet.close(); - } - return validTime; - } - - /** - * Gets the storage key for a LinkTuple - * - * @param lt - * The LinkTuple to get - * @return The storage key as a String - */ - private String getLinkId(Link lt) { - return HexString.toHexString(lt.getSrc()) + "-" + lt.getSrcPort() - + "-" + HexString.toHexString(lt.getDst()) + "-" - + lt.getDstPort(); - } - - //*************** - // IFloodlightModule - //*************** - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(ILinkDiscoveryService.class); - // l.add(ITopologyService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - Map<Class<? extends IFloodlightService>, IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); - // We are the class that implements the service - m.put(ILinkDiscoveryService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IStorageSourceService.class); - l.add(IThreadPoolService.class); - l.add(IRestApiService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); - storageSource = context.getServiceImpl(IStorageSourceService.class); - threadPool = context.getServiceImpl(IThreadPoolService.class); - restApi = context.getServiceImpl(IRestApiService.class); - debugCounters = context.getServiceImpl(IDebugCounterService.class); - debugEvents = context.getServiceImpl(IDebugEventService.class); - - // read our config options - Map<String, String> configOptions = context.getConfigParams(this); - try { - String histSize = configOptions.get("eventhistorysize"); - if (histSize != null) { - EVENT_HISTORY_SIZE = Short.parseShort(histSize); - } - } catch (NumberFormatException e) { - log.warn("Error event history size, using default of {} seconds", EVENT_HISTORY_SIZE); - } - log.debug("Event history size set to {}", EVENT_HISTORY_SIZE); - - // Set the autoportfast feature to false. - this.autoPortFastFeature = AUTOPORTFAST_DEFAULT; - - // We create this here because there is no ordering guarantee - this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>(); - this.lock = new ReentrantReadWriteLock(); - this.updates = new LinkedBlockingQueue<LDUpdate>(); - this.links = new HashMap<Link, LinkInfo>(); - this.portLinks = new HashMap<NodePortTuple, Set<Link>>(); - this.suppressLinkDiscovery = Collections.synchronizedSet(new HashSet<NodePortTuple>()); - this.switchLinks = new HashMap<Long, Set<Link>>(); - this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>(); - this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>(); - - this.ignoreMACSet = Collections.newSetFromMap( - new ConcurrentHashMap<MACRange,Boolean>()); - this.haListener = new HAListenerDelegate(); - registerLinkDiscoveryDebugCounters(); - registerLinkDiscoveryDebugEvents(); - } - - @Override - @LogMessageDocs({ - @LogMessageDoc(level = "ERROR", - message = "No storage source found.", - explanation = "Storage source was not initialized; cannot initialize " - + "link discovery.", - recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG), - @LogMessageDoc(level = "ERROR", - message = "Error in installing listener for " - + "switch config table {table}", - explanation = "Failed to install storage notification for the " - + "switch config table", - recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG), - @LogMessageDoc(level = "ERROR", - message = "No storage source found.", - explanation = "Storage source was not initialized; cannot initialize " - + "link discovery.", - recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG), - @LogMessageDoc(level = "ERROR", - message = "Exception in LLDP send timer.", - explanation = "An unknown error occured while sending LLDP " - + "messages to switches.", - recommendation = LogMessageDoc.CHECK_SWITCH) }) - public void startUp(FloodlightModuleContext context) throws FloodlightModuleException { - - // Initialize role to floodlight provider role. - this.role = floodlightProvider.getRole(); - - // Create our storage tables - if (storageSource == null) { - log.error("No storage source found."); - return; - } - - storageSource.createTable(TOPOLOGY_TABLE_NAME, null); - storageSource.setTablePrimaryKeyName(TOPOLOGY_TABLE_NAME, - TOPOLOGY_ID); - readTopologyConfigFromStorage(); - - storageSource.createTable(LINK_TABLE_NAME, null); - storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID); - storageSource.deleteMatchingRows(LINK_TABLE_NAME, null); - // Register for storage updates for the switch table - try { - storageSource.addListener(SWITCH_CONFIG_TABLE_NAME, this); - storageSource.addListener(TOPOLOGY_TABLE_NAME, this); - } catch (StorageException ex) { - log.error("Error in installing listener for " - + "switch table {}", SWITCH_CONFIG_TABLE_NAME); - } - - ScheduledExecutorService ses = threadPool.getScheduledExecutor(); - - // To be started by the first switch connection - discoveryTask = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - try { - discoverLinks(); - } catch (StorageException e) { - log.error("Storage exception in LLDP send timer; " - + "terminating process", e); - floodlightProvider.terminate(); - } catch (Exception e) { - log.error("Exception in LLDP send timer.", e); - } finally { - if (!shuttingDown) { - // null role implies HA mode is not enabled. - if (role == null || role == Role.MASTER) { - log.trace("Rescheduling discovery task as role = {}", - role); - discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, - TimeUnit.SECONDS); - } else { - log.trace("Stopped LLDP rescheduling due to role = {}.", - role); - } - } - } - } - }); - - // null role implies HA mode is not enabled. - if (role == null || role == Role.MASTER) { - log.trace("Setup: Rescheduling discovery task. role = {}", role); - discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, - TimeUnit.SECONDS); - } else { - log.trace("Setup: Not scheduling LLDP as role = {}.", role); - } - - // Setup the BDDP task. It is invoked whenever switch port tuples - // are added to the quarantine list. - bddpTask = new SingletonTask(ses, new QuarantineWorker()); - bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS); - - updatesThread = new Thread(new Runnable() { - @Override - public void run() { - while (true) { - try { - doUpdatesThread(); - } catch (InterruptedException e) { - return; - } - } - } - }, "Topology Updates"); - updatesThread.start(); - - // Register for the OpenFlow messages we want to receive - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this); - // Register for switch updates - floodlightProvider.addOFSwitchListener(this); - floodlightProvider.addHAListener(this.haListener); - floodlightProvider.addInfoProvider("summary", this); - if (restApi != null) - restApi.addRestletRoutable(new LinkDiscoveryWebRoutable()); - setControllerTLV(); - } - - // **************************************************** - // Link Discovery DebugCounters and DebugEvents - // **************************************************** - - private void registerLinkDiscoveryDebugCounters() throws FloodlightModuleException { - if (debugCounters == null) { - log.error("Debug Counter Service not found."); - debugCounters = new NullDebugCounter(); - } - try { - ctrIncoming = debugCounters.registerCounter(PACKAGE, "incoming", - "All incoming packets seen by this module", CounterType.ALWAYS_COUNT); - ctrLldpEol = debugCounters.registerCounter(PACKAGE, "lldp-eol", - "End of Life for LLDP packets", CounterType.COUNT_ON_DEMAND); - ctrLinkLocalDrops = debugCounters.registerCounter(PACKAGE, "linklocal-drops", - "All link local packets dropped by this module", - CounterType.ALWAYS_COUNT); - ctrIgnoreSrcMacDrops = debugCounters.registerCounter(PACKAGE, "ignore-srcmac-drops", - "All packets whose srcmac is configured to be dropped by this module", - CounterType.ALWAYS_COUNT); - ctrQuarantineDrops = debugCounters.registerCounter(PACKAGE, "quarantine-drops", - "All packets arriving on quarantined ports dropped by this module", - CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); - } catch (CounterException e) { - throw new FloodlightModuleException(e.getMessage()); - } - } - - private void registerLinkDiscoveryDebugEvents() throws FloodlightModuleException { - if (debugEvents == null) { - log.error("Debug Event Service not found."); - debugEvents = new NullDebugEvent(); - } - - try { - evDirectLink = debugEvents.registerEvent( - PACKAGE, "linkevent", - "Direct OpenFlow links discovered or timed-out", - EventType.ALWAYS_LOG, DirectLinkEvent.class, 100); - } catch (MaxEventsRegistered e) { - throw new FloodlightModuleException("max events registered", e); - } - - } - - public class DirectLinkEvent { - @EventColumn(name = "srcSw", description = EventFieldType.DPID) - long srcDpid; - - @EventColumn(name = "srcPort", description = EventFieldType.PRIMITIVE) - short srcPort; - - @EventColumn(name = "dstSw", description = EventFieldType.DPID) - long dstDpid; - - @EventColumn(name = "dstPort", description = EventFieldType.PRIMITIVE) - short dstPort; - - @EventColumn(name = "reason", description = EventFieldType.STRING) - String reason; - - public DirectLinkEvent(long srcDpid, short srcPort, long dstDpid, - short dstPort, String reason) { - this.srcDpid = srcDpid; - this.srcPort = srcPort; - this.dstDpid = dstDpid; - this.dstPort = dstPort; - this.reason = reason; - } - } - - - //********************* - // IInfoProvider - //********************* - - @Override - public Map<String, Object> getInfo(String type) { - if (!"summary".equals(type)) return null; - - Map<String, Object> info = new HashMap<String, Object>(); - - int numDirectLinks = 0; - for (Set<Link> links : switchLinks.values()) { - for (Link link : links) { - LinkInfo linkInfo = this.getLinkInfo(link); - if (linkInfo != null && - linkInfo.getLinkType() == LinkType.DIRECT_LINK) { - numDirectLinks++; - } - } - } - info.put("# inter-switch links", numDirectLinks / 2); - info.put("# quarantine ports", quarantineQueue.size()); - return info; - } - - //*************** - // IHAListener - //*************** - - private class HAListenerDelegate implements IHAListener { - @Override - public void transitionToMaster() { - if (log.isTraceEnabled()) { - log.trace("Sending LLDPs " - + "to HA change from SLAVE->MASTER"); - } - LinkDiscoveryManager.this.role = Role.MASTER; - clearAllLinks(); - readTopologyConfigFromStorage(); - log.debug("Role Change to Master: Rescheduling discovery task."); - discoveryTask.reschedule(1, TimeUnit.MICROSECONDS); - } - - @Override - public void controllerNodeIPsChanged(Map<String, String> curControllerNodeIPs, - Map<String, String> addedControllerNodeIPs, - Map<String, String> removedControllerNodeIPs) { - // ignore - } - - @Override - public String getName() { - return LinkDiscoveryManager.this.getName(); - } - - @Override - public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type, - String name) { - return ("topology".equals(name)); - } - - @Override - public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type, - String name) { - return "tunnelmanager".equals(name); - } - } - -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/AutoPortFast.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/AutoPortFast.java deleted file mode 100644 index a5775f1b2926f5b0dce6e996ded58f17b7d9ba6d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/AutoPortFast.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery.web; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; - -import org.restlet.data.Status; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AutoPortFast extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(AutoPortFast.class); - - @Get("json") - public String retrieve() { - ILinkDiscoveryService linkDiscovery; - linkDiscovery = (ILinkDiscoveryService)getContext().getAttributes(). - get(ILinkDiscoveryService.class.getCanonicalName()); - - String param = ((String)getRequestAttributes().get("state")).toLowerCase(); - if (param.equals("enable") || param.equals("true")) { - linkDiscovery.setAutoPortFastFeature(true); - } else if (param.equals("disable") || param.equals("false")) { - linkDiscovery.setAutoPortFastFeature(false); - } - setStatus(Status.SUCCESS_OK, "OK"); - if (linkDiscovery.isAutoPortFastFeature()) - return "enabled"; - else return "disabled"; - } -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java deleted file mode 100644 index 37dbd3953ee32287d8b1076e843faec154e1e15d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery.web; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.routing.Link; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class DirectedLinksResource extends ServerResource { - - @Get("json") - public Set<LinkWithType> retrieve() { - ILinkDiscoveryService ld = (ILinkDiscoveryService)getContext().getAttributes(). - get(ILinkDiscoveryService.class.getCanonicalName()); - Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>(); - Set<LinkWithType> returnLinkSet = new HashSet<LinkWithType>(); - - if (ld != null) { - links.putAll(ld.getLinks()); - for (Link link: links.keySet()) { - LinkInfo info = links.get(link); - LinkType type = ld.getLinkType(link, info); - if (type == LinkType.DIRECT_LINK || type == LinkType.TUNNEL) { - LinkWithType lwt = new LinkWithType(link, - type,LinkDirection.UNIDIRECTIONAL); - returnLinkSet.add(lwt); - } - } - } - return returnLinkSet; - } -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java deleted file mode 100644 index c2aa9d4e47dbf8a7d52020380466c50c62bd9660..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery.web; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.routing.Link; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class ExternalLinksResource extends ServerResource { - - @Get("json") - public Set<LinkWithType> retrieve() { - ILinkDiscoveryService ld = (ILinkDiscoveryService)getContext().getAttributes(). - get(ILinkDiscoveryService.class.getCanonicalName()); - Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>(); - Set<LinkWithType> returnLinkSet = new HashSet<LinkWithType>(); - - if (ld != null) { - links.putAll(ld.getLinks()); - for (Link link: links.keySet()) { - LinkInfo info = links.get(link); - LinkType type = ld.getLinkType(link, info); - if (type == LinkType.MULTIHOP_LINK) { - LinkWithType lwt; - - long src = link.getSrc(); - long dst = link.getDst(); - short srcPort = link.getSrcPort(); - short dstPort = link.getDstPort(); - Link otherLink = new Link(dst, dstPort, src, srcPort); - LinkInfo otherInfo = links.get(otherLink); - LinkType otherType = null; - if (otherInfo != null) - otherType = ld.getLinkType(otherLink, otherInfo); - if (otherType == LinkType.MULTIHOP_LINK) { - // This is a bi-direcitonal link. - // It is sufficient to add only one side of it. - if ((src < dst) || (src == dst && srcPort < dstPort)) { - lwt = new LinkWithType(link, - type, - LinkDirection.BIDIRECTIONAL); - returnLinkSet.add(lwt); - } - } else { - // This is a unidirectional link. - lwt = new LinkWithType(link, - type, - LinkDirection.UNIDIRECTIONAL); - returnLinkSet.add(lwt); - - } - } - } - } - return returnLinkSet; - } -} diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java deleted file mode 100644 index 093473ab4e9509a57d6a4df1742e1202c9f94d88..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery.web; - -import net.floodlightcontroller.restserver.RestletRoutable; - -import org.restlet.Context; -import org.restlet.routing.Router; - -public class LinkDiscoveryWebRoutable implements RestletRoutable { - /** - * Create the Restlet router and bind to the proper resources. - */ - @Override - public Router getRestlet(Context context) { - Router router = new Router(context); - router.attach("/autoportfast/{state}/json", AutoPortFast.class); // enable/true or disable/false - return router; - } - - /** - * Set the base path for the Topology - */ - @Override - public String basePath() { - return "/wm/linkdiscovery"; - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java deleted file mode 100644 index d95235705d016ab44bc22bbacea79302198876a5..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery.web; - -import java.io.IOException; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import org.openflow.util.HexString; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; -import net.floodlightcontroller.routing.Link; - -/** - * This class is both the datastructure and the serializer - * for a link with the corresponding type of link. - * @author alexreimers - */ -@JsonSerialize(using=LinkWithType.class) -public class LinkWithType extends JsonSerializer<LinkWithType> { - public long srcSwDpid; - public short srcPort; - public long dstSwDpid; - public short dstPort; - public LinkType type; - public LinkDirection direction; - - // Do NOT delete this, it's required for the serializer - public LinkWithType() {} - - public LinkWithType(Link link, - LinkType type, - LinkDirection direction) { - this.srcSwDpid = link.getSrc(); - this.srcPort = link.getSrcPort(); - this.dstSwDpid = link.getDst(); - this.dstPort = link.getDstPort(); - this.type = type; - this.direction = direction; - } - - @Override - public void serialize(LinkWithType lwt, JsonGenerator jgen, SerializerProvider arg2) - throws IOException, JsonProcessingException { - // You ****MUST*** use lwt for the fields as it's actually a different object. - jgen.writeStartObject(); - jgen.writeStringField("src-switch", HexString.toHexString(lwt.srcSwDpid)); - jgen.writeNumberField("src-port", lwt.srcPort); - jgen.writeStringField("dst-switch", HexString.toHexString(lwt.dstSwDpid)); - jgen.writeNumberField("dst-port", lwt.dstPort); - jgen.writeStringField("type", lwt.type.toString()); - jgen.writeStringField("direction", lwt.direction.toString()); - jgen.writeEndObject(); - } - - @Override - public Class<LinkWithType> handledType() { - return LinkWithType.class; - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java deleted file mode 100644 index 0e488ddf2e13e97c5834f6380515f7008a240916..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.linkdiscovery.web; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.routing.Link; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class LinksResource extends ServerResource { - - @Get("json") - public Set<LinkWithType> retrieve() { - ILinkDiscoveryService ld = (ILinkDiscoveryService)getContext().getAttributes(). - get(ILinkDiscoveryService.class.getCanonicalName()); - Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>(); - Set<LinkWithType> returnLinkSet = new HashSet<LinkWithType>(); - - if (ld != null) { - links.putAll(ld.getLinks()); - for (Link link: links.keySet()) { - LinkInfo info = links.get(link); - LinkType type = ld.getLinkType(link, info); - if (type == LinkType.DIRECT_LINK || type == LinkType.TUNNEL) { - LinkWithType lwt; - - long src = link.getSrc(); - long dst = link.getDst(); - short srcPort = link.getSrcPort(); - short dstPort = link.getDstPort(); - Link otherLink = new Link(dst, dstPort, src, srcPort); - LinkInfo otherInfo = links.get(otherLink); - LinkType otherType = null; - if (otherInfo != null) - otherType = ld.getLinkType(otherLink, otherInfo); - if (otherType == LinkType.DIRECT_LINK || - otherType == LinkType.TUNNEL) { - // This is a bi-direcitonal link. - // It is sufficient to add only one side of it. - if ((src < dst) || (src == dst && srcPort < dstPort)) { - lwt = new LinkWithType(link, - type, - LinkDirection.BIDIRECTIONAL); - returnLinkSet.add(lwt); - } - } else { - // This is a unidirectional link. - lwt = new LinkWithType(link, - type, - LinkDirection.UNIDIRECTIONAL); - returnLinkSet.add(lwt); - - } - } - } - } - return returnLinkSet; - } -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/ILoadBalancerService.java b/src/main/java/net/floodlightcontroller/loadbalancer/ILoadBalancerService.java deleted file mode 100644 index a335bf4daf1459b7de2764c475ad045121fd761f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/ILoadBalancerService.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.util.Collection; - -import net.floodlightcontroller.core.module.IFloodlightService; - -public interface ILoadBalancerService extends IFloodlightService { - - /** - * List all current Vips. - */ - public Collection<LBVip> listVips(); - - /** - * List selected Vip by its ID. - * @param vipId Id of requested Vip - */ - public Collection<LBVip> listVip(String vipId); - - /** - * Create and return a new Vip. - * @param LBVip vip: data structure with caller provided Vip attributes - * @return LBVip: Created Vip - */ - public LBVip createVip(LBVip vip); - - /** - * Update and return an existing Vip. - * @param LBVip vip: data structure with caller provided Vip attributes - * @return LBVip: Updated Vip - */ - public LBVip updateVip(LBVip vip); - - /** - * Remove an existing Vip. - * @param String vipId - * @return int: removal status - */ - public int removeVip(String vipId); - - /** - * List all current pools. - */ - public Collection<LBPool> listPools(); - - /** - * List selected pool by its ID. - * @param poolId Id of requested pool - */ - public Collection<LBPool> listPool(String poolId); - - /** - * Create and return a new pool. - * @param LBPool pool: data structure with caller provided pool attributes - * @return LBPool: Created pool - */ - public LBPool createPool(LBPool pool); - - /** - * Update and return an existing pool. - * @param LBPool pool: data structure with caller provided pool attributes - * @return LBPool: Updated pool - */ - public LBPool updatePool(LBPool pool); - - /** - * Remove an existing pool. - * @param String poolId - * @return int: removal status - */ - public int removePool(String poolId); - - /** - * List all current members. - */ - public Collection<LBMember> listMembers(); - - /** - * List selected member by its ID. - * @param memberId Id of requested member - */ - public Collection<LBMember> listMember(String memberId); - - /** - * List all members in a specified pool. - */ - public Collection<LBMember> listMembersByPool(String poolId); - - /** - * Create and return a new member. - * @param LBMember member: data structure with caller provided member attributes - * @return LBMember: Created member - */ - public LBMember createMember(LBMember member); - - /** - * Update and return an existing member. - * @param LBMember member: data structure with caller provided member attributes - * @return LBMember: Updated member - */ - public LBMember updateMember(LBMember member); - - /** - * Remove an existing member. - * @param String memberId - * @return int: removal status - */ - public int removeMember(String memberId); - - /** - * List all current monitors. - */ - public Collection<LBMonitor> listMonitors(); - - /** - * List selected monitor by its ID. - * @param monitorId Id of requested monitor - */ - public Collection<LBMonitor> listMonitor(String monitorId); - - /** - * Create and return a new monitor. - * @param LBMonitor monitor: data structure with caller provided monitor attributes - * @return LBMonitor: Created monitor - */ - public LBMonitor createMonitor(LBMonitor monitor); - - /** - * Update and return an existing monitor. - * @param LBMonitor monitor: data structure with caller provided pool attributes - * @return LBMonitor: Updated monitor - */ - public LBMonitor updateMonitor(LBMonitor monitor); - - /** - * Remove an existing monitor. - * @param String monitorId - * @return int: removal status - */ - public int removeMonitor(String monitorId); - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBMember.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBMember.java deleted file mode 100644 index 40569b478bd171f212d969b6e61cf9d1da3c5c12..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBMember.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -/** - * Data structure for Load Balancer based on - * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal - * - * @author KC Wang - */ - -@JsonSerialize(using=LBMemberSerializer.class) -public class LBMember { - protected String id; - protected int address; - protected short port; - protected String macString; - - protected int connectionLimit; - protected short adminState; - protected short status; - - protected String poolId; - protected String vipId; - - public LBMember() { - id = String.valueOf((int) (Math.random()*10000)); - address = 0; - macString = null; - port = 0; - - connectionLimit = 0; - adminState = 0; - status = 0; - poolId = null; - vipId = null; - } -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBMemberSerializer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBMemberSerializer.java deleted file mode 100644 index f77e8d30c38e1707241f2e54ee75558fbe19ba24..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBMemberSerializer.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; - -public class LBMemberSerializer extends JsonSerializer<LBMember>{ - - @Override - public void serialize(LBMember member, JsonGenerator jGen, - SerializerProvider serializer) throws IOException, - JsonProcessingException { - jGen.writeStartObject(); - - jGen.writeStringField("id", member.id); - jGen.writeStringField("address", String.valueOf(member.address)); - jGen.writeStringField("port", Short.toString(member.port)); - jGen.writeStringField("poolId", member.poolId); - jGen.writeStringField("vipId", member.vipId); - - jGen.writeEndObject(); - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBMonitor.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBMonitor.java deleted file mode 100644 index 72a113bc16792b5066b3d1a3cf65cdae7356f645..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBMonitor.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -/** - * Data structure for Load Balancer based on - * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal - * - * @author KC Wang - */ - -public class LBMonitor { - protected String id; - protected String name; - protected short type; - protected short delay; - protected short timeout; - protected short attemptsBeforeDeactivation; - - protected String netId; - protected int address; - protected byte protocol; - protected short port; - - //protected path?? - - protected short adminState; - protected short status; - - public LBMonitor() { - id = null; - name = null; - type = 0; - delay = 0; - timeout = 0; - attemptsBeforeDeactivation = 0; - netId = null; - address = 0; - protocol = 0; - port = 0; - adminState = 0; - status = 0; - - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java deleted file mode 100644 index 1f842aea7f12c7492eb5298e6665829817c7ce6f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.util.ArrayList; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import net.floodlightcontroller.loadbalancer.LoadBalancer.IPClient; - -/** - * Data structure for Load Balancer based on - * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal - * - * @author KC Wang - */ - - -@JsonSerialize(using=LBPoolSerializer.class) -public class LBPool { - protected String id; - protected String name; - protected String tenantId; - protected String netId; - protected short lbMethod; - protected byte protocol; - protected ArrayList<String> members; - protected ArrayList<String> monitors; - protected short adminState; - protected short status; - - protected String vipId; - - protected int previousMemberIndex; - - public LBPool() { - id = String.valueOf((int) (Math.random()*10000)); - name = null; - tenantId = null; - netId = null; - lbMethod = 0; - protocol = 0; - members = new ArrayList<String>(); - monitors = new ArrayList<String>(); - adminState = 0; - status = 0; - previousMemberIndex = -1; - } - - public String pickMember(IPClient client) { - // simple round robin for now; add different lbmethod later - if (members.size() > 0) { - previousMemberIndex = (previousMemberIndex + 1) % members.size(); - return members.get(previousMemberIndex); - } else { - return null; - } - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBPoolSerializer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBPoolSerializer.java deleted file mode 100644 index 406801a96a6c1c3173fb64881492d9fad3f60b74..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBPoolSerializer.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; - -public class LBPoolSerializer extends JsonSerializer<LBPool>{ - - @Override - public void serialize(LBPool pool, JsonGenerator jGen, - SerializerProvider serializer) throws IOException, - JsonProcessingException { - jGen.writeStartObject(); - - jGen.writeStringField("name", pool.name); - jGen.writeStringField("id", pool.id); - jGen.writeStringField("vipId", pool.vipId); - - for (int i=0; i<pool.members.size(); i++) - jGen.writeStringField("pool", pool.members.get(i)); - - jGen.writeEndObject(); - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBStats.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBStats.java deleted file mode 100644 index 8f6a5251b60bd17cd789603bb3620e1b52bc38d7..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBStats.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -/** - * Data structure for Load Balancer based on - * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal - * - * @author KC Wang - */ - -public class LBStats { - protected int bytesIn; - protected int bytesOut; - protected int activeConnections; - protected int totalConnections; - - public LBStats() { - bytesIn = 0; - bytesOut = 0; - activeConnections = 0; - totalConnections = 0; - } -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java deleted file mode 100644 index 1d0a9bdadd16cca75dccb00cb3251cd4b160e59b..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.util.ArrayList; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import net.floodlightcontroller.loadbalancer.LoadBalancer.IPClient; -import net.floodlightcontroller.util.MACAddress; - -/** - * Data structure for Load Balancer based on - * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal - * - * @author KC Wang - */ - -@JsonSerialize(using=LBVipSerializer.class) -public class LBVip { - protected String id; - protected String name; - protected String tenantId; - protected String netId; - protected int address; - protected byte protocol; - protected short lbMethod; - protected short port; - protected ArrayList<String> pools; - protected boolean sessionPersistence; - protected int connectionLimit; - protected short adminState; - protected short status; - - protected MACAddress proxyMac; - - public static String LB_PROXY_MAC= "12:34:56:78:90:12"; - - public LBVip() { - this.id = String.valueOf((int) (Math.random()*10000)); - this.name = null; - this.tenantId = null; - this.netId = null; - this.address = 0; - this.protocol = 0; - this.lbMethod = 0; - this.port = 0; - this.pools = new ArrayList<String>(); - this.sessionPersistence = false; - this.connectionLimit = 0; - this.address = 0; - this.status = 0; - - this.proxyMac = MACAddress.valueOf(LB_PROXY_MAC); - } - - public String pickPool(IPClient client) { - // for now, return the first pool; consider different pool choice policy later - if (pools.size() > 0) - return pools.get(0); - else - return null; - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBVipSerializer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBVipSerializer.java deleted file mode 100644 index 9a853b37d317abe899a8888b4c0e42c4e29fa00f..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBVipSerializer.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; - -public class LBVipSerializer extends JsonSerializer<LBVip>{ - - @Override - public void serialize(LBVip vip, JsonGenerator jGen, - SerializerProvider serializer) throws IOException, - JsonProcessingException { - jGen.writeStartObject(); - - jGen.writeStringField("name", vip.name); - jGen.writeStringField("id", vip.id); - jGen.writeStringField("address", String.valueOf(vip.address)); - jGen.writeStringField("protocol", Byte.toString(vip.protocol)); - jGen.writeStringField("port", Short.toString(vip.port)); - - jGen.writeEndObject(); - } - - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java deleted file mode 100644 index dabcef1e556231fdbb3c19d3496d5236e9714494..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java +++ /dev/null @@ -1,1331 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionDataLayerDestination; -import org.openflow.protocol.action.OFActionDataLayerSource; -import org.openflow.protocol.action.OFActionEnqueue; -import org.openflow.protocol.action.OFActionNetworkLayerDestination; -import org.openflow.protocol.action.OFActionNetworkLayerSource; -import org.openflow.protocol.action.OFActionNetworkTypeOfService; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.action.OFActionStripVirtualLan; -import org.openflow.protocol.action.OFActionTransportLayerDestination; -import org.openflow.protocol.action.OFActionTransportLayerSource; -import org.openflow.protocol.action.OFActionVirtualLanIdentifier; -import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint; -import org.openflow.util.HexString; -import org.openflow.util.U16; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.packet.ARP; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.ICMP; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.TCP; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; -import net.floodlightcontroller.util.MACAddress; -import net.floodlightcontroller.util.OFMessageDamper; - -/** - * A simple load balancer module for ping, tcp, and udp flows. This module is accessed - * via a REST API defined close to the OpenStack Quantum LBaaS (Load-balancer-as-a-Service) - * v1.0 API proposal. Since the proposal has not been final, no efforts have yet been - * made to confirm compatibility at this time. - * - * Limitations: - * - client records and static flows not purged after use, will exhaust switch flow tables over time - * - round robin policy among servers based on connections, not traffic volume - * - health monitoring feature not implemented yet - * - * @author kcwang - */ -public class LoadBalancer implements IFloodlightModule, - ILoadBalancerService, IOFMessageListener { - - protected static Logger log = LoggerFactory.getLogger(LoadBalancer.class); - - // Our dependencies - protected IFloodlightProviderService floodlightProvider; - protected IRestApiService restApi; - - protected ICounterStoreService counterStore; - protected OFMessageDamper messageDamper; - protected IDeviceService deviceManager; - protected IRoutingService routingEngine; - protected ITopologyService topology; - protected IStaticFlowEntryPusherService sfp; - - protected HashMap<String, LBVip> vips; - protected HashMap<String, LBPool> pools; - protected HashMap<String, LBMember> members; - protected HashMap<Integer, String> vipIpToId; - protected HashMap<Integer, MACAddress> vipIpToMac; - protected HashMap<Integer, String> memberIpToId; - protected HashMap<IPClient, LBMember> clientToMember; - - //Copied from Forwarding with message damper routine for pushing proxy Arp - protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // ms. - protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms - protected static String LB_ETHER_TYPE = "0x800"; - protected static int LB_PRIORITY = 32768; - - // Comparator for sorting by SwitchCluster - public Comparator<SwitchPort> clusterIdComparator = - new Comparator<SwitchPort>() { - @Override - public int compare(SwitchPort d1, SwitchPort d2) { - Long d1ClusterId = - topology.getL2DomainId(d1.getSwitchDPID()); - Long d2ClusterId = - topology.getL2DomainId(d2.getSwitchDPID()); - return d1ClusterId.compareTo(d2ClusterId); - } - }; - - // data structure for storing connected - public class IPClient { - int ipAddress; - byte nw_proto; - short srcPort; // tcp/udp src port. icmp type (OFMatch convention) - short targetPort; // tcp/udp dst port, icmp code (OFMatch convention) - - public IPClient() { - ipAddress = 0; - nw_proto = 0; - srcPort = -1; - targetPort = -1; - } - } - - @Override - public String getName() { - return "loadbalancer"; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return (type.equals(OFType.PACKET_IN) && - (name.equals("topology") || - name.equals("devicemanager") || - name.equals("virtualizer"))); - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")); - } - - @Override - public net.floodlightcontroller.core.IListener.Command - receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - return processPacketIn(sw, (OFPacketIn)msg, cntx); - default: - break; - } - log.warn("Received unexpected message {}", msg); - return Command.CONTINUE; - } - - private net.floodlightcontroller.core.IListener.Command - processPacketIn(IOFSwitch sw, OFPacketIn pi, - FloodlightContext cntx) { - - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - IPacket pkt = eth.getPayload(); - - if (eth.isBroadcast() || eth.isMulticast()) { - // handle ARP for VIP - if (pkt instanceof ARP) { - // retrieve arp to determine target IP address - ARP arpRequest = (ARP) eth.getPayload(); - - int targetProtocolAddress = IPv4.toIPv4Address(arpRequest - .getTargetProtocolAddress()); - - if (vipIpToId.containsKey(targetProtocolAddress)) { - String vipId = vipIpToId.get(targetProtocolAddress); - vipProxyArpReply(sw, pi, cntx, vipId); - return Command.STOP; - } - } - } else { - // currently only load balance IPv4 packets - no-op for other traffic - if (pkt instanceof IPv4) { - IPv4 ip_pkt = (IPv4) pkt; - - // If match Vip and port, check pool and choose member - int destIpAddress = ip_pkt.getDestinationAddress(); - - if (vipIpToId.containsKey(destIpAddress)){ - IPClient client = new IPClient(); - client.ipAddress = ip_pkt.getSourceAddress(); - client.nw_proto = ip_pkt.getProtocol(); - if (ip_pkt.getPayload() instanceof TCP) { - TCP tcp_pkt = (TCP) ip_pkt.getPayload(); - client.srcPort = tcp_pkt.getSourcePort(); - client.targetPort = tcp_pkt.getDestinationPort(); - } - if (ip_pkt.getPayload() instanceof UDP) { - UDP udp_pkt = (UDP) ip_pkt.getPayload(); - client.srcPort = udp_pkt.getSourcePort(); - client.targetPort = udp_pkt.getDestinationPort(); - } - if (ip_pkt.getPayload() instanceof ICMP) { - client.srcPort = 8; - client.targetPort = 0; - } - - LBVip vip = vips.get(vipIpToId.get(destIpAddress)); - LBPool pool = pools.get(vip.pickPool(client)); - LBMember member = members.get(pool.pickMember(client)); - - // for chosen member, check device manager and find and push routes, in both directions - pushBidirectionalVipRoutes(sw, pi, cntx, client, member); - - // packet out based on table rule - pushPacket(pkt, sw, pi.getBufferId(), pi.getInPort(), OFPort.OFPP_TABLE.getValue(), - cntx, true); - - return Command.STOP; - } - } - } - // bypass non-load-balanced traffic for normal processing (forwarding) - return Command.CONTINUE; - } - - /** - * used to send proxy Arp for load balanced service requests - * @param IOFSwitch sw - * @param OFPacketIn pi - * @param FloodlightContext cntx - * @param String vipId - */ - - protected void vipProxyArpReply(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, String vipId) { - log.debug("vipProxyArpReply"); - - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - // retrieve original arp to determine host configured gw IP address - if (! (eth.getPayload() instanceof ARP)) - return; - ARP arpRequest = (ARP) eth.getPayload(); - - // have to do proxy arp reply since at this point we cannot determine the requesting application type - byte[] vipProxyMacBytes = vips.get(vipId).proxyMac.toBytes(); - - // generate proxy ARP reply - IPacket arpReply = new Ethernet() - .setSourceMACAddress(vipProxyMacBytes) - .setDestinationMACAddress(eth.getSourceMACAddress()) - .setEtherType(Ethernet.TYPE_ARP) - .setVlanID(eth.getVlanID()) - .setPriorityCode(eth.getPriorityCode()) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REPLY) - .setSenderHardwareAddress(vipProxyMacBytes) - .setSenderProtocolAddress( - arpRequest.getTargetProtocolAddress()) - .setTargetHardwareAddress( - eth.getSourceMACAddress()) - .setTargetProtocolAddress( - arpRequest.getSenderProtocolAddress())); - - // push ARP reply out - pushPacket(arpReply, sw, OFPacketOut.BUFFER_ID_NONE, OFPort.OFPP_NONE.getValue(), - pi.getInPort(), cntx, true); - log.debug("proxy ARP reply pushed as {}", IPv4.fromIPv4Address(vips.get(vipId).address)); - - return; - } - - /** - * used to push any packet - borrowed routine from Forwarding - * - * @param OFPacketIn pi - * @param IOFSwitch sw - * @param int bufferId - * @param short inPort - * @param short outPort - * @param FloodlightContext cntx - * @param boolean flush - */ - public void pushPacket(IPacket packet, - IOFSwitch sw, - int bufferId, - short inPort, - short outPort, - FloodlightContext cntx, - boolean flush) { - if (log.isTraceEnabled()) { - log.trace("PacketOut srcSwitch={} inPort={} outPort={}", - new Object[] {sw, inPort, outPort}); - } - - OFPacketOut po = - (OFPacketOut) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.PACKET_OUT); - - // set actions - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(new OFActionOutput(outPort, (short) 0xffff)); - - po.setActions(actions) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); - short poLength = - (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); - - // set buffer_id, in_port - po.setBufferId(bufferId); - po.setInPort(inPort); - - // set data - only if buffer_id == -1 - if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { - if (packet == null) { - log.error("BufferId is not set and packet data is null. " + - "Cannot send packetOut. " + - "srcSwitch={} inPort={} outPort={}", - new Object[] {sw, inPort, outPort}); - return; - } - byte[] packetData = packet.serialize(); - poLength += packetData.length; - po.setPacketData(packetData); - } - - po.setLength(poLength); - - try { - counterStore.updatePktOutFMCounterStoreLocal(sw, po); - messageDamper.write(sw, po, cntx, flush); - } catch (IOException e) { - log.error("Failure writing packet out", e); - } - } - - /** - * used to find and push in-bound and out-bound routes using StaticFlowEntryPusher - * @param IOFSwitch sw - * @param OFPacketIn pi - * @param FloodlightContext cntx - * @param IPClient client - * @param LBMember member - */ - protected void pushBidirectionalVipRoutes(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, IPClient client, LBMember member) { - - // borrowed code from Forwarding to retrieve src and dst device entities - // Check if we have the location of the destination - IDevice srcDevice = null; - IDevice dstDevice = null; - - // retrieve all known devices - Collection<? extends IDevice> allDevices = deviceManager - .getAllDevices(); - - for (IDevice d : allDevices) { - for (int j = 0; j < d.getIPv4Addresses().length; j++) { - if (srcDevice == null && client.ipAddress == d.getIPv4Addresses()[j]) - srcDevice = d; - if (dstDevice == null && member.address == d.getIPv4Addresses()[j]) { - dstDevice = d; - member.macString = dstDevice.getMACAddressString(); - } - if (srcDevice != null && dstDevice != null) - break; - } - } - - // srcDevice and/or dstDevice is null, no route can be pushed - if (srcDevice == null || dstDevice == null) return; - - Long srcIsland = topology.getL2DomainId(sw.getId()); - - if (srcIsland == null) { - log.debug("No openflow island found for source {}/{}", - sw.getStringId(), pi.getInPort()); - return; - } - - // Validate that we have a destination known on the same island - // Validate that the source and destination are not on the same switchport - boolean on_same_island = false; - boolean on_same_if = false; - for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) { - long dstSwDpid = dstDap.getSwitchDPID(); - Long dstIsland = topology.getL2DomainId(dstSwDpid); - if ((dstIsland != null) && dstIsland.equals(srcIsland)) { - on_same_island = true; - if ((sw.getId() == dstSwDpid) && - (pi.getInPort() == dstDap.getPort())) { - on_same_if = true; - } - break; - } - } - - if (!on_same_island) { - // Flood since we don't know the dst device - if (log.isTraceEnabled()) { - log.trace("No first hop island found for destination " + - "device {}, Action = flooding", dstDevice); - } - return; - } - - if (on_same_if) { - if (log.isTraceEnabled()) { - log.trace("Both source and destination are on the same " + - "switch/port {}/{}, Action = NOP", - sw.toString(), pi.getInPort()); - } - return; - } - - // Install all the routes where both src and dst have attachment - // points. Since the lists are stored in sorted order we can - // traverse the attachment points in O(m+n) time - SwitchPort[] srcDaps = srcDevice.getAttachmentPoints(); - Arrays.sort(srcDaps, clusterIdComparator); - SwitchPort[] dstDaps = dstDevice.getAttachmentPoints(); - Arrays.sort(dstDaps, clusterIdComparator); - - int iSrcDaps = 0, iDstDaps = 0; - - // following Forwarding's same routing routine, retrieve both in-bound and out-bound routes for - // all clusters. - while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) { - SwitchPort srcDap = srcDaps[iSrcDaps]; - SwitchPort dstDap = dstDaps[iDstDaps]; - Long srcCluster = - topology.getL2DomainId(srcDap.getSwitchDPID()); - Long dstCluster = - topology.getL2DomainId(dstDap.getSwitchDPID()); - - int srcVsDest = srcCluster.compareTo(dstCluster); - if (srcVsDest == 0) { - if (!srcDap.equals(dstDap) && - (srcCluster != null) && - (dstCluster != null)) { - Route routeIn = - routingEngine.getRoute(srcDap.getSwitchDPID(), - (short)srcDap.getPort(), - dstDap.getSwitchDPID(), - (short)dstDap.getPort(), 0); - Route routeOut = - routingEngine.getRoute(dstDap.getSwitchDPID(), - (short)dstDap.getPort(), - srcDap.getSwitchDPID(), - (short)srcDap.getPort(), 0); - - // use static flow entry pusher to push flow mod along in and out path - // in: match src client (ip, port), rewrite dest from vip ip/port to member ip/port, forward - // out: match dest client (ip, port), rewrite src from member ip/port to vip ip/port, forward - - if (routeIn != null) { - pushStaticVipRoute(true, routeIn, client, member, sw.getId()); - } - - if (routeOut != null) { - pushStaticVipRoute(false, routeOut, client, member, sw.getId()); - } - - } - iSrcDaps++; - iDstDaps++; - } else if (srcVsDest < 0) { - iSrcDaps++; - } else { - iDstDaps++; - } - } - return; - } - - /** - * used to push given route using static flow entry pusher - * @param boolean inBound - * @param Route route - * @param IPClient client - * @param LBMember member - * @param long pinSwitch - */ - public void pushStaticVipRoute(boolean inBound, Route route, IPClient client, LBMember member, long pinSwitch) { - List<NodePortTuple> path = route.getPath(); - if (path.size()>0) { - for (int i = 0; i < path.size(); i+=2) { - - long sw = path.get(i).getNodeId(); - String swString = HexString.toHexString(path.get(i).getNodeId()); - String entryName; - String matchString = null; - String actionString = null; - - OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD); - - fm.setIdleTimeout((short) 0); // infinite - fm.setHardTimeout((short) 0); // infinite - fm.setBufferId(OFPacketOut.BUFFER_ID_NONE); - fm.setCommand((short) 0); - fm.setFlags((short) 0); - fm.setOutPort(OFPort.OFPP_NONE.getValue()); - fm.setCookie((long) 0); - fm.setPriority(Short.MAX_VALUE); - - if (inBound) { - entryName = "inbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort - +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw; - matchString = "nw_src="+IPv4.fromIPv4Address(client.ipAddress)+"," - + "nw_proto="+String.valueOf(client.nw_proto)+"," - + "tp_src="+String.valueOf(client.srcPort & 0xffff)+"," - + "dl_type="+LB_ETHER_TYPE+"," - + "in_port="+String.valueOf(path.get(i).getPortId()); - - if (sw == pinSwitch) { - actionString = "set-dst-ip="+IPv4.fromIPv4Address(member.address)+"," - + "set-dst-mac="+member.macString+"," - + "output="+path.get(i+1).getPortId(); - } else { - actionString = - "output="+path.get(i+1).getPortId(); - } - } else { - entryName = "outbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort - +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw; - matchString = "nw_dst="+IPv4.fromIPv4Address(client.ipAddress)+"," - + "nw_proto="+String.valueOf(client.nw_proto)+"," - + "tp_dst="+String.valueOf(client.srcPort & 0xffff)+"," - + "dl_type="+LB_ETHER_TYPE+"," - + "in_port="+String.valueOf(path.get(i).getPortId()); - - if (sw == pinSwitch) { - actionString = "set-src-ip="+IPv4.fromIPv4Address(vips.get(member.vipId).address)+"," - + "set-src-mac="+vips.get(member.vipId).proxyMac.toString()+"," - + "output="+path.get(i+1).getPortId(); - } else { - actionString = "output="+path.get(i+1).getPortId(); - } - - } - - parseActionString(fm, actionString, log); - - fm.setPriority(U16.t(LB_PRIORITY)); - - OFMatch ofMatch = new OFMatch(); - try { - ofMatch.fromString(matchString); - } catch (IllegalArgumentException e) { - log.debug("ignoring flow entry {} on switch {} with illegal OFMatch() key: " - + matchString, entryName, swString); - } - - fm.setMatch(ofMatch); - sfp.addFlow(entryName, fm, swString); - - } - } - return; - } - - - @Override - public Collection<LBVip> listVips() { - return vips.values(); - } - - @Override - public Collection<LBVip> listVip(String vipId) { - Collection<LBVip> result = new HashSet<LBVip>(); - result.add(vips.get(vipId)); - return result; - } - - @Override - public LBVip createVip(LBVip vip) { - if (vip == null) - vip = new LBVip(); - - vips.put(vip.id, vip); - vipIpToId.put(vip.address, vip.id); - vipIpToMac.put(vip.address, vip.proxyMac); - - return vip; - } - - @Override - public LBVip updateVip(LBVip vip) { - vips.put(vip.id, vip); - return vip; - } - - @Override - public int removeVip(String vipId) { - if(vips.containsKey(vipId)){ - vips.remove(vipId); - return 0; - } else { - return -1; - } - } - - @Override - public Collection<LBPool> listPools() { - return pools.values(); - } - - @Override - public Collection<LBPool> listPool(String poolId) { - Collection<LBPool> result = new HashSet<LBPool>(); - result.add(pools.get(poolId)); - return result; - } - - @Override - public LBPool createPool(LBPool pool) { - if (pool==null) - pool = new LBPool(); - - pools.put(pool.id, pool); - if (pool.vipId != null && vips.containsKey(pool.vipId)) - vips.get(pool.vipId).pools.add(pool.id); - else { - log.error("specified vip-id must exist"); - pool.vipId = null; - pools.put(pool.id, pool); - } - return pool; - } - - @Override - public LBPool updatePool(LBPool pool) { - pools.put(pool.id, pool); - return null; - } - - @Override - public int removePool(String poolId) { - LBPool pool; - if(pools!=null){ - pool = pools.get(poolId); - if (pool.vipId != null) - vips.get(pool.vipId).pools.remove(poolId); - pools.remove(poolId); - return 0; - } else { - return -1; - } - } - - @Override - public Collection<LBMember> listMembers() { - return members.values(); - } - - @Override - public Collection<LBMember> listMember(String memberId) { - Collection<LBMember> result = new HashSet<LBMember>(); - result.add(members.get(memberId)); - return result; - } - - @Override - public Collection<LBMember> listMembersByPool(String poolId) { - Collection<LBMember> result = new HashSet<LBMember>(); - - if(pools.containsKey(poolId)) { - ArrayList<String> memberIds = pools.get(poolId).members; - for (int i=0; i<memberIds.size(); i++) - result.add(members.get(memberIds.get(i))); - } - return result; - } - - @Override - public LBMember createMember(LBMember member) { - if (member == null) - member = new LBMember(); - - members.put(member.id, member); - memberIpToId.put(member.address, member.id); - - if (member.poolId != null && pools.get(member.poolId) != null) { - member.vipId = pools.get(member.poolId).vipId; - if (!pools.get(member.poolId).members.contains(member.id)) - pools.get(member.poolId).members.add(member.id); - } else - log.error("member must be specified with non-null pool_id"); - - return member; - } - - @Override - public LBMember updateMember(LBMember member) { - members.put(member.id, member); - return member; - } - - @Override - public int removeMember(String memberId) { - LBMember member; - member = members.get(memberId); - - if(member != null){ - if (member.poolId != null) - pools.get(member.poolId).members.remove(memberId); - members.remove(memberId); - return 0; - } else { - return -1; - } - } - - @Override - public Collection<LBMonitor> listMonitors() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Collection<LBMonitor> listMonitor(String monitorId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public LBMonitor createMonitor(LBMonitor monitor) { - // TODO Auto-generated method stub - return null; - } - - @Override - public LBMonitor updateMonitor(LBMonitor monitor) { - // TODO Auto-generated method stub - return null; - } - - @Override - public int removeMonitor(String monitorId) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(ILoadBalancerService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(ILoadBalancerService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IRestApiService.class); - l.add(ICounterStoreService.class); - l.add(IDeviceService.class); - l.add(ITopologyService.class); - l.add(IRoutingService.class); - l.add(IStaticFlowEntryPusherService.class); - - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); - restApi = context.getServiceImpl(IRestApiService.class); - counterStore = context.getServiceImpl(ICounterStoreService.class); - deviceManager = context.getServiceImpl(IDeviceService.class); - routingEngine = context.getServiceImpl(IRoutingService.class); - topology = context.getServiceImpl(ITopologyService.class); - sfp = context.getServiceImpl(IStaticFlowEntryPusherService.class); - - messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, - EnumSet.of(OFType.FLOW_MOD), - OFMESSAGE_DAMPER_TIMEOUT); - - vips = new HashMap<String, LBVip>(); - pools = new HashMap<String, LBPool>(); - members = new HashMap<String, LBMember>(); - vipIpToId = new HashMap<Integer, String>(); - vipIpToMac = new HashMap<Integer, MACAddress>(); - memberIpToId = new HashMap<Integer, String>(); - } - - @Override - public void startUp(FloodlightModuleContext context) { - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - restApi.addRestletRoutable(new LoadBalancerWebRoutable()); - } - - // Utilities borrowed from StaticFlowEntries - - private static class SubActionStruct { - OFAction action; - int len; - } - - /** - * Parses OFFlowMod actions from strings. - * @param flowMod The OFFlowMod to set the actions for - * @param actionstr The string containing all the actions - * @param log A logger to log for errors. - */ - public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) { - List<OFAction> actions = new LinkedList<OFAction>(); - int actionsLength = 0; - if (actionstr != null) { - actionstr = actionstr.toLowerCase(); - for (String subaction : actionstr.split(",")) { - String action = subaction.split("[=:]")[0]; - SubActionStruct subaction_struct = null; - - if (action.equals("output")) { - subaction_struct = decode_output(subaction, log); - } - else if (action.equals("enqueue")) { - subaction_struct = decode_enqueue(subaction, log); - } - else if (action.equals("strip-vlan")) { - subaction_struct = decode_strip_vlan(subaction, log); - } - else if (action.equals("set-vlan-id")) { - subaction_struct = decode_set_vlan_id(subaction, log); - } - else if (action.equals("set-vlan-priority")) { - subaction_struct = decode_set_vlan_priority(subaction, log); - } - else if (action.equals("set-src-mac")) { - subaction_struct = decode_set_src_mac(subaction, log); - } - else if (action.equals("set-dst-mac")) { - subaction_struct = decode_set_dst_mac(subaction, log); - } - else if (action.equals("set-tos-bits")) { - subaction_struct = decode_set_tos_bits(subaction, log); - } - else if (action.equals("set-src-ip")) { - subaction_struct = decode_set_src_ip(subaction, log); - } - else if (action.equals("set-dst-ip")) { - subaction_struct = decode_set_dst_ip(subaction, log); - } - else if (action.equals("set-src-port")) { - subaction_struct = decode_set_src_port(subaction, log); - } - else if (action.equals("set-dst-port")) { - subaction_struct = decode_set_dst_port(subaction, log); - } - else { - log.error("Unexpected action '{}', '{}'", action, subaction); - } - - if (subaction_struct != null) { - actions.add(subaction_struct.action); - actionsLength += subaction_struct.len; - } - } - } - log.debug("action {}", actions); - - flowMod.setActions(actions); - flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLength); - } - - private static SubActionStruct decode_output(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n; - - n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction); - if (n.matches()) { - OFActionOutput action = new OFActionOutput(); - action.setMaxLength(Short.MAX_VALUE); - short port = OFPort.OFPP_NONE.getValue(); - if (n.group(1) != null) { - try { - port = get_short(n.group(1)); - } - catch (NumberFormatException e) { - log.debug("Invalid port in: '{}' (error ignored)", subaction); - return null; - } - } - else if (n.group(2) != null) - port = OFPort.OFPP_ALL.getValue(); - else if (n.group(3) != null) - port = OFPort.OFPP_CONTROLLER.getValue(); - else if (n.group(4) != null) - port = OFPort.OFPP_LOCAL.getValue(); - else if (n.group(5) != null) - port = OFPort.OFPP_IN_PORT.getValue(); - else if (n.group(6) != null) - port = OFPort.OFPP_NORMAL.getValue(); - else if (n.group(7) != null) - port = OFPort.OFPP_FLOOD.getValue(); - action.setPort(port); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionOutput.MINIMUM_LENGTH; - } - else { - log.error("Invalid subaction: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_enqueue(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n; - - n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction); - if (n.matches()) { - short portnum = 0; - if (n.group(1) != null) { - try { - portnum = get_short(n.group(1)); - } - catch (NumberFormatException e) { - log.debug("Invalid port-num in: '{}' (error ignored)", subaction); - return null; - } - } - - int queueid = 0; - if (n.group(2) != null) { - try { - queueid = get_int(n.group(2)); - } - catch (NumberFormatException e) { - log.debug("Invalid queue-id in: '{}' (error ignored)", subaction); - return null; - } - } - - OFActionEnqueue action = new OFActionEnqueue(); - action.setPort(portnum); - action.setQueueId(queueid); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionEnqueue.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_strip_vlan(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("strip-vlan").matcher(subaction); - - if (n.matches()) { - OFActionStripVirtualLan action = new OFActionStripVirtualLan(); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionStripVirtualLan.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - short vlanid = get_short(n.group(1)); - OFActionVirtualLanIdentifier action = new OFActionVirtualLanIdentifier(); - action.setVirtualLanIdentifier(vlanid); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionVirtualLanIdentifier.MINIMUM_LENGTH; - } - catch (NumberFormatException e) { - log.debug("Invalid VLAN in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - byte prior = get_byte(n.group(1)); - OFActionVirtualLanPriorityCodePoint action = new OFActionVirtualLanPriorityCodePoint(); - action.setVirtualLanPriorityCodePoint(prior); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH; - } - catch (NumberFormatException e) { - log.debug("Invalid VLAN priority in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_src_mac(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); - - if (n.matches()) { - byte[] macaddr = get_mac_addr(n, subaction, log); - if (macaddr != null) { - OFActionDataLayerSource action = new OFActionDataLayerSource(); - action.setDataLayerAddress(macaddr); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionDataLayerSource.MINIMUM_LENGTH; - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); - - if (n.matches()) { - byte[] macaddr = get_mac_addr(n, subaction, log); - if (macaddr != null) { - OFActionDataLayerDestination action = new OFActionDataLayerDestination(); - action.setDataLayerAddress(macaddr); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionDataLayerDestination.MINIMUM_LENGTH; - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - byte tosbits = get_byte(n.group(1)); - OFActionNetworkTypeOfService action = new OFActionNetworkTypeOfService(); - action.setNetworkTypeOfService(tosbits); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionNetworkTypeOfService.MINIMUM_LENGTH; - } - catch (NumberFormatException e) { - log.debug("Invalid dst-port in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_src_ip(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction); - - if (n.matches()) { - int ipaddr = get_ip_addr(n, subaction, log); - OFActionNetworkLayerSource action = new OFActionNetworkLayerSource(); - action.setNetworkAddress(ipaddr); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionNetworkLayerSource.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction); - - if (n.matches()) { - int ipaddr = get_ip_addr(n, subaction, log); - OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination(); - action.setNetworkAddress(ipaddr); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionNetworkLayerDestination.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_src_port(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - short portnum = get_short(n.group(1)); - OFActionTransportLayerSource action = new OFActionTransportLayerSource(); - action.setTransportPort(portnum); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionTransportLayerSource.MINIMUM_LENGTH;; - } - catch (NumberFormatException e) { - log.debug("Invalid src-port in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_dst_port(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - short portnum = get_short(n.group(1)); - OFActionTransportLayerDestination action = new OFActionTransportLayerDestination(); - action.setTransportPort(portnum); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionTransportLayerDestination.MINIMUM_LENGTH;; - } - catch (NumberFormatException e) { - log.debug("Invalid dst-port in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) { - byte[] macaddr = new byte[6]; - - for (int i=0; i<6; i++) { - if (n.group(i+1) != null) { - try { - macaddr[i] = get_byte("0x" + n.group(i+1)); - } - catch (NumberFormatException e) { - log.debug("Invalid src-mac in: '{}' (error ignored)", subaction); - return null; - } - } - else { - log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction); - return null; - } - } - - return macaddr; - } - - private static int get_ip_addr(Matcher n, String subaction, Logger log) { - int ipaddr = 0; - - for (int i=0; i<4; i++) { - if (n.group(i+1) != null) { - try { - ipaddr = ipaddr<<8; - ipaddr = ipaddr | get_int(n.group(i+1)); - } - catch (NumberFormatException e) { - log.debug("Invalid src-ip in: '{}' (error ignored)", subaction); - return 0; - } - } - else { - log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction); - return 0; - } - } - - return ipaddr; - } - - // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0) - private static int get_int(String str) { - return Integer.decode(str); - } - - // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0) - private static short get_short(String str) { - return (short)(int)Integer.decode(str); - } - - // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0) - private static byte get_byte(String str) { - return Integer.decode(str).byteValue(); - } - - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java deleted file mode 100644 index 52c5f567d0b7b59443de7c615dc7832317554c9a..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -import net.floodlightcontroller.restserver.RestletRoutable; -import net.floodlightcontroller.virtualnetwork.NoOp; - -public class LoadBalancerWebRoutable implements RestletRoutable { - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/vips/", VipsResource.class); // GET, POST - router.attach("/vips/{vip}", VipsResource.class); // GET, PUT, DELETE - router.attach("/pools/", PoolsResource.class); // GET, POST - router.attach("/pools/{pool}", PoolsResource.class); // GET, PUT, DELETE - router.attach("/members/", MembersResource.class); // GET, POST - router.attach("/members/{member}", MembersResource.class); // GET, PUT, DELETE - router.attach("/pools/{pool}/members", PoolMemberResource.class); //GET - router.attach("/health_monitors/", MonitorsResource.class); //GET, POST - router.attach("/health_monitors/{monitor}", MonitorsResource.class); //GET, PUT, DELETE - router.attachDefault(NoOp.class); - return router; - } - - @Override - public String basePath() { - return "/quantum/v1.0"; - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java deleted file mode 100644 index b18ad040f4e7bdbb1b07b42176413573893d0b5e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; -import java.util.Collection; - -import net.floodlightcontroller.packet.IPv4; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.restlet.resource.Put; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MembersResource extends ServerResource { - - protected static Logger log = LoggerFactory.getLogger(MembersResource.class); - - @Get("json") - public Collection <LBMember> retrieve() { - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String memberId = (String) getRequestAttributes().get("member"); - if (memberId!=null) - return lbs.listMember(memberId); - else - return lbs.listMembers(); - } - - @Put - @Post - public LBMember createMember(String postData) { - - LBMember member=null; - try { - member=jsonToMember(postData); - } catch (IOException e) { - log.error("Could not parse JSON {}", e.getMessage()); - } - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String memberId = (String) getRequestAttributes().get("member"); - if (memberId != null) - return lbs.updateMember(member); - else - return lbs.createMember(member); - } - - @Delete - public int removeMember() { - - String memberId = (String) getRequestAttributes().get("member"); - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - return lbs.removeMember(memberId); - } - - protected LBMember jsonToMember(String json) throws IOException { - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - LBMember member = new LBMember(); - - try { - jp = f.createJsonParser(json); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - if (n.equals("id")) { - member.id = jp.getText(); - continue; - } else - if (n.equals("address")) { - member.address = IPv4.toIPv4Address(jp.getText()); - continue; - } else - if (n.equals("port")) { - member.port = Short.parseShort(jp.getText()); - continue; - } else - if (n.equals("connection_limit")) { - member.connectionLimit = Integer.parseInt(jp.getText()); - continue; - } else - if (n.equals("admin_state")) { - member.adminState = Short.parseShort(jp.getText()); - continue; - } else - if (n.equals("status")) { - member.status = Short.parseShort(jp.getText()); - continue; - } else - if (n.equals("pool_id")) { - member.poolId = jp.getText(); - continue; - } - - log.warn("Unrecognized field {} in " + - "parsing Members", - jp.getText()); - } - jp.close(); - - return member; - } -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/MonitorsResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/MonitorsResource.java deleted file mode 100644 index 94e722cfdce9aec875f7f327d54ee4a8c3a01596..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/MonitorsResource.java +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; -import java.util.Collection; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; - -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.restlet.resource.Put; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MonitorsResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(MonitorsResource.class); - - @Get("json") - public Collection <LBMonitor> retrieve() { - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String monitorId = (String) getRequestAttributes().get("monitor"); - if (monitorId!=null) - return lbs.listMonitor(monitorId); - else - return lbs.listMonitors(); - } - - @Put - @Post - public LBMonitor createMonitor(String postData) { - - LBMonitor monitor=null; - try { - monitor=jsonToMonitor(postData); - } catch (IOException e) { - log.error("Could not parse JSON {}", e.getMessage()); - } - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String monitorId = (String) getRequestAttributes().get("monitor"); - if (monitorId != null) - return lbs.updateMonitor(monitor); - else - return lbs.createMonitor(monitor); - } - - @Delete - public int removeMonitor() { - - String monitorId = (String) getRequestAttributes().get("monitor"); - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - return lbs.removeMonitor(monitorId); - } - - protected LBMonitor jsonToMonitor(String json) throws IOException { - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - LBMonitor monitor = new LBMonitor(); - - try { - jp = f.createJsonParser(json); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - else if (n.equals("monitor")) { - while (jp.nextToken() != JsonToken.END_OBJECT) { - String field = jp.getCurrentName(); - - if (field.equals("id")) { - monitor.id = jp.getText(); - continue; - } - if (field.equals("name")) { - monitor.name = jp.getText(); - continue; - } - if (field.equals("type")) { - monitor.type = Short.parseShort(jp.getText()); - continue; - } - if (field.equals("delay")) { - monitor.delay = Short.parseShort(jp.getText()); - continue; - } - if (field.equals("timeout")) { - monitor.timeout = Short.parseShort(jp.getText()); - continue; - } - if (field.equals("attempts_before_deactivation")) { - monitor.attemptsBeforeDeactivation = Short.parseShort(jp.getText()); - continue; - } - if (field.equals("network_id")) { - monitor.netId = jp.getText(); - continue; - } - if (field.equals("address")) { - monitor.address = Integer.parseInt(jp.getText()); - continue; - } - if (field.equals("protocol")) { - monitor.protocol = Byte.parseByte(jp.getText()); - continue; - } - if (field.equals("port")) { - monitor.port = Short.parseShort(jp.getText()); - continue; - } - if (field.equals("admin_state")) { - monitor.adminState = Short.parseShort(jp.getText()); - continue; - } - if (field.equals("status")) { - monitor.status = Short.parseShort(jp.getText()); - continue; - } - - log.warn("Unrecognized field {} in " + - "parsing Vips", - jp.getText()); - } - } - } - jp.close(); - - return monitor; - } -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/PoolMemberResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/PoolMemberResource.java deleted file mode 100644 index 481baeabedce85af632cb7c2e53efb3f55e94416..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/PoolMemberResource.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.util.Collection; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class PoolMemberResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(PoolMemberResource.class); - - @Get("json") - public Collection <LBMember> retrieve() { - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String poolId = (String) getRequestAttributes().get("pool"); - if (poolId!=null) - return lbs.listMembersByPool(poolId); - else - return null; - } -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/PoolsResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/PoolsResource.java deleted file mode 100644 index 8feb2eb03d1668eb23d0589ac3f1f8f21e58597d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/PoolsResource.java +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; -import java.util.Collection; - -import net.floodlightcontroller.packet.IPv4; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.restlet.resource.Put; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class PoolsResource extends ServerResource { - - protected static Logger log = LoggerFactory.getLogger(PoolsResource.class); - - @Get("json") - public Collection <LBPool> retrieve() { - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String poolId = (String) getRequestAttributes().get("pool"); - if (poolId!=null) - return lbs.listPool(poolId); - else - return lbs.listPools(); - } - - @Put - @Post - public LBPool createPool(String postData) { - - LBPool pool=null; - try { - pool=jsonToPool(postData); - } catch (IOException e) { - log.error("Could not parse JSON {}", e.getMessage()); - } - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String poolId = (String) getRequestAttributes().get("pool"); - if (poolId != null) - return lbs.updatePool(pool); - else - return lbs.createPool(pool); - } - - @Delete - public int removePool() { - - String poolId = (String) getRequestAttributes().get("pool"); - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - return lbs.removePool(poolId); - } - - protected LBPool jsonToPool(String json) throws IOException { - if (json==null) return null; - - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - LBPool pool = new LBPool(); - - try { - jp = f.createJsonParser(json); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - if (n.equals("id")) { - pool.id = jp.getText(); - continue; - } - if (n.equals("tenant_id")) { - pool.tenantId = jp.getText(); - continue; - } - if (n.equals("name")) { - pool.name = jp.getText(); - continue; - } - if (n.equals("network_id")) { - pool.netId = jp.getText(); - continue; - } - if (n.equals("lb_method")) { - pool.lbMethod = Short.parseShort(jp.getText()); - continue; - } - if (n.equals("protocol")) { - String tmp = jp.getText(); - if (tmp.equalsIgnoreCase("TCP")) { - pool.protocol = IPv4.PROTOCOL_TCP; - } else if (tmp.equalsIgnoreCase("UDP")) { - pool.protocol = IPv4.PROTOCOL_UDP; - } else if (tmp.equalsIgnoreCase("ICMP")) { - pool.protocol = IPv4.PROTOCOL_ICMP; - } - continue; - } - if (n.equals("vip_id")) { - pool.vipId = jp.getText(); - continue; - } - - log.warn("Unrecognized field {} in " + - "parsing Pools", - jp.getText()); - } - jp.close(); - - return pool; - } - -} diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/VipsResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/VipsResource.java deleted file mode 100644 index fd93e41ee17af92c2a3c8dc77abf1efc463924be..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/loadbalancer/VipsResource.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import java.io.IOException; -import java.util.Collection; - -import net.floodlightcontroller.packet.IPv4; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.restlet.resource.Put; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class VipsResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(VipsResource.class); - - @Get("json") - public Collection <LBVip> retrieve() { - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String vipId = (String) getRequestAttributes().get("vip"); - if (vipId!=null) - return lbs.listVip(vipId); - else - return lbs.listVips(); - } - - @Put - @Post - public LBVip createVip(String postData) { - - LBVip vip=null; - try { - vip=jsonToVip(postData); - } catch (IOException e) { - log.error("Could not parse JSON {}", e.getMessage()); - } - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - String vipId = (String) getRequestAttributes().get("vip"); - if (vipId != null) - return lbs.updateVip(vip); - else - return lbs.createVip(vip); - } - - @Delete - public int removeVip() { - - String vipId = (String) getRequestAttributes().get("vip"); - - ILoadBalancerService lbs = - (ILoadBalancerService)getContext().getAttributes(). - get(ILoadBalancerService.class.getCanonicalName()); - - return lbs.removeVip(vipId); - } - - protected LBVip jsonToVip(String json) throws IOException { - - if (json==null) return null; - - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - LBVip vip = new LBVip(); - - try { - jp = f.createJsonParser(json); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - - if (n.equals("id")) { - vip.id = jp.getText(); - continue; - } - if (n.equals("tenant_id")) { - vip.tenantId = jp.getText(); - continue; - } - if (n.equals("name")) { - vip.name = jp.getText(); - continue; - } - if (n.equals("network_id")) { - vip.netId = jp.getText(); - continue; - } - if (n.equals("protocol")) { - String tmp = jp.getText(); - if (tmp.equalsIgnoreCase("TCP")) { - vip.protocol = IPv4.PROTOCOL_TCP; - } else if (tmp.equalsIgnoreCase("UDP")) { - vip.protocol = IPv4.PROTOCOL_UDP; - } else if (tmp.equalsIgnoreCase("ICMP")) { - vip.protocol = IPv4.PROTOCOL_ICMP; - } - continue; - } - if (n.equals("address")) { - vip.address = IPv4.toIPv4Address(jp.getText()); - continue; - } - if (n.equals("port")) { - vip.port = Short.parseShort(jp.getText()); - continue; - } - if (n.equals("pool_id")) { - vip.pools.add(jp.getText()); - continue; - } - - log.warn("Unrecognized field {} in " + - "parsing Vips", - jp.getText()); - } - jp.close(); - - return vip; - } - -} diff --git a/src/main/java/net/floodlightcontroller/packet/Ethernet.java b/src/main/java/net/floodlightcontroller/packet/Ethernet.java index d29b0859c64daff72d9d503c5bb866a422c5b67a..916ce76d0c55e591f4202df2ace76009b79191f8 100644 --- a/src/main/java/net/floodlightcontroller/packet/Ethernet.java +++ b/src/main/java/net/floodlightcontroller/packet/Ethernet.java @@ -85,6 +85,14 @@ public class Ethernet extends BasePacket { this.destinationMACAddress = MacAddress.of(destinationMACAddress); return this; } + + /** + * @param destinationMACAddress the destination MAC to set + */ + public Ethernet setDestinationMACAddress(MacAddress destinationMACAddress) { + this.destinationMACAddress = destinationMACAddress; + return this; + } /** * @param destinationMACAddress the destination MAC to set @@ -115,6 +123,14 @@ public class Ethernet extends BasePacket { this.sourceMACAddress = MacAddress.of(sourceMACAddress); return this; } + + /** + * @param sourceMACAddress the source MAC to set + */ + public Ethernet setSourceMACAddress(MacAddress sourceMACAddress) { + this.sourceMACAddress = sourceMACAddress; + return this; + } /** * @param sourceMACAddress the source MAC to set @@ -443,9 +459,9 @@ public class Ethernet extends BasePacket { else if (pkt instanceof IPv4) { IPv4 p = (IPv4) pkt; sb.append("\nnw_src: "); - sb.append(IPv4.fromIPv4Address(p.getSourceAddress())); + sb.append(p.getSourceAddress().toString()); sb.append("\nnw_dst: "); - sb.append(IPv4.fromIPv4Address(p.getDestinationAddress())); + sb.append(p.getDestinationAddress().toString()); sb.append("\nnw_tos: "); sb.append(p.getDiffServ()); sb.append("\nnw_proto: "); diff --git a/src/main/java/net/floodlightcontroller/packet/ICMP.java b/src/main/java/net/floodlightcontroller/packet/ICMP.java index 2988106484530d437df2b5fe62aac2c0a0bea480..6f0d95006aa0170b88a1b386842dd3c7e3d7f800 100644 --- a/src/main/java/net/floodlightcontroller/packet/ICMP.java +++ b/src/main/java/net/floodlightcontroller/packet/ICMP.java @@ -21,6 +21,8 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import org.projectfloodlight.openflow.types.IpProtocol; + /** * Implements ICMP packet format * @author shudong.zhou@bigswitch.com @@ -126,7 +128,7 @@ public class ICMP extends BasePacket { bb.put(payloadData); if (this.parent != null && this.parent instanceof IPv4) - ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_ICMP); + ((IPv4)this.parent).setProtocol(IpProtocol.ICMP); // compute checksum if needed if (this.checksum == 0) { diff --git a/src/main/java/net/floodlightcontroller/packet/IPv4.java b/src/main/java/net/floodlightcontroller/packet/IPv4.java index 61d9730ba2040dd330e951f574b7c8471dcc051b..be925e88e595cd9bf341df7fcb2a8dd19756248e 100644 --- a/src/main/java/net/floodlightcontroller/packet/IPv4.java +++ b/src/main/java/net/floodlightcontroller/packet/IPv4.java @@ -26,6 +26,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IpProtocol; + /** * @author David Erickson (daviderickson@cs.stanford.edu) * @@ -57,10 +60,10 @@ public class IPv4 extends BasePacket { protected byte flags; protected short fragmentOffset; protected byte ttl; - protected byte protocol; + protected IpProtocol protocol; protected short checksum; - protected int sourceAddress; - protected int destinationAddress; + protected IPv4Address sourceAddress; + protected IPv4Address destinationAddress; protected byte[] options; protected boolean isTruncated; @@ -199,14 +202,14 @@ public class IPv4 extends BasePacket { /** * @return the protocol */ - public byte getProtocol() { + public IpProtocol getProtocol() { return protocol; } /** * @param protocol the protocol to set */ - public IPv4 setProtocol(byte protocol) { + public IPv4 setProtocol(IpProtocol protocol) { this.protocol = protocol; return this; } @@ -234,46 +237,62 @@ public class IPv4 extends BasePacket { /** * @return the sourceAddress */ - public int getSourceAddress() { + public IPv4Address getSourceAddress() { return sourceAddress; } /** * @param sourceAddress the sourceAddress to set */ - public IPv4 setSourceAddress(int sourceAddress) { + public IPv4 setSourceAddress(IPv4Address sourceAddress) { this.sourceAddress = sourceAddress; return this; } + + /** + * @param sourceAddress the sourceAddress to set + */ + public IPv4 setSourceAddress(int sourceAddress) { + this.sourceAddress = IPv4Address.of(sourceAddress); + return this; + } /** * @param sourceAddress the sourceAddress to set */ public IPv4 setSourceAddress(String sourceAddress) { - this.sourceAddress = IPv4.toIPv4Address(sourceAddress); + this.sourceAddress = IPv4Address.of(sourceAddress); return this; } /** * @return the destinationAddress */ - public int getDestinationAddress() { + public IPv4Address getDestinationAddress() { return destinationAddress; } /** * @param destinationAddress the destinationAddress to set */ - public IPv4 setDestinationAddress(int destinationAddress) { + public IPv4 setDestinationAddress(IPv4Address destinationAddress) { this.destinationAddress = destinationAddress; return this; } + + /** + * @param destinationAddress the destinationAddress to set + */ + public IPv4 setDestinationAddress(int destinationAddress) { + this.destinationAddress = IPv4Address.of(destinationAddress); + return this; + } /** * @param destinationAddress the destinationAddress to set */ public IPv4 setDestinationAddress(String destinationAddress) { - this.destinationAddress = IPv4.toIPv4Address(destinationAddress); + this.destinationAddress = IPv4Address.of(destinationAddress); return this; } @@ -328,10 +347,10 @@ public class IPv4 extends BasePacket { bb.putShort((short)(((this.flags & IPV4_FLAGS_MASK) << IPV4_FLAGS_SHIFT) | (this.fragmentOffset & IPV4_OFFSET_MASK))); bb.put(this.ttl); - bb.put(this.protocol); + bb.putShort(this.protocol.getIpProtocolNumber()); bb.putShort(this.checksum); - bb.putInt(this.sourceAddress); - bb.putInt(this.destinationAddress); + bb.putInt(this.sourceAddress.getInt()); + bb.putInt(this.destinationAddress.getInt()); if (this.options != null) bb.put(this.options); if (payloadData != null) @@ -373,10 +392,10 @@ public class IPv4 extends BasePacket { this.flags = (byte) ((sscratch >> IPV4_FLAGS_SHIFT) & IPV4_FLAGS_MASK); this.fragmentOffset = (short) (sscratch & IPV4_OFFSET_MASK); this.ttl = bb.get(); - this.protocol = bb.get(); + this.protocol = IpProtocol.of(bb.getShort()); this.checksum = bb.getShort(); - this.sourceAddress = bb.getInt(); - this.destinationAddress = bb.getInt(); + this.sourceAddress = IPv4Address.of(bb.getInt()); + this.destinationAddress = IPv4Address.of(bb.getInt()); if (this.headerLength > 5) { int optionsLength = (this.headerLength - 5) * 4; @@ -398,8 +417,8 @@ public class IPv4 extends BasePacket { } else { if (log.isTraceEnabled() && isFragment) { log.trace("IPv4 fragment detected {}->{}, forward using IP header only", - fromIPv4Address(this.sourceAddress), - fromIPv4Address(this.destinationAddress)); + this.sourceAddress.toString(), + this.destinationAddress.toString()); } payload = new Data(); } @@ -540,15 +559,15 @@ public class IPv4 extends BasePacket { final int prime = 2521; int result = super.hashCode(); result = prime * result + checksum; - result = prime * result + destinationAddress; + result = prime * result + destinationAddress.getInt(); result = prime * result + diffServ; result = prime * result + flags; result = prime * result + fragmentOffset; result = prime * result + headerLength; result = prime * result + identification; result = prime * result + Arrays.hashCode(options); - result = prime * result + protocol; - result = prime * result + sourceAddress; + result = prime * result + protocol.getIpProtocolNumber(); + result = prime * result + sourceAddress.getInt(); result = prime * result + totalLength; result = prime * result + ttl; result = prime * result + version; diff --git a/src/main/java/net/floodlightcontroller/packet/TCP.java b/src/main/java/net/floodlightcontroller/packet/TCP.java index 6af5932a55c15d9e4b5729ff6eac8998c9dc16eb..f4b9a50260c94137a3d0ab7eefe9debdf14d8ba7 100644 --- a/src/main/java/net/floodlightcontroller/packet/TCP.java +++ b/src/main/java/net/floodlightcontroller/packet/TCP.java @@ -20,13 +20,16 @@ package net.floodlightcontroller.packet; import java.nio.ByteBuffer; import java.util.Arrays; +import org.projectfloodlight.openflow.types.IpProtocol; +import org.projectfloodlight.openflow.types.TransportPort; + /** * * @author shudong.zhou@bigswitch.com */ public class TCP extends BasePacket { - protected short sourcePort; - protected short destinationPort; + protected TransportPort sourcePort; + protected TransportPort destinationPort; protected int sequence; protected int acknowledge; protected byte dataOffset; @@ -39,32 +42,48 @@ public class TCP extends BasePacket { /** * @return the sourcePort */ - public short getSourcePort() { + public TransportPort getSourcePort() { return sourcePort; } /** * @param sourcePort the sourcePort to set */ - public TCP setSourcePort(short sourcePort) { + public TCP setSourcePort(TransportPort sourcePort) { this.sourcePort = sourcePort; return this; } + + /** + * @param sourcePort the sourcePort to set + */ + public TCP setSourcePort(int sourcePort) { + this.sourcePort = TransportPort.of(sourcePort); + return this; + } /** * @return the destinationPort */ - public short getDestinationPort() { + public TransportPort getDestinationPort() { return destinationPort; } /** * @param destinationPort the destinationPort to set */ - public TCP setDestinationPort(short destinationPort) { + public TCP setDestinationPort(TransportPort destinationPort) { this.destinationPort = destinationPort; return this; } + + /** + * @param destinationPort the destinationPort to set + */ + public TCP setDestinationPort(short destinationPort) { + this.destinationPort = TransportPort.of(destinationPort); + return this; + } /** * @return the checksum @@ -166,8 +185,8 @@ public class TCP extends BasePacket { byte[] data = new byte[length]; ByteBuffer bb = ByteBuffer.wrap(data); - bb.putShort(this.sourcePort); - bb.putShort(this.destinationPort); + bb.putShort((short)this.sourcePort.getPort()); //TCP ports are defined to be 16 bits + bb.putShort((short)this.destinationPort.getPort()); bb.putInt(this.sequence); bb.putInt(this.acknowledge); bb.putShort((short) (this.flags | (dataOffset << 12))); @@ -185,7 +204,7 @@ public class TCP extends BasePacket { bb.put(payloadData); if (this.parent != null && this.parent instanceof IPv4) - ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_TCP); + ((IPv4)this.parent).setProtocol(IpProtocol.TCP); // compute checksum if needed if (this.checksum == 0) { @@ -195,11 +214,11 @@ public class TCP extends BasePacket { // compute pseudo header mac if (this.parent != null && this.parent instanceof IPv4) { IPv4 ipv4 = (IPv4) this.parent; - accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff) - + (ipv4.getSourceAddress() & 0xffff); - accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff) - + (ipv4.getDestinationAddress() & 0xffff); - accumulation += ipv4.getProtocol() & 0xff; + accumulation += ((ipv4.getSourceAddress().getInt() >> 16) & 0xffff) + + (ipv4.getSourceAddress().getInt() & 0xffff); + accumulation += ((ipv4.getDestinationAddress().getInt() >> 16) & 0xffff) + + (ipv4.getDestinationAddress().getInt() & 0xffff); + accumulation += ipv4.getProtocol().getIpProtocolNumber() & 0xff; accumulation += length & 0xffff; } @@ -227,8 +246,8 @@ public class TCP extends BasePacket { final int prime = 5807; int result = super.hashCode(); result = prime * result + checksum; - result = prime * result + destinationPort; - result = prime * result + sourcePort; + result = prime * result + destinationPort.getPort(); + result = prime * result + sourcePort.getPort(); return result; } @@ -261,8 +280,8 @@ public class TCP extends BasePacket { public IPacket deserialize(byte[] data, int offset, int length) throws PacketParsingException { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.sourcePort = bb.getShort(); - this.destinationPort = bb.getShort(); + this.sourcePort = TransportPort.of(bb.getShort()); + this.destinationPort = TransportPort.of(bb.getShort()); this.sequence = bb.getInt(); this.acknowledge = bb.getInt(); this.flags = bb.getShort(); diff --git a/src/main/java/net/floodlightcontroller/packet/UDP.java b/src/main/java/net/floodlightcontroller/packet/UDP.java index 710762c097137bede7a84da1fa7cd6de2a586057..fad7a128f85ccbb074665a11dc250189e540a884 100644 --- a/src/main/java/net/floodlightcontroller/packet/UDP.java +++ b/src/main/java/net/floodlightcontroller/packet/UDP.java @@ -21,6 +21,9 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import org.projectfloodlight.openflow.types.IpProtocol; +import org.projectfloodlight.openflow.types.TransportPort; + /** * * @author David Erickson (daviderickson@cs.stanford.edu) @@ -40,40 +43,56 @@ public class UDP extends BasePacket { } - protected short sourcePort; - protected short destinationPort; + protected TransportPort sourcePort; + protected TransportPort destinationPort; protected short length; protected short checksum; /** * @return the sourcePort */ - public short getSourcePort() { + public TransportPort getSourcePort() { return sourcePort; } /** * @param sourcePort the sourcePort to set */ - public UDP setSourcePort(short sourcePort) { + public UDP setSourcePort(TransportPort sourcePort) { this.sourcePort = sourcePort; return this; } + + /** + * @param sourcePort the sourcePort to set + */ + public UDP setSourcePort(short sourcePort) { + this.sourcePort = TransportPort.of(sourcePort); + return this; + } /** * @return the destinationPort */ - public short getDestinationPort() { + public TransportPort getDestinationPort() { return destinationPort; } /** * @param destinationPort the destinationPort to set */ - public UDP setDestinationPort(short destinationPort) { + public UDP setDestinationPort(TransportPort destinationPort) { this.destinationPort = destinationPort; return this; } + + /** + * @param destinationPort the destinationPort to set + */ + public UDP setDestinationPort(short destinationPort) { + this.destinationPort = TransportPort.of(destinationPort); + return this; + } /** * @return the length @@ -122,15 +141,15 @@ public class UDP extends BasePacket { byte[] data = new byte[this.length]; ByteBuffer bb = ByteBuffer.wrap(data); - bb.putShort(this.sourcePort); - bb.putShort(this.destinationPort); + bb.putShort((short)this.sourcePort.getPort()); // UDP packet port numbers are 16 bit + bb.putShort((short)this.destinationPort.getPort()); bb.putShort(this.length); bb.putShort(this.checksum); if (payloadData != null) bb.put(payloadData); if (this.parent != null && this.parent instanceof IPv4) - ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_UDP); + ((IPv4)this.parent).setProtocol(IpProtocol.UDP); // compute checksum if needed if (this.checksum == 0) { @@ -140,11 +159,11 @@ public class UDP extends BasePacket { // compute pseudo header mac if (this.parent != null && this.parent instanceof IPv4) { IPv4 ipv4 = (IPv4) this.parent; - accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff) - + (ipv4.getSourceAddress() & 0xffff); - accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff) - + (ipv4.getDestinationAddress() & 0xffff); - accumulation += ipv4.getProtocol() & 0xff; + accumulation += ((ipv4.getSourceAddress().getInt() >> 16) & 0xffff) + + (ipv4.getSourceAddress().getInt() & 0xffff); + accumulation += ((ipv4.getDestinationAddress().getInt() >> 16) & 0xffff) + + (ipv4.getDestinationAddress().getInt() & 0xffff); + accumulation += ipv4.getProtocol().getIpProtocolNumber() & 0xff; accumulation += this.length & 0xffff; } @@ -172,9 +191,9 @@ public class UDP extends BasePacket { final int prime = 5807; int result = super.hashCode(); result = prime * result + checksum; - result = prime * result + destinationPort; + result = prime * result + destinationPort.getPort(); result = prime * result + length; - result = prime * result + sourcePort; + result = prime * result + sourcePort.getPort(); return result; } @@ -205,8 +224,8 @@ public class UDP extends BasePacket { public IPacket deserialize(byte[] data, int offset, int length) throws PacketParsingException { ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.sourcePort = bb.getShort(); - this.destinationPort = bb.getShort(); + this.sourcePort = TransportPort.of(bb.getShort()); + this.destinationPort = TransportPort.of(bb.getShort()); this.length = bb.getShort(); this.checksum = bb.getShort(); diff --git a/src/main/java/net/floodlightcontroller/restserver/IRestApiService.java b/src/main/java/net/floodlightcontroller/restserver/IRestApiService.java deleted file mode 100644 index 8efcc516e261e8f44e49f1b2b40823fdb31812b3..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/restserver/IRestApiService.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.restserver; - -import net.floodlightcontroller.core.module.IFloodlightService; - -public interface IRestApiService extends IFloodlightService { - /** - * Adds a REST API - * @param routeable - */ - public void addRestletRoutable(RestletRoutable routable); - - /** - * Runs the REST API server - */ - public void run(); -} diff --git a/src/main/java/net/floodlightcontroller/restserver/RestApiServer.java b/src/main/java/net/floodlightcontroller/restserver/RestApiServer.java deleted file mode 100644 index 9973e0b319a4ec47d367856503cab6a5a707041d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/restserver/RestApiServer.java +++ /dev/null @@ -1,219 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.restserver; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.restlet.Application; -import org.restlet.Component; -import org.restlet.Context; -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.Restlet; -import org.restlet.data.Protocol; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.ext.jackson.JacksonRepresentation; -import org.restlet.representation.Representation; -import org.restlet.routing.Filter; -import org.restlet.routing.Router; -import org.restlet.routing.Template; -import org.restlet.service.StatusService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.internal.FloodlightProvider; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; - -public class RestApiServer - implements IFloodlightModule, IRestApiService { - protected static Logger logger = LoggerFactory.getLogger(RestApiServer.class); - protected List<RestletRoutable> restlets; - protected FloodlightModuleContext fmlContext; - protected String restHost = null; - protected int restPort = 8080; - - // *********** - // Application - // *********** - - protected class RestApplication extends Application { - protected Context context; - - public RestApplication() { - super(new Context()); - this.context = getContext(); - } - - @Override - public Restlet createInboundRoot() { - Router baseRouter = new Router(context); - baseRouter.setDefaultMatchingMode(Template.MODE_STARTS_WITH); - for (RestletRoutable rr : restlets) { - baseRouter.attach(rr.basePath(), rr.getRestlet(context)); - } - - Filter slashFilter = new Filter() { - @Override - protected int beforeHandle(Request request, Response response) { - Reference ref = request.getResourceRef(); - String originalPath = ref.getPath(); - if (originalPath.contains("//")) - { - String newPath = originalPath.replaceAll("/+", "/"); - ref.setPath(newPath); - } - return Filter.CONTINUE; - } - - }; - slashFilter.setNext(baseRouter); - - return slashFilter; - } - - public void run(FloodlightModuleContext fmlContext, String restHost, int restPort) { - setStatusService(new StatusService() { - @Override - public Representation getRepresentation(Status status, - Request request, - Response response) { - return new JacksonRepresentation<Status>(status); - } - }); - - // Add everything in the module context to the rest - for (Class<? extends IFloodlightService> s : fmlContext.getAllServices()) { - if (logger.isTraceEnabled()) { - logger.trace("Adding {} for service {} into context", - s.getCanonicalName(), fmlContext.getServiceImpl(s)); - } - context.getAttributes().put(s.getCanonicalName(), - fmlContext.getServiceImpl(s)); - } - - // Start listening for REST requests - try { - final Component component = new Component(); - if (restHost == null) { - component.getServers().add(Protocol.HTTP, restPort); - } else { - component.getServers().add(Protocol.HTTP, restHost, restPort); - } - component.getClients().add(Protocol.CLAP); - component.getDefaultHost().attach(this); - component.start(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - // *************** - // IRestApiService - // *************** - - @Override - public void addRestletRoutable(RestletRoutable routable) { - restlets.add(routable); - } - - @Override - public void run() { - if (logger.isDebugEnabled()) { - StringBuffer sb = new StringBuffer(); - sb.append("REST API routables: "); - for (RestletRoutable routable : restlets) { - sb.append(routable.getClass().getSimpleName()); - sb.append(" ("); - sb.append(routable.basePath()); - sb.append("), "); - } - logger.debug(sb.toString()); - } - - RestApplication restApp = new RestApplication(); - restApp.run(fmlContext, restHost, restPort); - } - - // ***************** - // IFloodlightModule - // ***************** - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> services = - new ArrayList<Class<? extends IFloodlightService>>(1); - services.add(IRestApiService.class); - return services; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(IRestApiService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - // We don't have any - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - // This has to be done here since we don't know what order the - // startUp methods will be called - this.restlets = new ArrayList<RestletRoutable>(); - this.fmlContext = context; - - // read our config options - Map<String, String> configOptions = context.getConfigParams(this); - restHost = configOptions.get("host"); - if (restHost == null) { - Map<String, String> providerConfigOptions = context.getConfigParams( - FloodlightProvider.class); - restHost = providerConfigOptions.get("openflowhost"); - } - if (restHost != null) { - logger.debug("REST host set to {}", restHost); - } - String port = configOptions.get("port"); - if (port != null) { - restPort = Integer.parseInt(port); - } - logger.debug("REST port set to {}", restPort); - } - - @Override - public void startUp(FloodlightModuleContext Context) { - // no-op - } -} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/restserver/RestletRoutable.java b/src/main/java/net/floodlightcontroller/restserver/RestletRoutable.java deleted file mode 100644 index cb7dfce8c26e8aa7eb83a1e6f2cc688345d564ff..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/restserver/RestletRoutable.java +++ /dev/null @@ -1,40 +0,0 @@ -/** -* 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.restserver; - -import org.restlet.Context; -import org.restlet.Restlet; - -/** - * Register a set of REST resources with the central controller - * @author readams - */ -public interface RestletRoutable { - /** - * Get the restlet that will map to the resources - * @param context the context for constructing the restlet - * @return the restlet - */ - Restlet getRestlet(Context context); - - /** - * Get the base path URL where the router should be registered - * @return the base path URL where the router should be registered - */ - String basePath(); -} diff --git a/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java b/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java deleted file mode 100644 index 28ca79f843a5f4984ab25eb012e95141c062c2bb..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java +++ /dev/null @@ -1,67 +0,0 @@ -/** -* 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.routing; -import java.util.HashMap; - -import net.floodlightcontroller.routing.Link; - -import org.projectfloodlight.openflow.types.DatapathId; - -public class BroadcastTree { - protected HashMap<DatapathId, Link> links; - protected HashMap<DatapathId, Integer> costs; - - public BroadcastTree() { - links = new HashMap<DatapathId, Link>(); - costs = new HashMap<DatapathId, Integer>(); - } - - public BroadcastTree(HashMap<DatapathId, Link> links, HashMap<DatapathId, Integer> costs) { - this.links = links; - this.costs = costs; - } - - public Link getTreeLink(DatapathId node) { - return links.get(node); - } - - public int getCost(DatapathId node) { - if (costs.get(node) == null) return -1; - return (costs.get(node)); - } - - public HashMap<DatapathId, Link> getLinks() { - return links; - } - - public void addTreeLink(DatapathId myNode, Link link) { - links.put(myNode, link); - } - - public String toString() { - StringBuffer sb = new StringBuffer(); - for(DatapathId n: links.keySet()) { - sb.append("[" + n.toString() + ": cost=" + costs.get(n) + ", " + links.get(n) + "]"); - } - return sb.toString(); - } - - public HashMap<DatapathId, Integer> getCosts() { - return costs; - } -} diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java deleted file mode 100644 index a3b22551433ab428e38a03f11881e57006412084..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java +++ /dev/null @@ -1,612 +0,0 @@ -/** - * 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.routing; - -import java.io.IOException; -import java.util.EnumSet; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.annotations.LogMessageDocs; -import net.floodlightcontroller.core.internal.IOFSwitchService; -import net.floodlightcontroller.core.util.AppCookie; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.IRoutingDecision; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; -import net.floodlightcontroller.util.OFMessageDamper; -import net.floodlightcontroller.util.TimedCache; - -import org.projectfloodlight.openflow.protocol.OFFlowMod; -import org.projectfloodlight.openflow.protocol.match.Match; -import org.projectfloodlight.openflow.protocol.match.MatchField; -import org.projectfloodlight.openflow.protocol.match.MatchFields; -import org.projectfloodlight.openflow.protocol.OFFlowAdd; -import org.projectfloodlight.openflow.protocol.OFFlowModCommand; -import org.projectfloodlight.openflow.protocol.OFFlowModify; -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFPacketOut; -import org.projectfloodlight.openflow.protocol.OFPacketQueue; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.protocol.OFUint64; -import org.projectfloodlight.openflow.protocol.action.OFAction; -import org.projectfloodlight.openflow.protocol.action.OFActionOutput; -import org.projectfloodlight.openflow.types.DatapathId; -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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Abstract base class for implementing a forwarding module. Forwarding is - * responsible for programming flows to a switch in response to a policy - * decision. - */ -@LogMessageCategory("Flow Programming") -public abstract class ForwardingBase - implements IOFMessageListener { - - protected static Logger log = - LoggerFactory.getLogger(ForwardingBase.class); - - protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find sweet spot - protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms - - public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds - public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite - - public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT_CONSTANT = 5; - public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT_CONSTANT = 0; - - protected IFloodlightProviderService floodlightProvider; - protected IDeviceService deviceManager; - protected IRoutingService routingEngine; - protected ITopologyService topology; - protected ICounterStoreService counterStore; - protected IOFSwitchService switchService; - - protected OFMessageDamper messageDamper; - - // for broadcast loop suppression - protected boolean broadcastCacheFeature = true; - public final int prime1 = 2633; // for hash calculation - public final static int prime2 = 4357; // for hash calculation - public TimedCache<Long> broadcastCache = - new TimedCache<Long>(100, 5*1000); // 5 seconds interval; - - // flow-mod - for use in the cookie - public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed - // by a global APP_ID class - static { - AppCookie.registerApp(FORWARDING_APP_ID, "Forwarding"); - } - public static final long appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); - - // Comparator for sorting by SwitchCluster - public Comparator<SwitchPort> clusterIdComparator = - new Comparator<SwitchPort>() { - @Override - public int compare(SwitchPort d1, SwitchPort d2) { - DatapathId d1ClusterId = - topology.getL2DomainId(d1.getSwitchDPID()); - DatapathId d2ClusterId = - topology.getL2DomainId(d2.getSwitchDPID()); - return d1ClusterId.compareTo(d2ClusterId); - } - }; - - /** - * init data structures - * - */ - protected void init() { - messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, - EnumSet.of(OFType.FLOW_MOD), - OFMESSAGE_DAMPER_TIMEOUT); - } - - /** - * Adds a listener for devicemanager and registers for PacketIns. - */ - protected void startUp() { - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - } - - /** - * Returns the application name "forwarding". - */ - @Override - public String getName() { - return "forwarding"; - } - - /** - * All subclasses must define this function if they want any specific - * forwarding action - * - * @param sw - * Switch that the packet came in from - * @param pi - * The packet that came in - * @param decision - * Any decision made by a policy engine - */ - public abstract Command - processPacketInMessage(IOFSwitch sw, OFPacketIn pi, - IRoutingDecision decision, - FloodlightContext cntx); - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, - FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - IRoutingDecision decision = null; - if (cntx != null) - decision = - IRoutingDecision.rtStore.get(cntx, - IRoutingDecision.CONTEXT_DECISION); - - return this.processPacketInMessage(sw, - (OFPacketIn) msg, - decision, - cntx); - default: - break; - } - return Command.CONTINUE; - } - - /** - * Push routes from back to front - * @param route Route to push - * @param match OpenFlow fields to match on - * @param srcSwPort Source switch port for the first hop - * @param dstSwPort Destination switch port for final hop - * @param cookie The cookie to set in each flow_mod - * @param cntx The floodlight context - * @param reqeustFlowRemovedNotifn if set to true then the switch would - * send a flow mod removal notification when the flow mod expires - * @param doFlush if set to true then the flow mod would be immediately - * written to the switch - * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD, - * OFFlowMod.OFPFC_MODIFY etc. - * @return srcSwitchIincluded True if the source switch is included in this route - */ - @LogMessageDocs({ - @LogMessageDoc(level="WARN", - message="Unable to push route, switch at DPID {dpid} not available", - explanation="A switch along the calculated path for the " + - "flow has disconnected.", - recommendation=LogMessageDoc.CHECK_SWITCH), - @LogMessageDoc(level="ERROR", - message="Failure writing flow mod", - explanation="An I/O error occurred while writing a " + - "flow modification to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - }) - public boolean pushRoute(Route route, Match match, - Match.Builder wildcard_hints, - OFPacketIn pi, - DatapathId pinSwitch, - long cookie, - FloodlightContext cntx, - boolean reqeustFlowRemovedNotifn, - boolean doFlush, - OFFlowModCommand flowModCommand) { - - boolean srcSwitchIncluded = false; - OFFlowAdd.Builder fmb = switchService.getSwitch(pinSwitch).getOFFactory().buildFlowAdd(); - OFActionOutput.Builder actionOutputBuilder = switchService.getSwitch(pinSwitch).getOFFactory().actions().buildOutput(); - actionOutputBuilder.setMaxLen((int) 0xffffffff); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(actionOutputBuilder.build()); - - fmb.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) - .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) - .setBufferId(OFBufferId.NO_BUFFER) - .setCookie(U64.of(cookie)) - .setMatch(match) - .setActions(actions); - List<NodePortTuple> switchPortList = route.getPath(); - - for (int indx = switchPortList.size() - 1; indx > 0; indx -= 2) { - // indx and indx-1 will always have the same switch DPID. - DatapathId switchDPID = switchPortList.get(indx).getNodeId(); - IOFSwitch sw = switchService.getSwitch(switchDPID); - if (sw == null) { - if (log.isWarnEnabled()) { - log.warn("Unable to push route, switch at DPID {} " + - "not available", switchDPID); - } - return srcSwitchIncluded; - } - - // set the match. - fmb.setMatch(wildcard(match, sw, wildcard_hints)); - - // set buffer id if it is the source switch - // this only appears to set wildcards, which I think are not necessary - /*if (1 == indx) { - // Set the flag to request flow-mod removal notifications only for the - // source switch. The removal message is used to maintain the flow - // cache. Don't set the flag for ARP messages - TODO generalize check - if ((reqeustFlowRemovedNotifn) - && (match.get(MatchField.ARP_OP).getOpcode() != Ethernet.TYPE_ARP)) { - //with new flow cache design, we don't need the flow removal message from switch anymore - //fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM); - // - match.setWildcards(fmb.getMatch().getWildcards()); - } - }*/ - - OFPort outPort = switchPortList.get(indx).getPortId(); - OFPort inPort = switchPortList.get(indx-1).getPortId(); - // set input and output ports on the switch - Match m = fmb.getMatch(); - m. - .setInputPort(inPort); - ((OFActionOutput)fm.getActions().get(0)).setPort(outPort); - - try { - counterStore.updatePktOutFMCounterStoreLocal(sw, fm); - if (log.isTraceEnabled()) { - log.trace("Pushing Route flowmod routeIndx={} " + - "sw={} inPort={} outPort={}", - new Object[] {indx, - sw, - fm.getMatch().getInputPort(), - outPort }); - } - messageDamper.write(sw, fm, cntx); - if (doFlush) { - sw.flush(); - counterStore.updateFlush(); - } - - // Push the packet out the source switch - if (sw.getId().equals(pinSwitch)) { - // TODO: Instead of doing a packetOut here we could also - // send a flowMod with bufferId set.... - pushPacket(sw, pi, false, outPort, cntx); - srcSwitchIncluded = true; - } - } catch (IOException e) { - log.error("Failure writing flow mod", e); - } - - try { - fm = fm.clone(); - } catch (CloneNotSupportedException e) { - log.error("Failure cloning flow mod", e); - } - } - - return srcSwitchIncluded; - } - - /*protected Match wildcard(Match match, IOFSwitch sw, - Integer wildcard_hints) { - if (wildcard_hints != null) { - return match.clone().setWildcards(wildcard_hints.intValue()); - } - return match.clone(); - }*/ - - /** - * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we - * assume that the packetOut switch is the same as the packetIn switch - * and we will use the bufferId. In this case the packet can be null - * Caller needs to make sure that inPort and outPort differs - * @param packet packet data to send. - * @param sw switch from which packet-out is sent - * @param bufferId bufferId - * @param inPort input port - * @param outPort output port - * @param cntx context of the packet - * @param flush force to flush the packet. - */ - @LogMessageDocs({ - @LogMessageDoc(level="ERROR", - message="BufferId is not and packet data is null. " + - "Cannot send packetOut. " + - "srcSwitch={dpid} inPort={port} outPort={port}", - explanation="The switch send a malformed packet-in." + - "The packet will be dropped", - recommendation=LogMessageDoc.REPORT_SWITCH_BUG), - @LogMessageDoc(level="ERROR", - message="Failure writing packet out", - explanation="An I/O error occurred while writing a " + - "packet out to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - }) - - /** - * Pushes a packet-out to a switch. The assumption here is that - * the packet-in was also generated from the same switch. Thus, if the input - * port of the packet-in and the outport are the same, the function will not - * push the packet-out. - * @param sw switch that generated the packet-in, and from which packet-out is sent - * @param pi packet-in - * @param useBufferId if true, use the bufferId from the packet in and - * do not add the packetIn's payload. If false set bufferId to - * BUFFER_ID_NONE and use the packetIn's payload - * @param outport output port - * @param cntx context of the packet - */ - protected void pushPacket(IOFSwitch sw, OFPacketIn pi, - boolean useBufferId, - OFPort outport, FloodlightContext cntx) { - - if (pi == null) { - return; - } - - // The assumption here is (sw) is the switch that generated the - // packet-in. If the input port is the same as output port, then - // the packet-out should be ignored. - if (pi.getInPort() == outport) { - if (log.isDebugEnabled()) { - log.debug("Attempting to do packet-out to the same " + - "interface as packet-in. Dropping packet. " + - " SrcSwitch={}, pi={}", - new Object[]{sw, pi}); - return; - } - } - - if (log.isTraceEnabled()) { - log.trace("PacketOut srcSwitch={} pi={}", - new Object[] {sw, pi}); - } - - //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); - OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut(); - - // set actions - List<OFAction> actions = new ArrayList<OFAction>(); - //actions.add(new OFActionOutput(outport, (short) 0xffff)); - actions.add(sw.getOFFactory().actions().output(outport, (int) 0xffffffff)); - - pob.setActions(actions); - //.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); - //short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); - - if (useBufferId) { - pob.setBufferId(pi.getBufferId()); - } else { - pob.setBufferId(OFBufferId.NO_BUFFER); - } - - if (pob.getBufferId() == OFBufferId.NO_BUFFER) { - //poLength += packetData.length; - pob.setData(pi.getData()); - } - - pob.setInPort(pi.getInPort()); - //po.setLength(poLength); - - try { - counterStore.updatePktOutFMCounterStoreLocal(sw, pob.build()); - messageDamper.write(sw, pob.build(), cntx); - } catch (IOException e) { - log.error("Failure writing packet out", e); - } - } - - - /** - * Write packetout message to sw with output actions to one or more - * output ports with inPort/outPorts passed in. - * @param packetData - * @param sw - * @param inPort - * @param ports - * @param cntx - */ - public void packetOutMultiPort(byte[] packetData, - IOFSwitch sw, - OFPort inPort, - Set<OFPort> outPorts, - FloodlightContext cntx) { - //setting actions - List<OFAction> actions = new ArrayList<OFAction>(); - - Iterator<OFPort> j = outPorts.iterator(); - - while (j.hasNext()) - { - //actions.add(new OFActionOutput(j.next().shortValue(), (short) 0)); - actions.add(sw.getOFFactory().actions().output(j.next(), 0)); - } - - //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); - OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut(); - pob.setActions(actions); - //po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * outPorts.size())); - - // set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE - pob.setBufferId(OFBufferId.NO_BUFFER); - pob.setInPort(inPort); - - // data (note buffer_id is always BUFFER_ID_NONE) and length - //short poLength = (short)(po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); - //poLength += packetData.length; - pob.setData(packetData); - //po.setLength(poLength); - - try { - counterStore.updatePktOutFMCounterStoreLocal(sw, pob.build()); - if (log.isTraceEnabled()) { - log.trace("write broadcast packet on switch-id={} " + - "interfaces={} packet-out={}", - new Object[] {sw.getId(), outPorts, pob.build()}); - } - messageDamper.write(sw, pob.build(), cntx); - - } catch (IOException e) { - log.error("Failure writing packet out", e); - } - } - - /** - * @see packetOutMultiPort - * Accepts a PacketIn instead of raw packet data. Note that the inPort - * and switch can be different than the packet in switch/port - */ - public void packetOutMultiPort(OFPacketIn pi, - IOFSwitch sw, - OFPort inPort, - Set<OFPort> outPorts, - FloodlightContext cntx) { - packetOutMultiPort(pi.getData(), sw, inPort, outPorts, cntx); - } - - /** - * @see packetOutMultiPort - * Accepts an IPacket instead of raw packet data. Note that the inPort - * and switch can be different than the packet in switch/port - */ - public void packetOutMultiPort(IPacket packet, - IOFSwitch sw, - OFPort inPort, - Set<OFPort> outPorts, - FloodlightContext cntx) { - packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx); - } - - protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi, - FloodlightContext cntx) { - // Get the cluster id of the switch. - // Get the hash of the Ethernet packet. - if (sw == null) return true; - - // If the feature is disabled, always return false; - if (!broadcastCacheFeature) return false; - - Ethernet eth = - IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - Long broadcastHash; - broadcastHash = topology.getL2DomainId(sw.getId()).getLong() * prime1 + - pi.getInPort().getPortNumber() * prime2 + eth.hashCode(); - if (broadcastCache.update(broadcastHash)) { - sw.updateBroadcastCache(broadcastHash, pi.getInPort()); - return true; - } else { - return false; - } - } - - protected boolean isInSwitchBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { - if (sw == null) return true; - - // If the feature is disabled, always return false; - if (!broadcastCacheFeature) return false; - - // Get the hash of the Ethernet packet. - Ethernet eth = - IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - long hash = pi.getInPort().getPortNumber() * prime2 + eth.hashCode(); - - // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac - return sw.updateBroadcastCache(hash, pi.getInPort()); - } - - @LogMessageDocs({ - @LogMessageDoc(level="ERROR", - message="Failure writing deny flow mod", - explanation="An I/O error occurred while writing a " + - "deny flow mod to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - }) - public static boolean - blockHost(IOFSwitchService switchService, - SwitchPort sw_tup, MacAddress host_mac, - short hardTimeout, long cookie) { - - if (sw_tup == null) { - return false; - } - - IOFSwitch sw = switchService.getSwitch(sw_tup.getSwitchDPID()); - if (sw == null) return false; - OFPort inputPort = sw_tup.getPort(); - log.debug("blockHost sw={} port={} mac={}", - new Object[] { sw, sw_tup.getPort(), host_mac.getLong() }); - - // Create flow-mod based on packet-in and src-switch - OFFlowMod.Builder fmb = switchService.getSwitch(sw_tup.getSwitchDPID()).getOFFactory().buildFlowAdd(); - Match.Builder mb = switchService.getSwitch(sw_tup.getSwitchDPID()).getOFFactory().buildMatch(); - List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to - // drop - mb.setExact(MatchField.IN_PORT, inputPort); - if (host_mac.getLong() != -1L) { - //match.setDataLayerSource(Ethernet.toByteArray(host_mac)).setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_IN_PORT); - mb.setExact(MatchField.ETH_SRC, host_mac); - } /*else { - match.setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_IN_PORT); - }*/ - fmb.setCookie(U64.of(cookie)) - .setHardTimeout(hardTimeout) - .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) - .setBufferId(OFBufferId.NO_BUFFER) - .setMatch(mb.build()) - .setActions(actions); - - log.debug("write drop flow-mod sw={} match={} flow-mod={}", - new Object[] { sw, mb.build(), fmb.build() }); - // TODO: can't use the message damper sine this method is static - sw.write(fmb.build(), null); - return true; - - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return (type.equals(OFType.PACKET_IN) && - (name.equals("topology") || - name.equals("devicemanager"))); - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return false; - } - -} diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java deleted file mode 100644 index 9c7a285970819db2cd48ebe92554ce7dc6d37fe3..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java +++ /dev/null @@ -1,66 +0,0 @@ -/** -* 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.routing; - -import java.util.List; - -import org.projectfloodlight.openflow.protocol.match.Match; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.FloodlightContextStore; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.SwitchPort; - -public interface IRoutingDecision { - public enum RoutingAction { - /* - * NONE: NO-OP, continue with the packet processing chain - * DROP: Drop this packet and this flow - * FORWARD: Forward this packet, and this flow, to the first - * (and only device) in getDestinationDevices(), - * if the destination is not known at this time, - * initiate a discovery action for it (e.g. ARP) - * FORWARD_OR_FLOOD: Forward this packet, and this flow, to the first - * (and only device) in getDestinationDevices(), - * if the destination is not known at this time, - * flood this packet on the source switch - * MULTICAST: Multicast this packet to all the interfaces - * and devices attached - */ - NONE, DROP, FORWARD, FORWARD_OR_FLOOD, MULTICAST - } - - public static final FloodlightContextStore<IRoutingDecision> rtStore = - new FloodlightContextStore<IRoutingDecision>(); - public static final String CONTEXT_DECISION = - "net.floodlightcontroller.routing.decision"; - - public void addToContext(FloodlightContext cntx); - public RoutingAction getRoutingAction(); - public void setRoutingAction(RoutingAction action); - public SwitchPort getSourcePort(); - public IDevice getSourceDevice(); - public List<IDevice> getDestinationDevices(); - public void addDestinationDevice(IDevice d); - public List<SwitchPort> getMulticastInterfaces(); - public void setMulticastInterfaces(List<SwitchPort> lspt); - public Match.Builder getWildcards(); - public void setWildcards(Match.Builder wildcards); - public short getHardTimeout(); - public void setHardTimeout(short hardTimeout); -} diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java deleted file mode 100644 index 6cff6f533a75e0a0b03cdab7a27c83fc61e00696..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java +++ /dev/null @@ -1,88 +0,0 @@ -/** -* 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.routing; - -import java.util.ArrayList; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.routing.Route; - -public interface IRoutingService extends IFloodlightService { - - /** - * Provides a route between src and dst that allows tunnels. The cookie is provisioned - * for callers of getRoute to provide additional information to influence the route - * to be returned, if the underlying routing implementation supports choice among - * multiple routes. - * @param src Source switch DPID. - * @param dst Destination switch DPID. - * @param cookie cookie (usage determined by implementation; ignored by topology instance now). - */ - public Route getRoute(DatapathId src, DatapathId dst, long cookie); - - /** - * Provides a route between src and dst, with option to allow or - * not allow tunnels in the path. - * @param src Source switch DPID. - * @param dst Destination switch DPID. - * @param cookie cookie (usage determined by implementation; ignored by topology instance now). - * @param tunnelEnabled boolean option. - */ - public Route getRoute(DatapathId src, DatapathId dst, long cookie, boolean tunnelEnabled); - - /** - * Provides a route between srcPort on src and dstPort on dst. - * @param src Source switch DPID. - * @param srcPort Source port on source switch. - * @param dst Destination switch DPID. - * @param dstPort dstPort on Destination switch. - * @param cookie cookie (usage determined by implementation; ignored by topology instance now). - */ - public Route getRoute(DatapathId srcId, OFPort srcPort, - DatapathId dstId, OFPort dstPort, long cookie); - - /** - * Provides a route between srcPort on src and dstPort on dst. - * @param src Source switch DPID. - * @param srcPort Source port on source switch. - * @param dst Destination switch DPID. - * @param dstPort dstPort on Destination switch. - * @param cookie cookie (usage determined by implementation; ignored by topology instance now). - * @param tunnelEnabled boolean option. - */ - public Route getRoute(DatapathId srcId, OFPort srcPort, - DatapathId dstId, OFPort dstPort, long cookie, - boolean tunnelEnabled); - - /** return all routes, if available */ - public ArrayList<Route> getRoutes(DatapathId longSrcDpid, DatapathId longDstDpid, boolean tunnelEnabled); - - /** Check if a route exists between src and dst, including tunnel links - * in the path. - */ - public boolean routeExists(DatapathId src, DatapathId dst); - - /** Check if a route exists between src and dst, with option to have - * or not have tunnels as part of the path. - */ - public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled); - -} diff --git a/src/main/java/net/floodlightcontroller/routing/Link.java b/src/main/java/net/floodlightcontroller/routing/Link.java deleted file mode 100755 index a2f125f5a5b2cd73c9ce6bfaa65e4b56e87d6ff6..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/Link.java +++ /dev/null @@ -1,149 +0,0 @@ -/** -* 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.routing; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -public class Link implements Comparable<Link> { - @JsonProperty("src-switch") - private DatapathId src; - @JsonProperty("src-port") - private OFPort srcPort; - @JsonProperty("dst-switch") - private DatapathId dst; - @JsonProperty("dst-port") - private OFPort dstPort; - - - public Link(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort dstPort) { - this.src = srcId; - this.srcPort = srcPort; - this.dst = dstId; - this.dstPort = dstPort; - } - - /* - * Do not use this constructor. Used primarily for JSON - * Serialization/Deserialization - */ - public Link() { - super(); - } - - public DatapathId getSrc() { - return src; - } - - public OFPort getSrcPort() { - return srcPort; - } - - public DatapathId getDst() { - return dst; - } - - public OFPort getDstPort() { - return dstPort; - } - - public void setSrc(DatapathId src) { - this.src = src; - } - - public void setSrcPort(OFPort srcPort) { - this.srcPort = srcPort; - } - - public void setDst(DatapathId dst) { - this.dst = dst; - } - - public void setDstPort(OFPort dstPort) { - this.dstPort = dstPort; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (dst.getLong() ^ (dst.getLong() >>> 32)); - result = prime * result + dstPort.getPortNumber(); - result = prime * result + (int) (src.getLong() ^ (src.getLong() >>> 32)); - result = prime * result + srcPort.getPortNumber(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Link other = (Link) obj; - if (dst != other.dst) - return false; - if (dstPort != other.dstPort) - return false; - if (src != other.src) - return false; - if (srcPort != other.srcPort) - return false; - return true; - } - - - @Override - public String toString() { - return "Link [src=" + this.src.toString() - + " outPort=" - + srcPort.toString() - + ", dst=" + this.dst.toString() - + ", inPort=" - + dstPort.toString() - + "]"; - } - - //TODO @Ryan there was some short 0xFFFF bitmasking here when ports were shorts. I don't get what that did other than just allow all bits of the short (16), so I just stringified the whole thing - public String toKeyString() { - return (this.src.toString() + "|" + - this.srcPort.toString() + "|" + - this.dst.toString() + "|" + - this.dstPort.toString()); - } - - @Override - public int compareTo(Link a) { - // compare link based on natural ordering - src id, src port, dst id, dst port - if (this.getSrc() != a.getSrc()) - return (int) (this.getSrc().getLong() - a.getSrc().getLong()); - - if (this.getSrcPort() != a.getSrcPort()) - return (int) (this.getSrc().getLong() - a.getSrc().getLong()); - - if (this.getDst() != a.getDst()) - return (int) (this.getDst().getLong() - a.getDst().getLong()); - - return this.getDstPort().getPortNumber() - a.getDstPort().getPortNumber(); - } -} - diff --git a/src/main/java/net/floodlightcontroller/routing/Route.java b/src/main/java/net/floodlightcontroller/routing/Route.java deleted file mode 100755 index f41a9aaf1e159249e4eb831da30cf80abe993ad5..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/Route.java +++ /dev/null @@ -1,136 +0,0 @@ -/** -* 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.routing; - -import java.util.ArrayList; -import java.util.List; - -import org.projectfloodlight.openflow.types.DatapathId; - -import net.floodlightcontroller.topology.NodePortTuple; - -/** - * Represents a route between two switches - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public class Route implements Comparable<Route> { - protected RouteId id; - protected List<NodePortTuple> switchPorts; - protected int routeCount; - - public Route(RouteId id, List<NodePortTuple> switchPorts) { - super(); - this.id = id; - this.switchPorts = switchPorts; - this.routeCount = 0; // useful if multipath routing available - } - - public Route(DatapathId src, DatapathId dst) { - super(); - this.id = new RouteId(src, dst); - this.switchPorts = new ArrayList<NodePortTuple>(); - this.routeCount = 0; - } - - /** - * @return the id - */ - public RouteId getId() { - return id; - } - - /** - * @param id the id to set - */ - public void setId(RouteId id) { - this.id = id; - } - - /** - * @return the path - */ - public List<NodePortTuple> getPath() { - return switchPorts; - } - - /** - * @param path the path to set - */ - public void setPath(List<NodePortTuple> switchPorts) { - this.switchPorts = switchPorts; - } - - /** - * @param routeCount routeCount set by (ECMP) buildRoute method - */ - public void setRouteCount(int routeCount) { - this.routeCount = routeCount; - } - - /** - * @return routeCount return routeCount set by (ECMP) buildRoute method - */ - public int getRouteCount() { - return routeCount; - } - - @Override - public int hashCode() { - final int prime = 5791; - int result = 1; - result = prime * result + ((id == null) ? 0 : id.hashCode()); - result = prime * result + ((switchPorts == null) ? 0 : switchPorts.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Route other = (Route) obj; - if (id == null) { - if (other.id != null) - return false; - } else if (!id.equals(other.id)) - return false; - if (switchPorts == null) { - if (other.switchPorts != null) - return false; - } else if (!switchPorts.equals(other.switchPorts)) - return false; - return true; - } - - @Override - public String toString() { - return "Route [id=" + id + ", switchPorts=" + switchPorts + "]"; - } - - /** - * Compares the path lengths between Routes. - */ - @Override - public int compareTo(Route o) { - return ((Integer)switchPorts.size()).compareTo(o.switchPorts.size()); - } -} diff --git a/src/main/java/net/floodlightcontroller/routing/RouteId.java b/src/main/java/net/floodlightcontroller/routing/RouteId.java deleted file mode 100755 index bd80f4d2c6727ab238ff18566896db16aae8223e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/RouteId.java +++ /dev/null @@ -1,122 +0,0 @@ -/** -* 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.routing; - -import org.projectfloodlight.openflow.types.DatapathId; - -/** - * Stores the endpoints of a route, in this case datapath ids - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public class RouteId implements Cloneable, Comparable<RouteId> { - protected DatapathId src; - protected DatapathId dst; - protected long cookie; - - public RouteId(DatapathId src, DatapathId dst) { - super(); - this.src = src; - this.dst = dst; - this.cookie = 0; - } - - public RouteId(DatapathId src, DatapathId dst, long cookie) { - super(); - this.src = src; - this.dst = dst; - this.cookie = cookie; - } - - public DatapathId getSrc() { - return src; - } - - public void setSrc(DatapathId src) { - this.src = src; - } - - public DatapathId getDst() { - return dst; - } - - public void setDst(DatapathId dst) { - this.dst = dst; - } - - public long getCookie() { - return cookie; - } - - public void setCookie(int cookie) { - this.cookie = cookie; - } - - @Override - public int hashCode() { - final int prime = 2417; - Long result = new Long(1); - result = prime * result + ((dst == null) ? 0 : dst.hashCode()); - result = prime * result + ((src == null) ? 0 : src.hashCode()); - result = prime * result + cookie; - // To cope with long cookie, use Long to compute hash then use Long's - // built-in hash to produce int hash code - return result.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - RouteId other = (RouteId) obj; - if (dst == null) { - if (other.dst != null) - return false; - } else if (!dst.equals(other.dst)) - return false; - if (src == null) { - if (other.src != null) - return false; - } else if (!src.equals(other.src)) - return false; - return true; - } - - @Override - public String toString() { - return "RouteId [src=" + this.src.toString() + " dst=" - + this.dst.toString() + "]"; - } - - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override - public int compareTo(RouteId o) { - int result = src.compareTo(o.getSrc()); - if (result != 0) - return result; - return dst.compareTo(o.getDst()); - } -} diff --git a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java deleted file mode 100644 index 2d487f409ca01c9f7d0cbe859521be2b9dcd0a29..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.routing; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.projectfloodlight.openflow.protocol.match.Match; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.SwitchPort; - - -public class RoutingDecision implements IRoutingDecision { - - protected RoutingAction action; - protected Match.Builder wildcards; - protected short hardTimeout; - protected SwitchPort srcPort; - protected IDevice srcDevice; - protected List<IDevice> destDevices; - protected List<SwitchPort> broadcastIntertfaces; - - public RoutingDecision(DatapathId swDipd, - OFPort inPort, - IDevice srcDevice, - RoutingAction action) { - this.srcPort = new SwitchPort(swDipd, inPort); - this.srcDevice = srcDevice; - this.destDevices = - Collections.synchronizedList(new ArrayList<IDevice>()); - this.broadcastIntertfaces = - Collections.synchronizedList(new ArrayList<SwitchPort>()); - this.action = action; - this.wildcards = null; - this.hardTimeout = ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT; - } - - @Override - public RoutingAction getRoutingAction() { - return this.action; - } - - @Override - public void setRoutingAction(RoutingAction action) { - this.action = action; - } - - @Override - public SwitchPort getSourcePort() { - return this.srcPort; - } - - @Override - public IDevice getSourceDevice() { - return this.srcDevice; - } - - @Override - public List<IDevice> getDestinationDevices() { - return this.destDevices; - } - - @Override - public void addDestinationDevice(IDevice d) { - if (!destDevices.contains(d)) { - destDevices.add(d); - } - } - - @Override - public void setMulticastInterfaces(List<SwitchPort> lspt) { - this.broadcastIntertfaces = lspt; - } - - @Override - public List<SwitchPort> getMulticastInterfaces() { - return this.broadcastIntertfaces; - } - - @Override - public Match.Builder getWildcards() { - return this.wildcards; - } - - @Override - public void setWildcards(Match.Builder wildcards) { - this.wildcards = wildcards; - } - - @Override - public short getHardTimeout() { - return hardTimeout; - } - - @Override - public void setHardTimeout(short hardTimeout) { - this.hardTimeout = hardTimeout; - } - - @Override - public void addToContext(FloodlightContext cntx) { - rtStore.put(cntx, IRoutingDecision.CONTEXT_DECISION, this); - } - - public String toString() { - return "action " + action + - " wildcard " + - ((wildcards == null) ? null : wildcards.toString()); - } -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java b/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java deleted file mode 100644 index a900b5b34863bfa0a83ad2d9f61251f00123cdd1..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry; - -import java.util.Map; - -import org.openflow.protocol.OFFlowMod; - -import net.floodlightcontroller.core.module.IFloodlightService; - -public interface IStaticFlowEntryPusherService extends IFloodlightService { - /** - * Adds a static flow. - * @param name Name of the flow mod. Must be unique. - * @param fm The flow to push. - * @param swDpid The switch DPID to push it to, in 00:00:00:00:00:00:00:01 notation. - */ - public void addFlow(String name, OFFlowMod fm, String swDpid); - - /** - * Deletes a static flow - * @param name The name of the static flow to delete. - */ - public void deleteFlow(String name); - - /** - * Deletes all static flows for a practicular switch - * @param dpid The DPID of the switch to delete flows for. - */ - public void deleteFlowsForSwitch(long dpid); - - /** - * Deletes all flows. - */ - public void deleteAllFlows(); - - /** - * Gets all list of all flows - */ - public Map<String, Map<String, OFFlowMod>> getFlows(); - - /** - * Gets a list of flows by switch - */ - public Map<String, OFFlowMod> getFlows(String dpid); -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java deleted file mode 100644 index 42329e5b4490da20f86c6af7182e93321f49470c..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java +++ /dev/null @@ -1,847 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.util.AppCookie; -import net.floodlightcontroller.packet.IPv4; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionDataLayerDestination; -import org.openflow.protocol.action.OFActionDataLayerSource; -import org.openflow.protocol.action.OFActionEnqueue; -import org.openflow.protocol.action.OFActionNetworkLayerDestination; -import org.openflow.protocol.action.OFActionNetworkLayerSource; -import org.openflow.protocol.action.OFActionNetworkTypeOfService; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.action.OFActionStripVirtualLan; -import org.openflow.protocol.action.OFActionTransportLayerDestination; -import org.openflow.protocol.action.OFActionTransportLayerSource; -import org.openflow.protocol.action.OFActionVirtualLanIdentifier; -import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint; -import org.openflow.util.HexString; - -/** - * Represents static flow entries to be maintained by the controller on the - * switches. - */ -@LogMessageCategory("Static Flow Pusher") -public class StaticFlowEntries { - protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class); - - private static class SubActionStruct { - OFAction action; - int len; - } - - private static byte[] zeroMac = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - - /** - * This function generates a random hash for the bottom half of the cookie - * - * @param fm - * @param userCookie - * @param name - * @return A cookie that encodes the application ID and a hash - */ - public static long computeEntryCookie(OFFlowMod fm, int userCookie, String name) { - // flow-specific hash is next 20 bits LOOK! who knows if this - int prime = 211; - int flowHash = 2311; - for (int i=0; i < name.length(); i++) - flowHash = flowHash * prime + (int)name.charAt(i); - - return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash); - } - - /** - * Sets defaults for an OFFlowMod - * @param fm The OFFlowMod to set defaults for - * @param entryName The name of the entry. Used to compute the cookie. - */ - public static void initDefaultFlowMod(OFFlowMod fm, String entryName) { - fm.setIdleTimeout((short) 0); // infinite - fm.setHardTimeout((short) 0); // infinite - fm.setBufferId(OFPacketOut.BUFFER_ID_NONE); - fm.setCommand((short) 0); - fm.setFlags((short) 0); - fm.setOutPort(OFPort.OFPP_NONE.getValue()); - fm.setCookie(computeEntryCookie(fm, 0, entryName)); - fm.setPriority(Short.MAX_VALUE); - } - - /** - * Gets the entry name of a flow mod - * @param fmJson The OFFlowMod in a JSON representation - * @return The name of the OFFlowMod, null if not found - * @throws IOException If there was an error parsing the JSON - */ - public static String getEntryNameFromJson(String fmJson) throws IOException{ - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - - try { - jp = f.createJsonParser(fmJson); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - - if (n == "name") - return jp.getText(); - } - - return null; - } - - /** - * Parses an OFFlowMod (and it's inner OFMatch) to the storage entry format. - * @param fm The FlowMod to parse - * @param sw The switch the FlowMod is going to be installed on - * @param name The name of this static flow entry - * @return A Map representation of the storage entry - */ - public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) { - Map<String, Object> entry = new HashMap<String, Object>(); - OFMatch match = fm.getMatch(); - entry.put(StaticFlowEntryPusher.COLUMN_NAME, name); - entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw); - entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true)); - entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Short.toString(fm.getPriority())); - entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, Integer.toString(match.getWildcards())); - - if ((fm.getActions() != null) && (fm.getActions().size() > 0)) - entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, StaticFlowEntries.flowModActionsToString(fm.getActions())); - - if (match.getInputPort() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Short.toString(match.getInputPort())); - - if (!Arrays.equals(match.getDataLayerSource(), zeroMac)) - entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, HexString.toHexString(match.getDataLayerSource())); - - if (!Arrays.equals(match.getDataLayerDestination(), zeroMac)) - entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, HexString.toHexString(match.getDataLayerDestination())); - - if (match.getDataLayerVirtualLan() != -1) - entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, Short.toString(match.getDataLayerVirtualLan())); - - if (match.getDataLayerVirtualLanPriorityCodePoint() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Short.toString(match.getDataLayerVirtualLanPriorityCodePoint())); - - if (match.getDataLayerType() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, Short.toString(match.getDataLayerType())); - - if (match.getNetworkTypeOfService() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Short.toString(match.getNetworkTypeOfService())); - - if (match.getNetworkProtocol() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.getNetworkProtocol())); - - if (match.getNetworkSource() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, IPv4.fromIPv4Address(match.getNetworkSource())); - - if (match.getNetworkDestination() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, IPv4.fromIPv4Address(match.getNetworkDestination())); - - if (match.getTransportSource() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, Short.toString(match.getTransportSource())); - - if (match.getTransportDestination() != 0) - entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, Short.toString(match.getTransportDestination())); - - return entry; - } - - /** - * Returns a String representation of all the openflow actions. - * @param fmActions A list of OFActions to encode into one string - * @return A string of the actions encoded for our database - */ - @LogMessageDoc(level="ERROR", - message="Could not decode action {action}", - explanation="A static flow entry contained an invalid action", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - private static String flowModActionsToString(List<OFAction> fmActions) { - StringBuilder sb = new StringBuilder(); - for (OFAction a : fmActions) { - if (sb.length() > 0) { - sb.append(','); - } - switch(a.getType()) { - case OUTPUT: - sb.append("output=" + Short.toString(((OFActionOutput)a).getPort())); - break; - case OPAQUE_ENQUEUE: - int queue = ((OFActionEnqueue)a).getQueueId(); - short port = ((OFActionEnqueue)a).getPort(); - sb.append("enqueue=" + Short.toString(port) + ":0x" + String.format("%02x", queue)); - break; - case STRIP_VLAN: - sb.append("strip-vlan"); - break; - case SET_VLAN_ID: - sb.append("set-vlan-id=" + - Short.toString(((OFActionVirtualLanIdentifier)a).getVirtualLanIdentifier())); - break; - case SET_VLAN_PCP: - sb.append("set-vlan-priority=" + - Byte.toString(((OFActionVirtualLanPriorityCodePoint)a).getVirtualLanPriorityCodePoint())); - break; - case SET_DL_SRC: - sb.append("set-src-mac=" + - HexString.toHexString(((OFActionDataLayerSource)a).getDataLayerAddress())); - break; - case SET_DL_DST: - sb.append("set-dst-mac=" + - HexString.toHexString(((OFActionDataLayerDestination)a).getDataLayerAddress())); - break; - case SET_NW_TOS: - sb.append("set-tos-bits=" + - Byte.toString(((OFActionNetworkTypeOfService)a).getNetworkTypeOfService())); - break; - case SET_NW_SRC: - sb.append("set-src-ip=" + - IPv4.fromIPv4Address(((OFActionNetworkLayerSource)a).getNetworkAddress())); - break; - case SET_NW_DST: - sb.append("set-dst-ip=" + - IPv4.fromIPv4Address(((OFActionNetworkLayerDestination)a).getNetworkAddress())); - break; - case SET_TP_SRC: - sb.append("set-src-port=" + - Short.toString(((OFActionTransportLayerSource)a).getTransportPort())); - break; - case SET_TP_DST: - sb.append("set-dst-port=" + - Short.toString(((OFActionTransportLayerDestination)a).getTransportPort())); - break; - default: - log.error("Could not decode action: {}", a); - break; - } - - } - return sb.toString(); - } - - /** - * Turns a JSON formatted Static Flow Pusher string into a storage entry - * Expects a string in JSON along the lines of: - * { - * "switch": "AA:BB:CC:DD:EE:FF:00:11", - * "name": "flow-mod-1", - * "cookie": "0", - * "priority": "32768", - * "ingress-port": "1", - * "actions": "output=2", - * } - * @param fmJson The JSON formatted static flow pusher entry - * @return The map of the storage entry - * @throws IOException If there was an error parsing the JSON - */ - public static Map<String, Object> jsonToStorageEntry(String fmJson) throws IOException { - Map<String, Object> entry = new HashMap<String, Object>(); - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - - try { - jp = f.createJsonParser(fmJson); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - - if (n == "name") - entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText()); - else if (n == "switch") - entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText()); - else if (n == "actions") - entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText()); - else if (n == "priority") - entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText()); - else if (n == "active") - entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText()); - else if (n == "wildcards") - entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, jp.getText()); - else if (n == "ingress-port") - entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText()); - else if (n == "src-mac") - entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText()); - else if (n == "dst-mac") - entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText()); - else if (n == "vlan-id") - entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText()); - else if (n == "vlan-priority") - entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText()); - else if (n == "ether-type") - entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText()); - else if (n == "tos-bits") - entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText()); - else if (n == "protocol") - entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText()); - else if (n == "src-ip") - entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText()); - else if (n == "dst-ip") - entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText()); - else if (n == "src-port") - entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText()); - else if (n == "dst-port") - entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText()); - } - - return entry; - } - - /** - * Parses OFFlowMod actions from strings. - * @param flowMod The OFFlowMod to set the actions for - * @param actionstr The string containing all the actions - * @param log A logger to log for errors. - */ - @LogMessageDoc(level="ERROR", - message="Unexpected action '{action}', '{subaction}'", - explanation="A static flow entry contained an invalid action", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) { - List<OFAction> actions = new LinkedList<OFAction>(); - int actionsLength = 0; - if (actionstr != null) { - actionstr = actionstr.toLowerCase(); - for (String subaction : actionstr.split(",")) { - String action = subaction.split("[=:]")[0]; - SubActionStruct subaction_struct = null; - - if (action.equals("output")) { - subaction_struct = StaticFlowEntries.decode_output(subaction, log); - } - else if (action.equals("enqueue")) { - subaction_struct = decode_enqueue(subaction, log); - } - else if (action.equals("strip-vlan")) { - subaction_struct = decode_strip_vlan(subaction, log); - } - else if (action.equals("set-vlan-id")) { - subaction_struct = decode_set_vlan_id(subaction, log); - } - else if (action.equals("set-vlan-priority")) { - subaction_struct = decode_set_vlan_priority(subaction, log); - } - else if (action.equals("set-src-mac")) { - subaction_struct = decode_set_src_mac(subaction, log); - } - else if (action.equals("set-dst-mac")) { - subaction_struct = decode_set_dst_mac(subaction, log); - } - else if (action.equals("set-tos-bits")) { - subaction_struct = decode_set_tos_bits(subaction, log); - } - else if (action.equals("set-src-ip")) { - subaction_struct = decode_set_src_ip(subaction, log); - } - else if (action.equals("set-dst-ip")) { - subaction_struct = decode_set_dst_ip(subaction, log); - } - else if (action.equals("set-src-port")) { - subaction_struct = decode_set_src_port(subaction, log); - } - else if (action.equals("set-dst-port")) { - subaction_struct = decode_set_dst_port(subaction, log); - } - else { - log.error("Unexpected action '{}', '{}'", action, subaction); - } - - if (subaction_struct != null) { - actions.add(subaction_struct.action); - actionsLength += subaction_struct.len; - } - } - } - log.debug("action {}", actions); - - flowMod.setActions(actions); - flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLength); - } - - @LogMessageDoc(level="ERROR", - message="Invalid subaction: '{subaction}'", - explanation="A static flow entry contained an invalid subaction", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - private static SubActionStruct decode_output(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n; - - n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction); - if (n.matches()) { - OFActionOutput action = new OFActionOutput(); - action.setMaxLength(Short.MAX_VALUE); - short port = OFPort.OFPP_NONE.getValue(); - if (n.group(1) != null) { - try { - port = get_short(n.group(1)); - } - catch (NumberFormatException e) { - log.debug("Invalid port in: '{}' (error ignored)", subaction); - return null; - } - } - else if (n.group(2) != null) - port = OFPort.OFPP_ALL.getValue(); - else if (n.group(3) != null) - port = OFPort.OFPP_CONTROLLER.getValue(); - else if (n.group(4) != null) - port = OFPort.OFPP_LOCAL.getValue(); - else if (n.group(5) != null) - port = OFPort.OFPP_IN_PORT.getValue(); - else if (n.group(6) != null) - port = OFPort.OFPP_NORMAL.getValue(); - else if (n.group(7) != null) - port = OFPort.OFPP_FLOOD.getValue(); - action.setPort(port); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionOutput.MINIMUM_LENGTH; - } - else { - log.error("Invalid subaction: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_enqueue(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n; - - n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction); - if (n.matches()) { - short portnum = 0; - if (n.group(1) != null) { - try { - portnum = get_short(n.group(1)); - } - catch (NumberFormatException e) { - log.debug("Invalid port-num in: '{}' (error ignored)", subaction); - return null; - } - } - - int queueid = 0; - if (n.group(2) != null) { - try { - queueid = get_int(n.group(2)); - } - catch (NumberFormatException e) { - log.debug("Invalid queue-id in: '{}' (error ignored)", subaction); - return null; - } - } - - OFActionEnqueue action = new OFActionEnqueue(); - action.setPort(portnum); - action.setQueueId(queueid); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionEnqueue.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_strip_vlan(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("strip-vlan").matcher(subaction); - - if (n.matches()) { - OFActionStripVirtualLan action = new OFActionStripVirtualLan(); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionStripVirtualLan.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - short vlanid = get_short(n.group(1)); - OFActionVirtualLanIdentifier action = new OFActionVirtualLanIdentifier(); - action.setVirtualLanIdentifier(vlanid); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionVirtualLanIdentifier.MINIMUM_LENGTH; - } - catch (NumberFormatException e) { - log.debug("Invalid VLAN in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - byte prior = get_byte(n.group(1)); - OFActionVirtualLanPriorityCodePoint action = new OFActionVirtualLanPriorityCodePoint(); - action.setVirtualLanPriorityCodePoint(prior); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH; - } - catch (NumberFormatException e) { - log.debug("Invalid VLAN priority in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_src_mac(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); - - if (n.matches()) { - byte[] macaddr = get_mac_addr(n, subaction, log); - if (macaddr != null) { - OFActionDataLayerSource action = new OFActionDataLayerSource(); - action.setDataLayerAddress(macaddr); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionDataLayerSource.MINIMUM_LENGTH; - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); - - if (n.matches()) { - byte[] macaddr = get_mac_addr(n, subaction, log); - if (macaddr != null) { - OFActionDataLayerDestination action = new OFActionDataLayerDestination(); - action.setDataLayerAddress(macaddr); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionDataLayerDestination.MINIMUM_LENGTH; - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - byte tosbits = get_byte(n.group(1)); - OFActionNetworkTypeOfService action = new OFActionNetworkTypeOfService(); - action.setNetworkTypeOfService(tosbits); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionNetworkTypeOfService.MINIMUM_LENGTH; - } - catch (NumberFormatException e) { - log.debug("Invalid dst-port in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_src_ip(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction); - - if (n.matches()) { - int ipaddr = get_ip_addr(n, subaction, log); - OFActionNetworkLayerSource action = new OFActionNetworkLayerSource(); - action.setNetworkAddress(ipaddr); - log.debug(" action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionNetworkLayerSource.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction); - - if (n.matches()) { - int ipaddr = get_ip_addr(n, subaction, log); - OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination(); - action.setNetworkAddress(ipaddr); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionNetworkLayerDestination.MINIMUM_LENGTH; - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_src_port(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - short portnum = get_short(n.group(1)); - OFActionTransportLayerSource action = new OFActionTransportLayerSource(); - action.setTransportPort(portnum); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionTransportLayerSource.MINIMUM_LENGTH;; - } - catch (NumberFormatException e) { - log.debug("Invalid src-port in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static SubActionStruct decode_set_dst_port(String subaction, Logger log) { - SubActionStruct sa = null; - Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction); - - if (n.matches()) { - if (n.group(1) != null) { - try { - short portnum = get_short(n.group(1)); - OFActionTransportLayerDestination action = new OFActionTransportLayerDestination(); - action.setTransportPort(portnum); - log.debug("action {}", action); - - sa = new SubActionStruct(); - sa.action = action; - sa.len = OFActionTransportLayerDestination.MINIMUM_LENGTH;; - } - catch (NumberFormatException e) { - log.debug("Invalid dst-port in: {} (error ignored)", subaction); - return null; - } - } - } - else { - log.debug("Invalid action: '{}'", subaction); - return null; - } - - return sa; - } - - private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) { - byte[] macaddr = new byte[6]; - - for (int i=0; i<6; i++) { - if (n.group(i+1) != null) { - try { - macaddr[i] = get_byte("0x" + n.group(i+1)); - } - catch (NumberFormatException e) { - log.debug("Invalid src-mac in: '{}' (error ignored)", subaction); - return null; - } - } - else { - log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction); - return null; - } - } - - return macaddr; - } - - private static int get_ip_addr(Matcher n, String subaction, Logger log) { - int ipaddr = 0; - - for (int i=0; i<4; i++) { - if (n.group(i+1) != null) { - try { - ipaddr = ipaddr<<8; - ipaddr = ipaddr | get_int(n.group(i+1)); - } - catch (NumberFormatException e) { - log.debug("Invalid src-ip in: '{}' (error ignored)", subaction); - return 0; - } - } - else { - log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction); - return 0; - } - } - - return ipaddr; - } - - // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0) - private static int get_int(String str) { - return Integer.decode(str); - } - - // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0) - private static short get_short(String str) { - return (short)(int)Integer.decode(str); - } - - // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0) - private static byte get_byte(String str) { - return Integer.decode(str).byteValue(); - } - -} - diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java deleted file mode 100644 index 029d4a00da8eee4f0ac68ef69f1f3a57f1d4643a..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java +++ /dev/null @@ -1,852 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.HAListenerTypeMarker; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IHAListener; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IOFSwitchListener; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.AppCookie; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.staticflowentry.web.StaticFlowEntryWebRoutable; -import net.floodlightcontroller.storage.IResultSet; -import net.floodlightcontroller.storage.IStorageSourceListener; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.StorageException; - -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFFlowRemoved; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFType; -import org.openflow.util.HexString; -import org.openflow.util.U16; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@LogMessageCategory("Static Flow Pusher") -/** - * This module is responsible for maintaining a set of static flows on - * switches. This is just a big 'ol dumb list of flows and something external - * is responsible for ensuring they make sense for the network. - */ -public class StaticFlowEntryPusher - implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, - IStorageSourceListener, IOFMessageListener { - protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class); - public static final String StaticFlowName = "staticflowentry"; - - public static final int STATIC_FLOW_APP_ID = 10; - static { - AppCookie.registerApp(STATIC_FLOW_APP_ID, StaticFlowName); - } - - public static final String TABLE_NAME = "controller_staticflowtableentry"; - public static final String COLUMN_NAME = "name"; - public static final String COLUMN_SWITCH = "switch_id"; - public static final String COLUMN_ACTIVE = "active"; - public static final String COLUMN_IDLE_TIMEOUT = "idle_timeout"; - public static final String COLUMN_HARD_TIMEOUT = "hard_timeout"; - public static final String COLUMN_PRIORITY = "priority"; - public static final String COLUMN_COOKIE = "cookie"; - public static final String COLUMN_WILDCARD = "wildcards"; - public static final String COLUMN_IN_PORT = "in_port"; - public static final String COLUMN_DL_SRC = "dl_src"; - public static final String COLUMN_DL_DST = "dl_dst"; - public static final String COLUMN_DL_VLAN = "dl_vlan"; - public static final String COLUMN_DL_VLAN_PCP = "dl_vlan_pcp"; - public static final String COLUMN_DL_TYPE = "dl_type"; - public static final String COLUMN_NW_TOS = "nw_tos"; - public static final String COLUMN_NW_PROTO = "nw_proto"; - public static final String COLUMN_NW_SRC = "nw_src"; // includes CIDR-style - // netmask, e.g. - // "128.8.128.0/24" - public static final String COLUMN_NW_DST = "nw_dst"; - public static final String COLUMN_TP_DST = "tp_dst"; - public static final String COLUMN_TP_SRC = "tp_src"; - public static final String COLUMN_ACTIONS = "actions"; - public static String ColumnNames[] = { COLUMN_NAME, COLUMN_SWITCH, - COLUMN_ACTIVE, COLUMN_IDLE_TIMEOUT, COLUMN_HARD_TIMEOUT, - COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_WILDCARD, COLUMN_IN_PORT, - COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_VLAN, COLUMN_DL_VLAN_PCP, - COLUMN_DL_TYPE, COLUMN_NW_TOS, COLUMN_NW_PROTO, COLUMN_NW_SRC, - COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, COLUMN_ACTIONS }; - - - protected IFloodlightProviderService floodlightProvider; - protected IStorageSourceService storageSource; - protected IRestApiService restApi; - - private IHAListener haListener; - - // Map<DPID, Map<Name, FlowMod>>; FlowMod can be null to indicate non-active - protected Map<String, Map<String, OFFlowMod>> entriesFromStorage; - // Entry Name -> DPID of Switch it's on - protected Map<String, String> entry2dpid; - - // Class to sort FlowMod's by priority, from lowest to highest - class FlowModSorter implements Comparator<String> { - private String dpid; - public FlowModSorter(String dpid) { - this.dpid = dpid; - } - @Override - public int compare(String o1, String o2) { - OFFlowMod f1 = entriesFromStorage.get(dpid).get(o1); - OFFlowMod f2 = entriesFromStorage.get(dpid).get(o2); - if (f1 == null || f2 == null) // sort active=false flows by key - return o1.compareTo(o2); - return U16.f(f1.getPriority()) - U16.f(f2.getPriority()); - } - }; - - /** - * used for debugging and unittests - * @return the number of static flow entries as cached from storage - */ - public int countEntries() { - int size = 0; - if (entriesFromStorage == null) - return 0; - for (String ofswitch : entriesFromStorage.keySet()) - size += entriesFromStorage.get(ofswitch).size(); - return size; - } - - public IFloodlightProviderService getFloodlightProvider() { - return floodlightProvider; - } - - public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) { - this.floodlightProvider = floodlightProvider; - } - - public void setStorageSource(IStorageSourceService storageSource) { - this.storageSource = storageSource; - } - - /** - * Reads from our entriesFromStorage for the specified switch and - * sends the FlowMods down to the controller in <b>sorted</b> order. - * - * Sorted is important to maintain correctness of the switch: - * if a packet would match both a lower and a higher priority - * rule, then we want it to match the higher priority or nothing, - * but never just the lower priority one. Inserting from high to - * low priority fixes this. - * - * TODO consider adding a "block all" flow mod and then removing it - * while starting up. - * - * @param sw The switch to send entries to - */ - protected void sendEntriesToSwitch(long switchId) { - IOFSwitch sw = floodlightProvider.getSwitch(switchId); - if (sw == null) - return; - String stringId = sw.getStringId(); - - if ((entriesFromStorage != null) && (entriesFromStorage.containsKey(stringId))) { - Map<String, OFFlowMod> entries = entriesFromStorage.get(stringId); - List<String> sortedList = new ArrayList<String>(entries.keySet()); - // weird that Collections.sort() returns void - Collections.sort( sortedList, new FlowModSorter(stringId)); - for (String entryName : sortedList) { - OFFlowMod flowMod = entries.get(entryName); - if (flowMod != null) { - if (log.isDebugEnabled()) { - log.debug("Pushing static entry {} for {}", stringId, entryName); - } - writeFlowModToSwitch(sw, flowMod); - } - } - } - } - - /** - * Used only for bundle-local indexing - * - * @param map - * @return - */ - - protected Map<String, String> computeEntry2DpidMap( - Map<String, Map<String, OFFlowMod>> map) { - Map<String, String> ret = new ConcurrentHashMap<String, String>(); - for(String dpid : map.keySet()) { - for( String entry: map.get(dpid).keySet()) - ret.put(entry, dpid); - } - return ret; - } - - /** - * Read entries from storageSource, and store them in a hash - * - * @return - */ - @LogMessageDoc(level="ERROR", - message="failed to access storage: {reason}", - explanation="Could not retrieve static flows from the system " + - "database", - recommendation=LogMessageDoc.CHECK_CONTROLLER) - private Map<String, Map<String, OFFlowMod>> readEntriesFromStorage() { - Map<String, Map<String, OFFlowMod>> entries = new ConcurrentHashMap<String, Map<String, OFFlowMod>>(); - try { - Map<String, Object> row; - // null1=no predicate, null2=no ordering - IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, - ColumnNames, null, null); - for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) { - row = it.next().getRow(); - parseRow(row, entries); - } - } catch (StorageException e) { - log.error("failed to access storage: {}", e.getMessage()); - // if the table doesn't exist, then wait to populate later via - // setStorageSource() - } - return entries; - } - - /** - * Take a single row, turn it into a flowMod, and add it to the - * entries{$dpid}.{$entryName}=FlowMod - * - * IF an entry is in active, mark it with FlowMod = null - * - * @param row - * @param entries - */ - void parseRow(Map<String, Object> row, Map<String, Map<String, OFFlowMod>> entries) { - String switchName = null; - String entryName = null; - - StringBuffer matchString = new StringBuffer(); - - OFFlowMod flowMod = (OFFlowMod) floodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD); - - if (!row.containsKey(COLUMN_SWITCH) || !row.containsKey(COLUMN_NAME)) { - log.debug( - "skipping entry with missing required 'switch' or 'name' entry: {}", - row); - return; - } - // most error checking done with ClassCastException - try { - // first, snag the required entries, for debugging info - switchName = (String) row.get(COLUMN_SWITCH); - entryName = (String) row.get(COLUMN_NAME); - if (!entries.containsKey(switchName)) - entries.put(switchName, new HashMap<String, OFFlowMod>()); - StaticFlowEntries.initDefaultFlowMod(flowMod, entryName); - - for (String key : row.keySet()) { - if (row.get(key) == null) - continue; - if (key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME) - || key.equals("id")) - continue; // already handled - // explicitly ignore timeouts and wildcards - if (key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT) || - key.equals(COLUMN_WILDCARD)) - continue; - if (key.equals(COLUMN_ACTIVE)) { - if (!Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) { - log.debug("skipping inactive entry {} for switch {}", - entryName, switchName); - entries.get(switchName).put(entryName, null); // mark this an inactive - return; - } - } else if (key.equals(COLUMN_ACTIONS)){ - StaticFlowEntries.parseActionString(flowMod, (String) row.get(COLUMN_ACTIONS), log); - } else if (key.equals(COLUMN_COOKIE)) { - flowMod.setCookie( - StaticFlowEntries.computeEntryCookie(flowMod, - Integer.valueOf((String) row.get(COLUMN_COOKIE)), - entryName)); - } else if (key.equals(COLUMN_PRIORITY)) { - flowMod.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY)))); - } else { // the rest of the keys are for OFMatch().fromString() - if (matchString.length() > 0) - matchString.append(","); - matchString.append(key + "=" + row.get(key).toString()); - } - } - } catch (ClassCastException e) { - if (entryName != null && switchName != null) { - log.warn( - "Skipping entry {} on switch {} with bad data : " - + e.getMessage(), entryName, switchName); - } else { - log.warn("Skipping entry with bad data: {} :: {} ", - e.getMessage(), e.getStackTrace()); - } - } - - OFMatch ofMatch = new OFMatch(); - String match = matchString.toString(); - try { - ofMatch.fromString(match); - } catch (IllegalArgumentException e) { - log.debug( - "ignoring flow entry {} on switch {} with illegal OFMatch() key: " - + match, entryName, switchName); - return; - } - flowMod.setMatch(ofMatch); - - entries.get(switchName).put(entryName, flowMod); - } - - @Override - public void switchAdded(long switchId) { - log.debug("Switch {} connected; processing its static entries", - HexString.toHexString(switchId)); - sendEntriesToSwitch(switchId); - } - - @Override - public void switchRemoved(long switchId) { - // do NOT delete from our internal state; we're tracking the rules, - // not the switches - } - - @Override - public void switchActivated(long switchId) { - // no-op - } - - @Override - public void switchChanged(long switchId) { - // no-op - } - - @Override - public void switchPortChanged(long switchId, - ImmutablePort port, - IOFSwitch.PortChangeType type) { - // no-op - } - - - @Override - public void rowsModified(String tableName, Set<Object> rowKeys) { - // This handles both rowInsert() and rowUpdate() - log.debug("Modifying Table {}", tableName); - HashMap<String, Map<String, OFFlowMod>> entriesToAdd = - new HashMap<String, Map<String, OFFlowMod>>(); - // build up list of what was added - for (Object key: rowKeys) { - IResultSet resultSet = storageSource.getRow(tableName, key); - Iterator<IResultSet> it = resultSet.iterator(); - while (it.hasNext()) { - Map<String, Object> row = it.next().getRow(); - parseRow(row, entriesToAdd); - } - } - // batch updates by switch and blast them out - for (String dpid : entriesToAdd.keySet()) { - if (!entriesFromStorage.containsKey(dpid)) - entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>()); - - List<OFMessage> outQueue = new ArrayList<OFMessage>(); - for(String entry : entriesToAdd.get(dpid).keySet()) { - OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry); - //OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry); - OFFlowMod oldFlowMod = null; - String dpidOldFlowMod = entry2dpid.get(entry); - if (dpidOldFlowMod != null) { - oldFlowMod = entriesFromStorage.get(dpidOldFlowMod).remove(entry); - } - if (oldFlowMod != null && newFlowMod != null) { - // set the new flow mod to modify a pre-existing rule if these fields match - if(oldFlowMod.getMatch().equals(newFlowMod.getMatch()) - && oldFlowMod.getCookie() == newFlowMod.getCookie() - && oldFlowMod.getPriority() == newFlowMod.getPriority()){ - newFlowMod.setCommand(OFFlowMod.OFPFC_MODIFY_STRICT); - // if they don't match delete the old flow - } else{ - oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); - if (dpidOldFlowMod.equals(dpid)) { - outQueue.add(oldFlowMod); - } else { - writeOFMessageToSwitch(HexString.toLong(dpidOldFlowMod), oldFlowMod); - } - } - } - // write the new flow - if (newFlowMod != null) { - entriesFromStorage.get(dpid).put(entry, newFlowMod); - outQueue.add(newFlowMod); - entry2dpid.put(entry, dpid); - } else { - entriesFromStorage.get(dpid).remove(entry); - entry2dpid.remove(entry); - } - } - writeOFMessagesToSwitch(HexString.toLong(dpid), outQueue); - } - } - - @Override - public void rowsDeleted(String tableName, Set<Object> rowKeys) { - if (log.isDebugEnabled()) { - log.debug("Deleting from table {}", tableName); - } - - for(Object obj : rowKeys) { - if (!(obj instanceof String)) { - log.debug("Tried to delete non-string key {}; ignoring", obj); - continue; - } - deleteStaticFlowEntry((String) obj); - } - } - - @LogMessageDoc(level="ERROR", - message="inconsistent internal state: no switch has rule {rule}", - explanation="Inconsistent internat state discovered while " + - "deleting a static flow rule", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - private void deleteStaticFlowEntry(String entryName) { - String dpid = entry2dpid.remove(entryName); - - if (dpid == null) { - // assume state has been cleared by deleteFlowsForSwitch() or - // deleteAllFlows() - return; - } - - if (log.isDebugEnabled()) { - log.debug("Sending delete flow mod for flow {} for switch {}", entryName, dpid); - } - - // send flow_mod delete - OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName); - flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); - - if (entriesFromStorage.containsKey(dpid) && - entriesFromStorage.get(dpid).containsKey(entryName)) { - entriesFromStorage.get(dpid).remove(entryName); - } else { - log.debug("Tried to delete non-existent entry {} for switch {}", - entryName, dpid); - return; - } - - writeFlowModToSwitch(HexString.toLong(dpid), flowMod); - return; - } - - /** - * Writes a list of OFMessages to a switch - * @param dpid The datapath ID of the switch to write to - * @param messages The list of OFMessages to write. - */ - @LogMessageDoc(level="ERROR", - message="Tried to write to switch {switch} but got {error}", - explanation="An I/O error occured while trying to write a " + - "static flow to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - private void writeOFMessagesToSwitch(long dpid, List<OFMessage> messages) { - IOFSwitch ofswitch = floodlightProvider.getSwitch(dpid); - if (ofswitch != null) { // is the switch connected - try { - if (log.isDebugEnabled()) { - log.debug("Sending {} new entries to {}", messages.size(), dpid); - } - ofswitch.write(messages, null); - ofswitch.flush(); - } catch (IOException e) { - log.error("Tried to write to switch {} but got {}", dpid, e.getMessage()); - } - } - } - - /** - * Writes a single OFMessage to a switch - * @param dpid The datapath ID of the switch to write to - * @param message The OFMessage to write. - */ - @LogMessageDoc(level="ERROR", - message="Tried to write to switch {switch} but got {error}", - explanation="An I/O error occured while trying to write a " + - "static flow to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - private void writeOFMessageToSwitch(long dpid, OFMessage message) { - IOFSwitch ofswitch = floodlightProvider.getSwitch(dpid); - if (ofswitch != null) { // is the switch connected - try { - if (log.isDebugEnabled()) { - log.debug("Sending 1 new entries to {}", HexString.toHexString(dpid)); - } - ofswitch.write(message, null); - ofswitch.flush(); - } catch (IOException e) { - log.error("Tried to write to switch {} but got {}", dpid, e.getMessage()); - } - } - } - - /** - * Writes an OFFlowMod to a switch. It checks to make sure the switch - * exists before it sends - * @param dpid The data to write the flow mod to - * @param flowMod The OFFlowMod to write - */ - private void writeFlowModToSwitch(long dpid, OFFlowMod flowMod) { - IOFSwitch ofSwitch = floodlightProvider.getSwitch(dpid); - if (ofSwitch == null) { - if (log.isDebugEnabled()) { - log.debug("Not deleting key {} :: switch {} not connected", - dpid); - } - return; - } - writeFlowModToSwitch(ofSwitch, flowMod); - } - - /** - * Writes an OFFlowMod to a switch - * @param sw The IOFSwitch to write to - * @param flowMod The OFFlowMod to write - */ - @LogMessageDoc(level="ERROR", - message="Tried to write OFFlowMod to {switch} but got {error}", - explanation="An I/O error occured while trying to write a " + - "static flow to a switch", - recommendation=LogMessageDoc.CHECK_SWITCH) - private void writeFlowModToSwitch(IOFSwitch sw, OFFlowMod flowMod) { - try { - sw.write(flowMod, null); - sw.flush(); - } catch (IOException e) { - log.error("Tried to write OFFlowMod to {} but failed: {}", - HexString.toHexString(sw.getId()), e.getMessage()); - } - } - - @Override - public String getName() { - return StaticFlowName; - } - - /** - * Handles a flow removed message from a switch. If the flow was removed - * and we did not explicitly delete it we re-install it. If we explicitly - * removed the flow we stop the processing of the flow removed message. - * @param sw The switch that sent the flow removed message. - * @param msg The flow removed message. - * @param cntx The associated context. - * @return Whether to continue processing this message. - */ - public Command handleFlowRemoved(IOFSwitch sw, OFFlowRemoved msg, FloodlightContext cntx) { - long cookie = msg.getCookie(); - /** - * This is just to sanity check our assumption that static flows - * never expire. - */ - if (AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) { - if (msg.getReason() != OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE) - log.error("Got a FlowRemove message for a infinite " + - "timeout flow: {} from switch {}", msg, sw); - // Stop the processing chain since we sent the delete. - return Command.STOP; - } - - return Command.CONTINUE; - } - - @Override - @LogMessageDoc(level="ERROR", - message="Got a FlowRemove message for a infinite " + - "timeout flow: {flow} from switch {switch}", - explanation="Flows with infinite timeouts should not expire. " + - "The switch has expired the flow anyway.", - recommendation=LogMessageDoc.REPORT_SWITCH_BUG) - public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { - switch (msg.getType()) { - case FLOW_REMOVED: - return handleFlowRemoved(sw, (OFFlowRemoved) msg, cntx); - default: - return Command.CONTINUE; - } - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return false; // no dependency for non-packet in - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return false; // no dependency for non-packet in - } - - // IFloodlightModule - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IStaticFlowEntryPusherService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(IStaticFlowEntryPusherService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IStorageSourceService.class); - l.add(IRestApiService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - floodlightProvider = - context.getServiceImpl(IFloodlightProviderService.class); - storageSource = - context.getServiceImpl(IStorageSourceService.class); - restApi = - context.getServiceImpl(IRestApiService.class); - haListener = new HAListenerDelegate(); - } - - @Override - public void startUp(FloodlightModuleContext context) { - floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this); - floodlightProvider.addOFSwitchListener(this); - floodlightProvider.addHAListener(this.haListener); - - // assumes no switches connected at startup() - storageSource.createTable(TABLE_NAME, null); - storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_NAME); - storageSource.addListener(TABLE_NAME, this); - entriesFromStorage = readEntriesFromStorage(); - entry2dpid = computeEntry2DpidMap(entriesFromStorage); - restApi.addRestletRoutable(new StaticFlowEntryWebRoutable()); - } - - // IStaticFlowEntryPusherService methods - - @Override - public void addFlow(String name, OFFlowMod fm, String swDpid) { - Map<String, Object> fmMap = StaticFlowEntries.flowModToStorageEntry(fm, swDpid, name); - storageSource.insertRowAsync(TABLE_NAME, fmMap); - } - - @Override - public void deleteFlow(String name) { - storageSource.deleteRowAsync(TABLE_NAME, name); - } - - @Override - public void deleteAllFlows() { - for (String entry : entry2dpid.keySet()) { - deleteFlow(entry); - } - - /* - FIXME: Since the OF spec 1.0 is not clear on how - to match on cookies. Once all switches come to a - common implementation we can possibly re-enable this - fix. - - // Send a delete for each switch - Set<String> swSet = new HashSet<String>(); - for (String dpid : entry2dpid.values()) { - // Avoid sending duplicate deletes - if (!swSet.contains(dpid)) { - swSet.add(dpid); - sendDeleteByCookie(HexString.toLong(dpid)); - } - } - - // Clear our map - entry2dpid.clear(); - - // Clear our book keeping map - for (Map<String, OFFlowMod> eMap : entriesFromStorage.values()) { - eMap.clear(); - } - - // Reset our DB - storageSource.deleteMatchingRowsAsync(TABLE_NAME, null); - */ - } - - @Override - public void deleteFlowsForSwitch(long dpid) { - String sDpid = HexString.toHexString(dpid); - - for (Entry<String, String> e : entry2dpid.entrySet()) { - if (e.getValue().equals(sDpid)) - deleteFlow(e.getKey()); - } - - /* - FIXME: Since the OF spec 1.0 is not clear on how - to match on cookies. Once all switches come to a - common implementation we can possibly re-enable this - fix. - //sendDeleteByCookie(dpid); - - String sDpid = HexString.toHexString(dpid); - // Clear all internal flows for this switch - Map<String, OFFlowMod> sMap = entriesFromStorage.get(sDpid); - if (sMap != null) { - for (String entryName : sMap.keySet()) { - entry2dpid.remove(entryName); - // Delete from DB - deleteFlow(entryName); - } - sMap.clear(); - } else { - log.warn("Map of storage entries for switch {} was null", sDpid); - } - */ - } - - /** - * Deletes all flows installed by static flow pusher on a given switch. - * We send a delete flow mod with the static flow pusher app ID in the cookie. - * Since OF1.0 doesn't support masking based on the cookie we have to - * disable having flow specific cookies. - * @param dpid The DPID of the switch to clear all it's flows. - */ - /* - FIXME: Since the OF spec 1.0 is not clear on how - to match on cookies. Once all switches come to a - common implementation we can possibly re-enable this - fix. - private void sendDeleteByCookie(long dpid) { - if (log.isDebugEnabled()) - log.debug("Deleting all static flows on switch {}", HexString.toHexString(dpid)); - - IOFSwitch sw = floodlightProvider.getSwitch(dpid); - if (sw == null) { - log.warn("Tried to delete static flows for non-existant switch {}", - HexString.toHexString(dpid)); - return; - } - - OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory(). - getMessage(OFType.FLOW_MOD); - OFMatch ofm = new OFMatch(); - fm.setMatch(ofm); - fm.setCookie(AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, 0)); - fm.setCommand(OFFlowMod.OFPFC_DELETE); - fm.setOutPort(OFPort.OFPP_NONE); - - try { - sw.write(fm, null); - sw.flush(); - } catch (IOException e1) { - log.error("Error deleting all flows for switch {}:\n {}", - HexString.toHexString(dpid), e1.getMessage()); - return; - } - } - */ - - @Override - public Map<String, Map<String, OFFlowMod>> getFlows() { - return entriesFromStorage; - } - - @Override - public Map<String, OFFlowMod> getFlows(String dpid) { - return entriesFromStorage.get(dpid); - } - - // IHAListener - - private class HAListenerDelegate implements IHAListener { - @Override - public void transitionToMaster() { - log.debug("Re-reading static flows from storage due " + - "to HA change from SLAVE->MASTER"); - entriesFromStorage = readEntriesFromStorage(); - entry2dpid = computeEntry2DpidMap(entriesFromStorage); - } - - @Override - public void controllerNodeIPsChanged( - Map<String, String> curControllerNodeIPs, - Map<String, String> addedControllerNodeIPs, - Map<String, String> removedControllerNodeIPs) { - // ignore - } - - @Override - public String getName() { - return StaticFlowEntryPusher.this.getName(); - } - - @Override - public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type, - String name) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type, - String name) { - // TODO Auto-generated method stub - return false; - } - } -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java deleted file mode 100644 index 8705282bc358af59e8660e89d906226a65cb21d0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry.web; - -import net.floodlightcontroller.core.web.ControllerSwitchesResource; -import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; - -import org.openflow.util.HexString; -import org.restlet.data.Status; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ClearStaticFlowEntriesResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(ClearStaticFlowEntriesResource.class); - - @Get - public void ClearStaticFlowEntries() { - IStaticFlowEntryPusherService sfpService = - (IStaticFlowEntryPusherService)getContext().getAttributes(). - get(IStaticFlowEntryPusherService.class.getCanonicalName()); - - String param = (String) getRequestAttributes().get("switch"); - if (log.isDebugEnabled()) - log.debug("Clearing all static flow entires for switch: " + param); - - if (param.toLowerCase().equals("all")) { - sfpService.deleteAllFlows(); - } else { - try { - sfpService.deleteFlowsForSwitch(HexString.toLong(param)); - } catch (NumberFormatException e){ - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, - ControllerSwitchesResource.DPID_ERROR); - return; - } - } - } -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java deleted file mode 100644 index b552381f7dbf4d1909a7a2cdf262dd99a61ead45..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry.web; - -import java.util.HashMap; -import java.util.Map; - -import net.floodlightcontroller.core.web.ControllerSwitchesResource; -import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; - -import org.openflow.protocol.OFFlowMod; -import org.restlet.data.Status; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ListStaticFlowEntriesResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(ListStaticFlowEntriesResource.class); - - @Get - public Map<String, Map<String, OFFlowMod>> ListStaticFlowEntries() { - IStaticFlowEntryPusherService sfpService = - (IStaticFlowEntryPusherService)getContext().getAttributes(). - get(IStaticFlowEntryPusherService.class.getCanonicalName()); - - String param = (String) getRequestAttributes().get("switch"); - if (log.isDebugEnabled()) - log.debug("Listing all static flow entires for switch: " + param); - - if (param.toLowerCase().equals("all")) { - return sfpService.getFlows(); - } else { - try { - Map<String, Map<String, OFFlowMod>> retMap = - new HashMap<String, Map<String, OFFlowMod>>(); - retMap.put(param, sfpService.getFlows(param)); - return retMap; - - } catch (NumberFormatException e){ - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, - ControllerSwitchesResource.DPID_ERROR); - } - } - return null; - } -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryDeleteResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryDeleteResource.java deleted file mode 100644 index 8c8baa3e3fd4dc0a7bac6210a366cb4e617b0574..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryDeleteResource.java +++ /dev/null @@ -1,74 +0,0 @@ -/** -* 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.staticflowentry.web; - -import java.io.IOException; - -import org.restlet.resource.Post; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.staticflowentry.StaticFlowEntries; -import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; -import net.floodlightcontroller.storage.IStorageSourceService; - -/** - * Deletes a static flow entry to the storage source - * @author alexreimers - * - * @author Henrique Rodrigues <hsr@cs.ucsd.edu> - * Contributed with splitting StaticFlowEntryPusherResource into - * two, to make Floodlight's StaticFlowEntryPusher restlet resource - * REST compliant. - * - */ -@LogMessageCategory("Static Flow Pusher Delete Resource") -public class StaticFlowEntryDeleteResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryDeleteResource.class); - - @Post - @LogMessageDoc(level="ERROR", - message="Error deleting flow mod request: {request}", - explanation="An invalid delete request was sent to static flow pusher", - recommendation="Fix the format of the static flow mod request") - public String del(String fmJson) { - IStorageSourceService storageSource = - (IStorageSourceService)getContext().getAttributes(). - get(IStorageSourceService.class.getCanonicalName()); - String fmName = null; - if (fmJson == null) { - return "{\"status\" : \"Error! No data posted.\"}"; - } - try { - fmName = StaticFlowEntries.getEntryNameFromJson(fmJson); - if (fmName == null) { - return "{\"status\" : \"Error deleting entry, no name provided\"}"; - } - } catch (IOException e) { - log.error("Error deleting flow mod request: " + fmJson, e); - return "{\"status\" : \"Error deleting entry, see log for details\"}"; - } - - storageSource.deleteRowAsync(StaticFlowEntryPusher.TABLE_NAME, fmName); - return "{\"status\" : \"Entry " + fmName + " deleted\"}"; - } -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryPusherResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryPusherResource.java deleted file mode 100644 index 8048fe18390eab52d04e9d12e7eab7c1206277ac..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryPusherResource.java +++ /dev/null @@ -1,140 +0,0 @@ -/** -* 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.staticflowentry.web; - -import java.io.IOException; -import java.util.Map; - -import org.restlet.resource.Delete; -import org.restlet.resource.Post; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.staticflowentry.StaticFlowEntries; -import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; -import net.floodlightcontroller.storage.IStorageSourceService; - -/** - * Pushes a static flow entry to the storage source - * @author alexreimers - * - */ -@LogMessageCategory("Static Flow Pusher") -public class StaticFlowEntryPusherResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusherResource.class); - - /** - * Checks to see if the user matches IP information without - * checking for the correct ether-type (2048). - * @param rows The Map that is a string representation of - * the static flow. - * @reutrn True if they checked the ether-type, false otherwise - */ - private boolean checkMatchIp(Map<String, Object> rows) { - boolean matchEther = false; - String val = (String) rows.get(StaticFlowEntryPusher.COLUMN_DL_TYPE); - if (val != null) { - int type = 0; - // check both hex and decimal - if (val.startsWith("0x")) { - type = Integer.parseInt(val.substring(2), 16); - } else { - try { - type = Integer.parseInt(val); - } catch (NumberFormatException e) { /* fail silently */} - } - if (type == 2048) matchEther = true; - } - - if ((rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_DST) || - rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_SRC) || - rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_PROTO) || - rows.containsKey(StaticFlowEntryPusher.COLUMN_NW_TOS)) && - (matchEther == false)) - return false; - - return true; - } - - /** - * Takes a Static Flow Pusher string in JSON format and parses it into - * our database schema then pushes it to the database. - * @param fmJson The Static Flow Pusher entry in JSON format. - * @return A string status message - */ - @Post - @LogMessageDoc(level="ERROR", - message="Error parsing push flow mod request: {request}", - explanation="An invalid request was sent to static flow pusher", - recommendation="Fix the format of the static flow mod request") - public String store(String fmJson) { - IStorageSourceService storageSource = - (IStorageSourceService)getContext().getAttributes(). - get(IStorageSourceService.class.getCanonicalName()); - - Map<String, Object> rowValues; - try { - rowValues = StaticFlowEntries.jsonToStorageEntry(fmJson); - String status = null; - if (!checkMatchIp(rowValues)) { - status = "Warning! Pushing a static flow entry that matches IP " + - "fields without matching for IP payload (ether-type 2048) will cause " + - "the switch to wildcard higher level fields."; - log.error(status); - } else { - status = "Entry pushed"; - } - storageSource.insertRowAsync(StaticFlowEntryPusher.TABLE_NAME, rowValues); - return ("{\"status\" : \"" + status + "\"}"); - } catch (IOException e) { - log.error("Error parsing push flow mod request: " + fmJson, e); - return "{\"status\" : \"Error! Could not parse flod mod, see log for details.\"}"; - } - } - - @Delete - @LogMessageDoc(level="ERROR", - message="Error deleting flow mod request: {request}", - explanation="An invalid delete request was sent to static flow pusher", - recommendation="Fix the format of the static flow mod request") - public String del(String fmJson) { - IStorageSourceService storageSource = - (IStorageSourceService)getContext().getAttributes(). - get(IStorageSourceService.class.getCanonicalName()); - String fmName = null; - if (fmJson == null) { - return "{\"status\" : \"Error! No data posted.\"}"; - } - try { - fmName = StaticFlowEntries.getEntryNameFromJson(fmJson); - if (fmName == null) { - return "{\"status\" : \"Error deleting entry, no name provided\"}"; - } - } catch (IOException e) { - log.error("Error deleting flow mod request: " + fmJson, e); - return "{\"status\" : \"Error deleting entry, see log for details\"}"; - } - - storageSource.deleteRowAsync(StaticFlowEntryPusher.TABLE_NAME, fmName); - return "{\"status\" : \"Entry " + fmName + " deleted\"}"; - } -} diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryWebRoutable.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryWebRoutable.java deleted file mode 100644 index e8a578c63de3287652d12ddbb130b48d77fa15be..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/staticflowentry/web/StaticFlowEntryWebRoutable.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry.web; - -import net.floodlightcontroller.restserver.RestletRoutable; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -public class StaticFlowEntryWebRoutable implements RestletRoutable { - /** - * Create the Restlet router and bind to the proper resources. - */ - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/json", StaticFlowEntryPusherResource.class); - router.attach("/json/store", StaticFlowEntryPusherResource.class); - router.attach("/json/delete", StaticFlowEntryDeleteResource.class); - router.attach("/clear/{switch}/json", ClearStaticFlowEntriesResource.class); - router.attach("/list/{switch}/json", ListStaticFlowEntriesResource.class); - return router; - } - - /** - * Set the base path for the Topology - */ - @Override - public String basePath() { - return "/wm/staticflowentrypusher"; - } -} diff --git a/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java b/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java index 3033e99e4fd44eb799045b38f7b947ceddcf3c7b..911c1a12dcc31d06bced558ffbcc87b694eb6474 100644 --- a/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java +++ b/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java @@ -36,10 +36,8 @@ import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.counter.ICounter; -import net.floodlightcontroller.counter.CounterStore; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.counter.CounterValue.CounterType; +import net.floodlightcontroller.debugcounter.IDebugCounter; +import net.floodlightcontroller.debugcounter.IDebugCounterService; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.storage.web.StorageWebRoutable; @@ -67,7 +65,7 @@ public abstract class AbstractStorageSource protected final static String STORAGE_DELETE_COUNTER_NAME = "StorageDelete"; protected Set<String> allTableNames = new CopyOnWriteArraySet<String>(); - protected ICounterStoreService counterStore; + protected IDebugCounterService debugCounterService; protected ExecutorService executorService = defaultExecutorService; protected IStorageExceptionHandler exceptionHandler; @@ -146,25 +144,26 @@ public abstract class AbstractStorageSource return allTableNames; } - public void setCounterStore(CounterStore counterStore) { - this.counterStore = counterStore; + public void setDebugCounterService(IDebugCounterService dcs) { + debugCounterService = dcs; } protected void updateCounters(String baseName, String tableName) { - if (counterStore != null) { + /*if (debugCounterService != null) { String counterName; if (tableName != null) { updateCounters(baseName, null); - counterName = baseName + CounterStore.TitleDelimitor + tableName; + counterName = baseName + "__" + tableName; //TODO @Ryan __ was CounterStore.Title } else { counterName = baseName; } - ICounter counter = counterStore.getCounter(counterName); + TODO @Ryan not sure what to do about this counter. It seems different than debug counters. + * IDebugCounter counter = debugCounterService.getCounter(counterName); if (counter == null) { counter = counterStore.createCounter(counterName, CounterType.LONG); } counter.increment(); - } + }*/ } @Override @@ -518,7 +517,7 @@ public abstract class AbstractStorageSource Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); l.add(IRestApiService.class); - l.add(ICounterStoreService.class); + l.add(IDebugCounterService.class); return l; } @@ -527,8 +526,8 @@ public abstract class AbstractStorageSource throws FloodlightModuleException { restApi = context.getServiceImpl(IRestApiService.class); - counterStore = - context.getServiceImpl(ICounterStoreService.class); + debugCounterService = + context.getServiceImpl(IDebugCounterService.class); } @Override diff --git a/src/main/java/net/floodlightcontroller/topology/Cluster.java b/src/main/java/net/floodlightcontroller/topology/Cluster.java deleted file mode 100644 index 914740f10246698c95c7cf0085cb09465c79a709..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/Cluster.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.floodlightcontroller.routing.Link; - -import org.projectfloodlight.openflow.types.DatapathId; - -public class Cluster { - protected DatapathId id; // the lowest id of the nodes - protected Map<DatapathId, Set<Link>> links; // set of links connected to a node. - - public Cluster() { - id = DatapathId.NONE; - links = new HashMap<DatapathId, Set<Link>>(); - } - - public DatapathId getId() { - return id; - } - - public void setId(DatapathId id) { - this.id = id; - } - - public Map<DatapathId, Set<Link>> getLinks() { - return links; - } - - public Set<DatapathId> getNodes() { - return links.keySet(); - } - - void add(DatapathId n) { - if (links.containsKey(n) == false) { - links.put(n, new HashSet<Link>()); - if (n.getLong() < id.getLong()) id = n; - } - } - - void addLink(Link l) { - add(l.getSrc()); - links.get(l.getSrc()).add(l); - - add(l.getDst()); - links.get(l.getDst()).add(l); - } - - @Override - public int hashCode() { - return (int) (id.getLong() + id.getLong() >>>32); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - - Cluster other = (Cluster) obj; - return (this.id == other.id); - } - - public String toString() { - return "[Cluster id=" + id.toString() + ", " + links.keySet() + "]"; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyListener.java b/src/main/java/net/floodlightcontroller/topology/ITopologyListener.java deleted file mode 100644 index 56933ca59515cf242c4d3b7108975b0c0fbb034a..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/ITopologyListener.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import java.util.List; - -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate; - -public interface ITopologyListener { - /** - * Happens when the switch clusters are recomputed - */ - void topologyChanged(List<LDUpdate> linkUpdates); -} diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java deleted file mode 100644 index d6bd177550852501cded815cc2132abc9dc868b0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java +++ /dev/null @@ -1,213 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import java.util.Date; -import java.util.Set; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; - -import net.floodlightcontroller.core.module.IFloodlightService; - -public interface ITopologyService extends IFloodlightService { - - public void addListener(ITopologyListener listener); - - public Date getLastUpdateTime(); - - /** - * Query to determine if devices must be learned on a given switch port. - */ - public boolean isAttachmentPointPort(DatapathId switchid, OFPort port); - public boolean isAttachmentPointPort(DatapathId switchid, OFPort port, - boolean tunnelEnabled); - - public DatapathId getOpenflowDomainId(DatapathId switchId); - public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled); - - /** - * Returns the identifier of the L2 domain of a given switch. - * @param switchId The DPID of the switch in long form - * @return The DPID of the switch that is the key for the cluster - */ - public DatapathId getL2DomainId(DatapathId switchId); - public DatapathId getL2DomainId(DatapathId switchId, boolean tunnelEnabled); - - /** - * Queries whether two switches are in the same cluster. - * @param switch1 - * @param switch2 - * @return true if the switches are in the same cluster - */ - public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2); - public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2, - boolean tunnelEnabled); - - public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID); - public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID, - boolean tunnelEnabled); - - /** - * Queries whether two switches are in the same island. - * Currently, island and cluster are the same. In future, - * islands could be different than clusters. - * @param switch1 - * @param switch2 - * @return True of they are in the same island, false otherwise - */ - public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2); - public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2, - boolean tunnelEnabled); - - public boolean isBroadcastDomainPort(DatapathId sw, OFPort port); - public boolean isBroadcastDomainPort(DatapathId sw, OFPort port, - boolean tunnelEnabled); - - - public boolean isAllowed(DatapathId sw, OFPort portId); - public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled); - - /** - * Indicates if an attachment point on the new switch port is consistent - * with the attachment point on the old switch port or not. - */ - public boolean isConsistent(DatapathId oldSw, OFPort oldPort, - DatapathId newSw, OFPort newPort); - public boolean isConsistent(DatapathId oldSw, OFPort oldPort, - DatapathId newSw, OFPort newPort, - boolean tunnelEnabled); - - /** - * Indicates if the two switch ports are connected to the same - * broadcast domain or not. - * @param s1 - * @param p1 - * @param s2 - * @param p2 - * @return - */ - public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1, - DatapathId s2, OFPort p2); - public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1, - DatapathId s2, OFPort p2, - boolean tunnelEnabled); - - /** - * Gets a list of ports on a given switch that are known to topology. - * @param sw The switch DPID in long - * @return The set of ports on this switch - */ - public Set<OFPort> getPortsWithLinks(DatapathId sw); - public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled); - - /** Get broadcast ports on a target switch for a given attachmentpoint - * point port. - */ - public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort); - - public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort, - boolean tunnelEnabled); - - /** - * - */ - public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId); - public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId, - boolean tunnelEnabled); - - - /** Get the proper outgoing switchport for a given pair of src-dst - * switchports. - */ - public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort); - - - public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort, - boolean tunnelEnabled); - - - public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort); - public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort, - boolean tunnelEnabled); - - /** - * If the dst is not allowed by the higher-level topology, - * this method provides the topologically equivalent broadcast port. - * @param src - * @param dst - * @return the allowed broadcast port - */ - public NodePortTuple - getAllowedOutgoingBroadcastPort(DatapathId src, - OFPort srcPort, - DatapathId dst, - OFPort dstPort); - - public NodePortTuple - getAllowedOutgoingBroadcastPort(DatapathId src, - OFPort srcPort, - DatapathId dst, - OFPort dstPort, - boolean tunnelEnabled); - - /** - * If the src broadcast domain port is not allowed for incoming - * broadcast, this method provides the topologically equivalent - * incoming broadcast-allowed - * src port. - * @param src - * @param dst - * @return the allowed broadcast port - */ - public NodePortTuple - getAllowedIncomingBroadcastPort(DatapathId src, - OFPort srcPort); - - public NodePortTuple - getAllowedIncomingBroadcastPort(DatapathId src, - OFPort srcPort, - boolean tunnelEnabled); - - - /** - * Gets the set of ports that belong to a broadcast domain. - * @return The set of ports that belong to a broadcast domain. - */ - public Set<NodePortTuple> getBroadcastDomainPorts(); - public Set<NodePortTuple> getTunnelPorts(); - - - /** - * Returns a set of blocked ports. The set of blocked - * ports is the union of all the blocked ports across all - * instances. - * @return - */ - public Set<NodePortTuple> getBlockedPorts(); - - /** - * Returns the enabled, non quarantined ports of the given switch. Returns - * an empty set if switch doesn't exists, doesn't have any enabled port, or - * has only quarantined ports. Will never return null. - */ - public Set<OFPort> getPorts(DatapathId sw); -} diff --git a/src/main/java/net/floodlightcontroller/topology/NodePair.java b/src/main/java/net/floodlightcontroller/topology/NodePair.java deleted file mode 100644 index 27f61c36cd7c83f151895abbc3af5f1f01123d00..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/NodePair.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -public class NodePair { - private long min; - private long max; - - public NodePair(long a, long b) { - if (a < b) { - min = a; - max = b; - } else { - min = b; - max = a; - } - } - - public long getNode() { - return min; - } - - public long getOtherNode() { - return max; - } - - public String toString() { - return "[" + new Long(min) + ", " + new Long(max) + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (max ^ (max >>> 32)); - result = prime * result + (int) (min ^ (min >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - NodePair other = (NodePair) obj; - if (max != other.max) - return false; - if (min != other.min) - return false; - return true; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java b/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java deleted file mode 100644 index f7b0a178ac397c9c2bc4bd9135c4053eb1882f96..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import net.floodlightcontroller.core.web.serializers.DPIDSerializer; -import net.floodlightcontroller.core.web.serializers.UShortSerializer; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; -import org.projectfloodlight.openflow.util.HexString; - -/** - * A NodePortTuple is similar to a SwitchPortTuple - * but it only stores IDs instead of references - * to the actual objects. - * @author srini - */ - -public class NodePortTuple implements Comparable<NodePortTuple> { - protected DatapathId nodeId; // switch DPID - protected OFPort portId; // switch port id - - /** - * Creates a NodePortTuple - * @param nodeId The DPID of the switch - * @param portId The port of the switch - */ - public NodePortTuple(DatapathId nodeId, OFPort portId) { - this.nodeId = nodeId; - this.portId = portId; - } - - @JsonProperty("switch") - @JsonSerialize(using=DPIDSerializer.class) - public DatapathId getNodeId() { - return nodeId; - } - public void setNodeId(DatapathId nodeId) { - this.nodeId = nodeId; - } - @JsonProperty("port") - @JsonSerialize(using=UShortSerializer.class) - public OFPort getPortId() { - return portId; - } - public void setPortId(OFPort portId) { - this.portId = portId; - } - - public String toString() { - return "[id=" + nodeId.toString() + ", port=" + portId.toString() + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (nodeId.getLong() ^ (nodeId.getLong() >>> 32)); - result = prime * result + portId.getPortNumber(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - NodePortTuple other = (NodePortTuple) obj; - if (nodeId != other.nodeId) - return false; - if (portId != other.portId) - return false; - return true; - } - - /** - * API to return a String value formed wtih NodeID and PortID - * The portID is a 16-bit field, so mask it as an integer to get full - * positive value - * @return - */ - public String toKeyString() { - return (nodeId.toString()+ "|" + portId.toString()); - } - - @Override - public int compareTo(NodePortTuple obj) { - final int BEFORE = -1; - final int EQUAL = 0; - final int AFTER = 1; - - if (this.getNodeId().getLong() < obj.getNodeId().getLong()) - return BEFORE; - if (this.getNodeId().getLong() > obj.getNodeId().getLong()) - return AFTER; - - if (this.getPortId().getPortNumber() < obj.getPortId().getPortNumber()) - return BEFORE; - if (this.getPortId().getPortNumber() > obj.getPortId().getPortNumber()) - return AFTER; - - return EQUAL; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/OrderedNodePair.java b/src/main/java/net/floodlightcontroller/topology/OrderedNodePair.java deleted file mode 100644 index 28b7eb6631556ed137fc571ac524de1b12fc8c36..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/OrderedNodePair.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -public class OrderedNodePair { - private long src; - private long dst; - - public OrderedNodePair(long s, long d) { - src = s; - dst = d; - } - - public long getSrc() { - return src; - } - - public long getDst() { - return dst; - } - - @Override - public int hashCode() { - final int prime = 2417; - int result = 1; - result = prime * result + (int) (dst ^ (dst >>> 32)); - result = prime * result + (int) (src ^ (src >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - OrderedNodePair other = (OrderedNodePair) obj; - if (dst != other.dst) - return false; - if (src != other.src) - return false; - return true; - } - - @Override - public String toString() { - return "OrderedNodePair [src=" + src + ", dst=" + dst + "]"; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java deleted file mode 100644 index bc5d626783048f653c6c9ba63ac14f6a459709f0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java +++ /dev/null @@ -1,848 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.Set; - -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFPort; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; - -import net.floodlightcontroller.util.ClusterDFS; -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.routing.BroadcastTree; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.routing.RouteId; -import net.floodlightcontroller.servicechaining.ServiceChain; - -/** - * A representation of a network topology. Used internally by - * {@link TopologyManager} - */ -@LogMessageCategory("Network Topology") -public class TopologyInstance { - - public static final short LT_SH_LINK = 1; - public static final short LT_BD_LINK = 2; - public static final short LT_TUNNEL = 3; - - public static final int MAX_LINK_WEIGHT = 10000; - public static final int MAX_PATH_WEIGHT = Integer.MAX_VALUE - MAX_LINK_WEIGHT - 1; - public static final int PATH_CACHE_SIZE = 1000; - - protected static Logger log = LoggerFactory.getLogger(TopologyInstance.class); - - protected Map<DatapathId, Set<OFPort>> switchPorts; // Set of ports for each switch - /** Set of switch ports that are marked as blocked. A set of blocked - * switch ports may be provided at the time of instantiation. In addition, - * we may add additional ports to this set. - */ - protected Set<NodePortTuple> blockedPorts; - protected Map<NodePortTuple, Set<Link>> switchPortLinks; // Set of links organized by node port tuple - /** Set of links that are blocked. */ - protected Set<Link> blockedLinks; - - protected Set<DatapathId> switches; - protected Set<NodePortTuple> broadcastDomainPorts; - protected Set<NodePortTuple> tunnelPorts; - - protected Set<Cluster> clusters; // set of openflow domains - protected Map<DatapathId, Cluster> switchClusterMap; // switch to OF domain map - - // States for routing - protected Map<DatapathId, BroadcastTree> destinationRootedTrees; - protected Map<DatapathId, Set<NodePortTuple>> clusterBroadcastNodePorts; - protected Map<DatapathId, BroadcastTree> clusterBroadcastTrees; - - protected class PathCacheLoader extends CacheLoader<RouteId, Route> { - TopologyInstance ti; - PathCacheLoader(TopologyInstance ti) { - this.ti = ti; - } - - @Override - public Route load(RouteId rid) { - return ti.buildroute(rid); - } - } - - // Path cache loader is defined for loading a path when it not present - // in the cache. - private final PathCacheLoader pathCacheLoader = new PathCacheLoader(this); - protected LoadingCache<RouteId, Route> pathcache; - - public TopologyInstance() { - this.switches = new HashSet<DatapathId>(); - this.switchPorts = new HashMap<DatapathId, Set<OFPort>>(); - this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); - this.broadcastDomainPorts = new HashSet<NodePortTuple>(); - this.tunnelPorts = new HashSet<NodePortTuple>(); - this.blockedPorts = new HashSet<NodePortTuple>(); - this.blockedLinks = new HashSet<Link>(); - } - - public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts, - Map<NodePortTuple, Set<Link>> switchPortLinks, - Set<NodePortTuple> broadcastDomainPorts) - { - this.switches = new HashSet<DatapathId>(switchPorts.keySet()); - this.switchPorts = new HashMap<DatapathId, Set<OFPort>>(switchPorts); - this.switchPortLinks = new HashMap<NodePortTuple, - Set<Link>>(switchPortLinks); - this.broadcastDomainPorts = new HashSet<NodePortTuple>(broadcastDomainPorts); - this.tunnelPorts = new HashSet<NodePortTuple>(); - this.blockedPorts = new HashSet<NodePortTuple>(); - this.blockedLinks = new HashSet<Link>(); - - clusters = new HashSet<Cluster>(); - switchClusterMap = new HashMap<DatapathId, Cluster>(); - } - public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts, - Set<NodePortTuple> blockedPorts, - Map<NodePortTuple, Set<Link>> switchPortLinks, - Set<NodePortTuple> broadcastDomainPorts, - Set<NodePortTuple> tunnelPorts){ - - // copy these structures - this.switches = new HashSet<DatapathId>(switchPorts.keySet()); - this.switchPorts = new HashMap<DatapathId, Set<OFPort>>(); - for(DatapathId sw: switchPorts.keySet()) { - this.switchPorts.put(sw, new HashSet<OFPort>(switchPorts.get(sw))); - } - - this.blockedPorts = new HashSet<NodePortTuple>(blockedPorts); - this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); - for(NodePortTuple npt: switchPortLinks.keySet()) { - this.switchPortLinks.put(npt, - new HashSet<Link>(switchPortLinks.get(npt))); - } - this.broadcastDomainPorts = new HashSet<NodePortTuple>(broadcastDomainPorts); - this.tunnelPorts = new HashSet<NodePortTuple>(tunnelPorts); - - blockedLinks = new HashSet<Link>(); - clusters = new HashSet<Cluster>(); - switchClusterMap = new HashMap<DatapathId, Cluster>(); - destinationRootedTrees = new HashMap<DatapathId, BroadcastTree>(); - clusterBroadcastTrees = new HashMap<DatapathId, BroadcastTree>(); - clusterBroadcastNodePorts = new HashMap<DatapathId, Set<NodePortTuple>>(); - - pathcache = CacheBuilder.newBuilder().concurrencyLevel(4) - .maximumSize(1000L) - .build( - new CacheLoader<RouteId, Route>() { - public Route load(RouteId rid) { - return pathCacheLoader.load(rid); - } - }); - } - - public void compute() { - - // Step 1: Compute clusters ignoring broadcast domain links - // Create nodes for clusters in the higher level topology - // Must ignore blocked links. - identifyOpenflowDomains(); - - // Step 1.1: Add links to clusters - // Avoid adding blocked links to clusters - addLinksToOpenflowDomains(); - - // Step 2. Compute shortest path trees in each cluster for - // unicast routing. The trees are rooted at the destination. - // Cost for tunnel links and direct links are the same. - calculateShortestPathTreeInClusters(); - - // Step 3. Compute broadcast tree in each cluster. - // Cost for tunnel links are high to discourage use of - // tunnel links. The cost is set to the number of nodes - // in the cluster + 1, to use as minimum number of - // clusters as possible. - calculateBroadcastNodePortsInClusters(); - - // Step 4. print topology. - printTopology(); - } - - public void printTopology() { - if (log.isTraceEnabled()) { - log.trace("-----------------------------------------------"); - log.trace("Links: {}",this.switchPortLinks); - log.trace("broadcastDomainPorts: {}", broadcastDomainPorts); - log.trace("tunnelPorts: {}", tunnelPorts); - log.trace("clusters: {}", clusters); - log.trace("destinationRootedTrees: {}", destinationRootedTrees); - log.trace("clusterBroadcastNodePorts: {}", clusterBroadcastNodePorts); - log.trace("-----------------------------------------------"); - } - } - - protected void addLinksToOpenflowDomains() { - for(DatapathId s: switches) { - if (switchPorts.get(s) == null) continue; - for (OFPort p: switchPorts.get(s)) { - NodePortTuple np = new NodePortTuple(s, p); - if (switchPortLinks.get(np) == null) continue; - if (isBroadcastDomainPort(np)) continue; - for(Link l: switchPortLinks.get(np)) { - if (isBlockedLink(l)) continue; - if (isBroadcastDomainLink(l)) continue; - Cluster c1 = switchClusterMap.get(l.getSrc()); - Cluster c2 = switchClusterMap.get(l.getDst()); - if (c1 ==c2) { - c1.addLink(l); - } - } - } - } - } - - /** - * @author Srinivasan Ramasubramanian - * - * This function divides the network into clusters. Every cluster is - * a strongly connected component. The network may contain unidirectional - * links. The function calls dfsTraverse for performing depth first - * search and cluster formation. - * - * The computation of strongly connected components is based on - * Tarjan's algorithm. For more details, please see the Wikipedia - * link below. - * - * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm - */ - @LogMessageDoc(level="ERROR", - message="No DFS object for switch {} found.", - explanation="The internal state of the topology module is corrupt", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - public void identifyOpenflowDomains() { - Map<DatapathId, ClusterDFS> dfsList = new HashMap<DatapathId, ClusterDFS>(); - - if (switches == null) return; - - for (DatapathId key: switches) { - ClusterDFS cdfs = new ClusterDFS(); - dfsList.put(key, cdfs); - } - Set<DatapathId> currSet = new HashSet<DatapathId>(); - - for (DatapathId sw: switches) { - ClusterDFS cdfs = dfsList.get(sw); - if (cdfs == null) { - log.error("No DFS object for switch {} found.", sw); - }else if (!cdfs.isVisited()) { - dfsTraverse(0, 1, sw, dfsList, currSet); - } - } - } - - - /** - * @author Srinivasan Ramasubramanian - * - * This algorithm computes the depth first search (DFS) traversal of the - * switches in the network, computes the lowpoint, and creates clusters - * (of strongly connected components). - * - * The computation of strongly connected components is based on - * Tarjan's algorithm. For more details, please see the Wikipedia - * link below. - * - * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm - * - * The initialization of lowpoint and the check condition for when a - * cluster should be formed is modified as we do not remove switches that - * are already part of a cluster. - * - * A return value of -1 indicates that dfsTraverse failed somewhere in the middle - * of computation. This could happen when a switch is removed during the cluster - * computation procedure. - * - * @param parentIndex: DFS index of the parent node - * @param currIndex: DFS index to be assigned to a newly visited node - * @param currSw: ID of the current switch - * @param dfsList: HashMap of DFS data structure for each switch - * @param currSet: Set of nodes in the current cluster in formation - * @return long: DSF index to be used when a new node is visited - */ - private long dfsTraverse (long parentIndex, long currIndex, DatapathId currSw, - Map<DatapathId, ClusterDFS> dfsList, Set <DatapathId> currSet) { - - //Get the DFS object corresponding to the current switch - ClusterDFS currDFS = dfsList.get(currSw); - // Get all the links corresponding to this switch - - Set<DatapathId> nodesInMyCluster = new HashSet<DatapathId>(); - Set<DatapathId> myCurrSet = new HashSet<DatapathId>(); - - //Assign the DFS object with right values. - currDFS.setVisited(true); - currDFS.setDfsIndex(currIndex); - currDFS.setParentDFSIndex(parentIndex); - currIndex++; - - // Traverse the graph through every outgoing link. - if (switchPorts.get(currSw) != null){ - for(OFPort p: switchPorts.get(currSw)) { - Set<Link> lset = switchPortLinks.get(new NodePortTuple(currSw, p)); - if (lset == null) continue; - for(Link l:lset) { - DatapathId dstSw = l.getDst(); - - // ignore incoming links. - if (dstSw.equals(currSw)) continue; - - // ignore if the destination is already added to - // another cluster - if (switchClusterMap.get(dstSw) != null) continue; - - // ignore the link if it is blocked. - if (isBlockedLink(l)) continue; - - // ignore this link if it is in broadcast domain - if (isBroadcastDomainLink(l)) continue; - - // Get the DFS object corresponding to the dstSw - ClusterDFS dstDFS = dfsList.get(dstSw); - - if (dstDFS.getDfsIndex() < currDFS.getDfsIndex()) { - // could be a potential lowpoint - if (dstDFS.getDfsIndex() < currDFS.getLowpoint()) - currDFS.setLowpoint(dstDFS.getDfsIndex()); - - } else if (!dstDFS.isVisited()) { - // make a DFS visit - currIndex = dfsTraverse(currDFS.getDfsIndex(), currIndex, dstSw, - dfsList, myCurrSet); - - if (currIndex < 0) return -1; - - // update lowpoint after the visit - if (dstDFS.getLowpoint() < currDFS.getLowpoint()) - currDFS.setLowpoint(dstDFS.getLowpoint()); - - nodesInMyCluster.addAll(myCurrSet); - myCurrSet.clear(); - } - // else, it is a node already visited with a higher - // dfs index, just ignore. - } - } - } - - nodesInMyCluster.add(currSw); - currSet.addAll(nodesInMyCluster); - - // Cluster computation. - // If the node's lowpoint is greater than its parent's DFS index, - // we need to form a new cluster with all the switches in the - // currSet. - if (currDFS.getLowpoint() > currDFS.getParentDFSIndex()) { - // The cluster thus far forms a strongly connected component. - // create a new switch cluster and the switches in the current - // set to the switch cluster. - Cluster sc = new Cluster(); - for(DatapathId sw: currSet){ - sc.add(sw); - switchClusterMap.put(sw, sc); - } - // delete all the nodes in the current set. - currSet.clear(); - // add the newly formed switch clusters to the cluster set. - clusters.add(sc); - } - - return currIndex; - } - - public Set<NodePortTuple> getBlockedPorts() { - return this.blockedPorts; - } - - protected Set<Link> getBlockedLinks() { - return this.blockedLinks; - } - - /** Returns true if a link has either one of its switch ports - * blocked. - * @param l - * @return - */ - protected boolean isBlockedLink(Link l) { - NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); - NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); - return (isBlockedPort(n1) || isBlockedPort(n2)); - } - - protected boolean isBlockedPort(NodePortTuple npt) { - return blockedPorts.contains(npt); - } - - protected boolean isTunnelPort(NodePortTuple npt) { - return tunnelPorts.contains(npt); - } - - protected boolean isTunnelLink(Link l) { - NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); - NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); - return (isTunnelPort(n1) || isTunnelPort(n2)); - } - - public boolean isBroadcastDomainLink(Link l) { - NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); - NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); - return (isBroadcastDomainPort(n1) || isBroadcastDomainPort(n2)); - } - - public boolean isBroadcastDomainPort(NodePortTuple npt) { - return broadcastDomainPorts.contains(npt); - } - - protected class NodeDist implements Comparable<NodeDist> { - private final DatapathId node; - public DatapathId getNode() { - return node; - } - - private final int dist; - public int getDist() { - return dist; - } - - public NodeDist(DatapathId node, int dist) { - this.node = node; - this.dist = dist; - } - - @Override - public int compareTo(NodeDist o) { - if (o.dist == this.dist) { - return (int)(this.node.getLong() - o.node.getLong()); - } - return this.dist - o.dist; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - NodeDist other = (NodeDist) obj; - if (!getOuterType().equals(other.getOuterType())) - return false; - if (node == null) { - if (other.node != null) - return false; - } else if (!node.equals(other.node)) - return false; - return true; - } - - @Override - public int hashCode() { - assert false : "hashCode not designed"; - return 42; - } - - private TopologyInstance getOuterType() { - return TopologyInstance.this; - } - } - - protected BroadcastTree dijkstra(Cluster c, DatapathId root, - Map<Link, Integer> linkCost, - boolean isDstRooted) { - HashMap<DatapathId, Link> nexthoplinks = new HashMap<DatapathId, Link>(); - //HashMap<Long, Long> nexthopnodes = new HashMap<Long, Long>(); - HashMap<DatapathId, Integer> cost = new HashMap<DatapathId, Integer>(); - int w; - - for (DatapathId node: c.links.keySet()) { - nexthoplinks.put(node, null); - //nexthopnodes.put(node, null); - cost.put(node, MAX_PATH_WEIGHT); - } - - HashMap<DatapathId, Boolean> seen = new HashMap<DatapathId, Boolean>(); - PriorityQueue<NodeDist> nodeq = new PriorityQueue<NodeDist>(); - nodeq.add(new NodeDist(root, 0)); - cost.put(root, 0); - while (nodeq.peek() != null) { - NodeDist n = nodeq.poll(); - DatapathId cnode = n.getNode(); - int cdist = n.getDist(); - if (cdist >= MAX_PATH_WEIGHT) break; - if (seen.containsKey(cnode)) continue; - seen.put(cnode, true); - - for (Link link: c.links.get(cnode)) { - DatapathId neighbor; - - if (isDstRooted == true) neighbor = link.getSrc(); - else neighbor = link.getDst(); - - // links directed toward cnode will result in this condition - if (neighbor.equals(cnode)) continue; - - if (seen.containsKey(neighbor)) continue; - - if (linkCost == null || linkCost.get(link)==null) w = 1; - else w = linkCost.get(link); - - int ndist = cdist + w; // the weight of the link, always 1 in current version of floodlight. - if (ndist < cost.get(neighbor)) { - cost.put(neighbor, ndist); - nexthoplinks.put(neighbor, link); - //nexthopnodes.put(neighbor, cnode); - NodeDist ndTemp = new NodeDist(neighbor, ndist); - // Remove an object that's already in there. - // Note that the comparison is based on only the node id, - // and not node id and distance. - nodeq.remove(ndTemp); - // add the current object to the queue. - nodeq.add(ndTemp); - } - } - } - - BroadcastTree ret = new BroadcastTree(nexthoplinks, cost); - return ret; - } - - protected void calculateShortestPathTreeInClusters() { - pathcache.invalidateAll(); - destinationRootedTrees.clear(); - - Map<Link, Integer> linkCost = new HashMap<Link, Integer>(); - int tunnel_weight = switchPorts.size() + 1; - - for(NodePortTuple npt: tunnelPorts) { - if (switchPortLinks.get(npt) == null) continue; - for(Link link: switchPortLinks.get(npt)) { - if (link == null) continue; - linkCost.put(link, tunnel_weight); - } - } - - for(Cluster c: clusters) { - for (DatapathId node : c.links.keySet()) { - BroadcastTree tree = dijkstra(c, node, linkCost, true); - destinationRootedTrees.put(node, tree); - } - } - } - - protected void calculateBroadcastTreeInClusters() { - for(Cluster c: clusters) { - // c.id is the smallest node that's in the cluster - BroadcastTree tree = destinationRootedTrees.get(c.id); - clusterBroadcastTrees.put(c.id, tree); - } - } - - protected void calculateBroadcastNodePortsInClusters() { - - clusterBroadcastTrees.clear(); - - calculateBroadcastTreeInClusters(); - - for(Cluster c: clusters) { - // c.id is the smallest node that's in the cluster - BroadcastTree tree = clusterBroadcastTrees.get(c.id); - //log.info("Broadcast Tree {}", tree); - - Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>(); - Map<DatapathId, Link> links = tree.getLinks(); - if (links == null) continue; - for(DatapathId nodeId: links.keySet()) { - Link l = links.get(nodeId); - if (l == null) continue; - NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); - NodePortTuple npt2 = new NodePortTuple(l.getDst(), l.getDstPort()); - nptSet.add(npt1); - nptSet.add(npt2); - } - clusterBroadcastNodePorts.put(c.id, nptSet); - } - } - - protected Route buildroute(RouteId id) { - NodePortTuple npt; - DatapathId srcId = id.getSrc(); - DatapathId dstId = id.getDst(); - - LinkedList<NodePortTuple> switchPorts = - new LinkedList<NodePortTuple>(); - - if (destinationRootedTrees == null) return null; - if (destinationRootedTrees.get(dstId) == null) return null; - - Map<DatapathId, Link> nexthoplinks = - destinationRootedTrees.get(dstId).getLinks(); - - if (!switches.contains(srcId) || !switches.contains(dstId)) { - // This is a switch that is not connected to any other switch - // hence there was no update for links (and hence it is not - // in the network) - log.debug("buildroute: Standalone switch: {}", srcId); - - // The only possible non-null path for this case is - // if srcId equals dstId --- and that too is an 'empty' path [] - - } else if ((nexthoplinks!=null) && (nexthoplinks.get(srcId)!=null)) { - while (srcId != dstId) { - Link l = nexthoplinks.get(srcId); - - npt = new NodePortTuple(l.getSrc(), l.getSrcPort()); - switchPorts.addLast(npt); - npt = new NodePortTuple(l.getDst(), l.getDstPort()); - switchPorts.addLast(npt); - srcId = nexthoplinks.get(srcId).getDst(); - } - } - // else, no path exists, and path equals null - - Route result = null; - if (switchPorts != null && !switchPorts.isEmpty()) - result = new Route(id, switchPorts); - if (log.isTraceEnabled()) { - log.trace("buildroute: {}", result); - } - return result; - } - - protected int getCost(DatapathId srcId, DatapathId dstId) { - BroadcastTree bt = destinationRootedTrees.get(dstId); - if (bt == null) return -1; - return (bt.getCost(srcId)); - } - - /* - * Getter Functions - */ - - protected Set<Cluster> getClusters() { - return clusters; - } - - // IRoutingEngineService interfaces - protected boolean routeExists(DatapathId srcId, DatapathId dstId) { - BroadcastTree bt = destinationRootedTrees.get(dstId); - if (bt == null) return false; - Link link = bt.getLinks().get(srcId); - if (link == null) return false; - return true; - } - - protected Route getRoute(ServiceChain sc, DatapathId srcId, OFPort srcPort, - DatapathId dstId, OFPort dstPort, long cookie) { - - - // Return null the route source and desitnation are the - // same switchports. - if (srcId.equals(dstId) && srcPort.equals(dstPort)) - return null; - - List<NodePortTuple> nptList; - NodePortTuple npt; - Route r = getRoute(srcId, dstId, 0); - if (r == null && !srcId.equals(dstId)) return null; - - if (r != null) { - nptList= new ArrayList<NodePortTuple>(r.getPath()); - } else { - nptList = new ArrayList<NodePortTuple>(); - } - npt = new NodePortTuple(srcId, srcPort); - nptList.add(0, npt); // add src port to the front - npt = new NodePortTuple(dstId, dstPort); - nptList.add(npt); // add dst port to the end - - RouteId id = new RouteId(srcId, dstId); - r = new Route(id, nptList); - return r; - } - - // NOTE: Return a null route if srcId equals dstId. The null route - // need not be stored in the cache. Moreover, the LoadingCache will - // throw an exception if null route is returned. - protected Route getRoute(DatapathId srcId, DatapathId dstId, long cookie) { - // Return null route if srcId equals dstId - if (srcId.equals(dstId)) return null; - - - RouteId id = new RouteId(srcId, dstId); - Route result = null; - - try { - result = pathcache.get(id); - } catch (Exception e) { - log.error("{}", e); - } - - if (log.isTraceEnabled()) { - log.trace("getRoute: {} -> {}", id, result); - } - return result; - } - - protected BroadcastTree getBroadcastTreeForCluster(long clusterId){ - Cluster c = switchClusterMap.get(clusterId); - if (c == null) return null; - return clusterBroadcastTrees.get(c.id); - } - - // - // ITopologyService interface method helpers. - // - - protected boolean isInternalToOpenflowDomain(DatapathId switchid, OFPort port) { - return !isAttachmentPointPort(switchid, port); - } - - public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) { - NodePortTuple npt = new NodePortTuple(switchid, port); - if (switchPortLinks.containsKey(npt)) return false; - return true; - } - - protected DatapathId getOpenflowDomainId(DatapathId switchId) { - Cluster c = switchClusterMap.get(switchId); - if (c == null) return switchId; - return c.getId(); - } - - protected DatapathId getL2DomainId(DatapathId switchId) { - return getOpenflowDomainId(switchId); - } - - protected Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchId) { - Cluster c = switchClusterMap.get(switchId); - if (c == null) { - // The switch is not known to topology as there - // are no links connected to it. - Set<DatapathId> nodes = new HashSet<DatapathId>(); - nodes.add(switchId); - return nodes; - } - return (c.getNodes()); - } - - protected boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) { - Cluster c1 = switchClusterMap.get(switch1); - Cluster c2 = switchClusterMap.get(switch2); - if (c1 != null && c2 != null) - return (c1.getId().equals(c2.getId())); - return (switch1.equals(switch2)); - } - - public boolean isAllowed(DatapathId sw, OFPort portId) { - return true; - } - - protected boolean - isIncomingBroadcastAllowedOnSwitchPort(DatapathId sw, OFPort portId) { - if (isInternalToOpenflowDomain(sw, portId)) { - DatapathId clusterId = getOpenflowDomainId(sw); - NodePortTuple npt = new NodePortTuple(sw, portId); - if (clusterBroadcastNodePorts.get(clusterId).contains(npt)) - return true; - else return false; - } - return true; - } - - public boolean isConsistent(DatapathId oldSw, OFPort oldPort, DatapathId newSw, - OFPort newPort) { - if (isInternalToOpenflowDomain(newSw, newPort)) return true; - return (oldSw.equals(newSw) && oldPort.equals(newPort)); - } - - protected Set<NodePortTuple> - getBroadcastNodePortsInCluster(DatapathId sw) { - DatapathId clusterId = getOpenflowDomainId(sw); - return clusterBroadcastNodePorts.get(clusterId); - } - - public boolean inSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2, OFPort p2) { - return false; - } - - public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) { - return inSameOpenflowDomain(switch1, switch2); - } - - public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort) { - // Use this function to redirect traffic if needed. - return new NodePortTuple(dst, dstPort); - } - - public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort) { - // Use this function to reinject traffic from a - // different port if needed. - return new NodePortTuple(src, srcPort); - } - - public Set<DatapathId> getSwitches() { - return switches; - } - - public Set<OFPort> getPortsWithLinks(DatapathId sw) { - return switchPorts.get(sw); - } - - public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort) { - Set<OFPort> result = new HashSet<OFPort>(); - DatapathId clusterId = getOpenflowDomainId(targetSw); - for(NodePortTuple npt: clusterBroadcastNodePorts.get(clusterId)) { - if (npt.getNodeId().equals(targetSw)) { - result.add(npt.getPortId()); - } - } - return result; - } - - public NodePortTuple - getAllowedOutgoingBroadcastPort(DatapathId src, OFPort srcPort, DatapathId dst, - OFPort dstPort) { - return null; - } - - public NodePortTuple - getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) { - return null; - } -} - diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java deleted file mode 100644 index dce7d28b92a0928d211a245ad49f678a1af87685..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java +++ /dev/null @@ -1,1561 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.HAListenerTypeMarker; -import net.floodlightcontroller.core.HARole; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IHAListener; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.LogicalOFMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageCategory; -import net.floodlightcontroller.core.annotations.LogMessageDoc; -import net.floodlightcontroller.core.internal.IOFSwitchService; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.SingletonTask; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.debugcounter.IDebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType; -import net.floodlightcontroller.debugcounter.MockDebugCounterService; -import net.floodlightcontroller.debugevent.IDebugEventService; -import net.floodlightcontroller.debugevent.IEventUpdater; -import net.floodlightcontroller.debugevent.NullDebugEvent; -import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn; -import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType; -import net.floodlightcontroller.debugevent.IDebugEventService.EventType; -import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.packet.BSN; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.LLDP; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.web.TopologyWebRoutable; - -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFPacketOut; -import org.projectfloodlight.openflow.protocol.OFPortDesc; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.protocol.action.OFAction; -import org.projectfloodlight.openflow.protocol.action.OFActionOutput; -import org.projectfloodlight.openflow.types.DatapathId; -import org.projectfloodlight.openflow.types.OFBufferId; -import org.projectfloodlight.openflow.types.OFPort; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Topology manager is responsible for maintaining the controller's notion - * of the network graph, as well as implementing tools for finding routes - * through the topology. - */ -@LogMessageCategory("Network Topology") -public class TopologyManager implements - IFloodlightModule, ITopologyService, - IRoutingService, ILinkDiscoveryListener, - IOFMessageListener { - - protected static Logger log = LoggerFactory.getLogger(TopologyManager.class); - - public static final String MODULE_NAME = "topology"; - - public static final String CONTEXT_TUNNEL_ENABLED = - "com.bigswitch.floodlight.topologymanager.tunnelEnabled"; - - /** - * Role of the controller. - */ - private HARole role; - - /** - * Set of ports for each switch - */ - protected Map<DatapathId, Set<OFPort>> switchPorts; - - /** - * Set of links organized by node port tuple - */ - protected Map<NodePortTuple, Set<Link>> switchPortLinks; - - /** - * Set of direct links - */ - protected Map<NodePortTuple, Set<Link>> directLinks; - - /** - * set of links that are broadcast domain links. - */ - protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks; - - /** - * set of tunnel links - */ - protected Set<NodePortTuple> tunnelPorts; - - protected ILinkDiscoveryService linkDiscovery; - protected IThreadPoolService threadPool; - protected IFloodlightProviderService floodlightProvider; - protected IOFSwitchService switchService; - protected IRestApiService restApi; - protected IDebugCounterService debugCounters; - - // Modules that listen to our updates - protected ArrayList<ITopologyListener> topologyAware; - - protected BlockingQueue<LDUpdate> ldUpdates; - - // These must be accessed using getCurrentInstance(), not directly - protected TopologyInstance currentInstance; - protected TopologyInstance currentInstanceWithoutTunnels; - - protected SingletonTask newInstanceTask; - private Date lastUpdateTime; - - /** - * Flag that indicates if links (direct/tunnel/multihop links) were - * updated as part of LDUpdate. - */ - protected boolean linksUpdated; - /** - * Flag that indicates if direct or tunnel links were updated as - * part of LDUpdate. - */ - protected boolean dtLinksUpdated; - - /** Flag that indicates if tunnel ports were updated or not - */ - protected boolean tunnelPortsUpdated; - - protected int TOPOLOGY_COMPUTE_INTERVAL_MS = 500; - - private IHAListener haListener; - - /** - * Debug Counters - */ - protected static final String PACKAGE = TopologyManager.class.getPackage().getName(); - protected IDebugCounter ctrIncoming; - - /** - * Debug Events - */ - protected IDebugEventService debugEvents; - - /* - * Topology Event Updater - */ - protected IEventUpdater<TopologyEvent> evTopology; - - /** - * Topology Information exposed for a Topology related event - used inside - * the BigTopologyEvent class - */ - protected class TopologyEventInfo { - private final int numOpenflowClustersWithTunnels; - private final int numOpenflowClustersWithoutTunnels; - private final Map<DatapathId, List<NodePortTuple>> externalPortsMap; - private final int numTunnelPorts; - public TopologyEventInfo(int numOpenflowClustersWithTunnels, - int numOpenflowClustersWithoutTunnels, - Map<DatapathId, List<NodePortTuple>> externalPortsMap, - int numTunnelPorts) { - super(); - this.numOpenflowClustersWithTunnels = numOpenflowClustersWithTunnels; - this.numOpenflowClustersWithoutTunnels = numOpenflowClustersWithoutTunnels; - this.externalPortsMap = externalPortsMap; - this.numTunnelPorts = numTunnelPorts; - } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("# Openflow Clusters:"); - builder.append(" { With Tunnels: "); - builder.append(numOpenflowClustersWithTunnels); - builder.append(" Without Tunnels: "); - builder.append(numOpenflowClustersWithoutTunnels); - builder.append(" }"); - builder.append(", # External Clusters: "); - int numExternalClusters = externalPortsMap.size(); - builder.append(numExternalClusters); - if (numExternalClusters > 0) { - builder.append(" { "); - int count = 0; - for (DatapathId extCluster : externalPortsMap.keySet()) { - builder.append("#" + extCluster + ":Ext Ports: "); - builder.append(externalPortsMap.get(extCluster).size()); - if (++count < numExternalClusters) { - builder.append(", "); - } else { - builder.append(" "); - } - } - builder.append("}"); - } - builder.append(", # Tunnel Ports: "); - builder.append(numTunnelPorts); - return builder.toString(); - } - } - - /** - * Topology Event class to track topology related events - */ - protected class TopologyEvent { - @EventColumn(name = "Reason", description = EventFieldType.STRING) - private final String reason; - @EventColumn(name = "Topology Summary") - private final TopologyEventInfo topologyInfo; - public TopologyEvent(String reason, - TopologyEventInfo topologyInfo) { - super(); - this.reason = reason; - this.topologyInfo = topologyInfo; - } - } - - // Getter/Setter methods - /** - * Get the time interval for the period topology updates, if any. - * The time returned is in milliseconds. - * @return - */ - public int getTopologyComputeInterval() { - return TOPOLOGY_COMPUTE_INTERVAL_MS; - } - - /** - * Set the time interval for the period topology updates, if any. - * The time is in milliseconds. - * @return - */ - public void setTopologyComputeInterval(int time_ms) { - TOPOLOGY_COMPUTE_INTERVAL_MS = time_ms; - } - - /** - * Thread for recomputing topology. The thread is always running, - * however the function applyUpdates() has a blocking call. - */ - @LogMessageDoc(level="ERROR", - message="Error in topology instance task thread", - explanation="An unknown error occured in the topology " + - "discovery module.", - recommendation=LogMessageDoc.CHECK_CONTROLLER) - protected class UpdateTopologyWorker implements Runnable { - @Override - public void run() { - try { - if (ldUpdates.peek() != null) - updateTopology(); - handleMiscellaneousPeriodicEvents(); - } - catch (Exception e) { - log.error("Error in topology instance task thread", e); - } finally { - if (floodlightProvider.getRole() != HARole.STANDBY) - newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, - TimeUnit.MILLISECONDS); - } - } - } - - // To be used for adding any periodic events that's required by topology. - protected void handleMiscellaneousPeriodicEvents() { - return; - } - - public boolean updateTopology() { - boolean newInstanceFlag; - linksUpdated = false; - dtLinksUpdated = false; - tunnelPortsUpdated = false; - List<LDUpdate> appliedUpdates = applyUpdates(); - newInstanceFlag = createNewInstance("link-discovery-updates"); - lastUpdateTime = new Date(); - informListeners(appliedUpdates); - return newInstanceFlag; - } - - // ********************** - // ILinkDiscoveryListener - // ********************** - @Override - public void linkDiscoveryUpdate(List<LDUpdate> updateList) { - if (log.isTraceEnabled()) { - log.trace("Queuing update: {}", updateList); - } - ldUpdates.addAll(updateList); - } - - @Override - public void linkDiscoveryUpdate(LDUpdate update) { - if (log.isTraceEnabled()) { - log.trace("Queuing update: {}", update); - } - ldUpdates.add(update); - } - - // **************** - // ITopologyService - // **************** - - // - // ITopologyService interface methods - // - @Override - public Date getLastUpdateTime() { - return lastUpdateTime; - } - - @Override - public void addListener(ITopologyListener listener) { - topologyAware.add(listener); - } - - @Override - public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) { - return isAttachmentPointPort(switchid, port, true); - } - - @Override - public boolean isAttachmentPointPort(DatapathId switchid, OFPort port, - boolean tunnelEnabled) { - - // If the switch port is 'tun-bsn' port, it is not - // an attachment point port, irrespective of whether - // a link is found through it or not. - if (linkDiscovery.isTunnelPort(switchid, port)) - return false; - - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - - // if the port is not attachment point port according to - // topology instance, then return false - if (ti.isAttachmentPointPort(switchid, port) == false) - return false; - - // Check whether the port is a physical port. We should not learn - // attachment points on "special" ports. - //TODO @Ryan port numbers should be handled as ints now, not shorts. I suppose anything above 65280 up to 65533 is a "special" non-physical port. - if ((port.getShortPortNumber() & 0xff00) == 0xff00 && port.getShortPortNumber() != (short)0xfffe) return false; - - // Make sure that the port is enabled. - IOFSwitch sw = switchService.getActiveSwitch(switchid); - if (sw == null) return false; - return (sw.portEnabled(port)); - } - - @Override - public DatapathId getOpenflowDomainId(DatapathId switchId) { - return getOpenflowDomainId(switchId, true); - } - - @Override - public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getOpenflowDomainId(switchId); - } - - @Override - public DatapathId getL2DomainId(DatapathId switchId) { - return getL2DomainId(switchId, true); - } - - @Override - public DatapathId getL2DomainId(DatapathId switchId, boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getL2DomainId(switchId); - } - - @Override - public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) { - return inSameOpenflowDomain(switch1, switch2, true); - } - - @Override - public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.inSameOpenflowDomain(switch1, switch2); - } - - @Override - public boolean isAllowed(DatapathId sw, OFPort portId) { - return isAllowed(sw, portId, true); - } - - @Override - public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.isAllowed(sw, portId); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - @Override - public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId) { - return isIncomingBroadcastAllowed(sw, portId, true); - } - - @Override - public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - /** Get all the ports connected to the switch */ - @Override - public Set<OFPort> getPortsWithLinks(DatapathId sw) { - return getPortsWithLinks(sw, true); - } - - /** Get all the ports connected to the switch */ - @Override - public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getPortsWithLinks(sw); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - /** Get all the ports on the target switch (targetSw) on which a - * broadcast packet must be sent from a host whose attachment point - * is on switch port (src, srcPort). - */ - @Override - public Set<OFPort> getBroadcastPorts(DatapathId targetSw, - DatapathId src, OFPort srcPort) { - return getBroadcastPorts(targetSw, src, srcPort, true); - } - - /** Get all the ports on the target switch (targetSw) on which a - * broadcast packet must be sent from a host whose attachment point - * is on switch port (src, srcPort). - */ - @Override - public Set<OFPort> getBroadcastPorts(DatapathId targetSw, - DatapathId src, OFPort srcPort, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getBroadcastPorts(targetSw, src, srcPort); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - @Override - public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort) { - // Use this function to redirect traffic if needed. - return getOutgoingSwitchPort(src, srcPort, dst, dstPort, true); - } - - @Override - public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort, - boolean tunnelEnabled) { - // Use this function to redirect traffic if needed. - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getOutgoingSwitchPort(src, srcPort, - dst, dstPort); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - @Override - public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort) { - return getIncomingSwitchPort(src, srcPort, dst, dstPort, true); - } - - @Override - public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort, - DatapathId dst, OFPort dstPort, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getIncomingSwitchPort(src, srcPort, - dst, dstPort); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - /** - * Checks if the two switchports belong to the same broadcast domain. - */ - @Override - public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2, - OFPort p2) { - return isInSameBroadcastDomain(s1, p1, s2, p2, true); - - } - - @Override - public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1, - DatapathId s2, OFPort p2, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.inSameBroadcastDomain(s1, p1, s2, p2); - - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - /** - * Checks if the switchport is a broadcast domain port or not. - */ - @Override - public boolean isBroadcastDomainPort(DatapathId sw, OFPort port) { - return isBroadcastDomainPort(sw, port, true); - } - - @Override - public boolean isBroadcastDomainPort(DatapathId sw, OFPort port, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.isBroadcastDomainPort(new NodePortTuple(sw, port)); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - /** - * Checks if the new attachment point port is consistent with the - * old attachment point port. - */ - @Override - public boolean isConsistent(DatapathId oldSw, OFPort oldPort, - DatapathId newSw, OFPort newPort) { - return isConsistent(oldSw, oldPort, - newSw, newPort, true); - } - - @Override - public boolean isConsistent(DatapathId oldSw, OFPort oldPort, - DatapathId newSw, OFPort newPort, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.isConsistent(oldSw, oldPort, newSw, newPort); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - /** - * Checks if the two switches are in the same Layer 2 domain. - */ - @Override - public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) { - return inSameL2Domain(switch1, switch2, true); - } - - @Override - public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.inSameL2Domain(switch1, switch2); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - @Override - public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src, - OFPort srcPort, - DatapathId dst, - OFPort dstPort) { - return getAllowedOutgoingBroadcastPort(src, srcPort, - dst, dstPort, true); - } - - @Override - public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src, - OFPort srcPort, - DatapathId dst, - OFPort dstPort, - boolean tunnelEnabled){ - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getAllowedOutgoingBroadcastPort(src, srcPort, - dst, dstPort); - } - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - @Override - public NodePortTuple - getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) { - return getAllowedIncomingBroadcastPort(src,srcPort, true); - } - - @Override - public NodePortTuple - getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getAllowedIncomingBroadcastPort(src,srcPort); - } - - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - @Override - public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID) { - return getSwitchesInOpenflowDomain(switchDPID, true); - } - - @Override - public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getSwitchesInOpenflowDomain(switchDPID); - } - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - - @Override - public Set<NodePortTuple> getBroadcastDomainPorts() { - return portBroadcastDomainLinks.keySet(); - } - - @Override - public Set<NodePortTuple> getTunnelPorts() { - return tunnelPorts; - } - - @Override - public Set<NodePortTuple> getBlockedPorts() { - Set<NodePortTuple> bp; - Set<NodePortTuple> blockedPorts = - new HashSet<NodePortTuple>(); - - // As we might have two topologies, simply get the union of - // both of them and send it. - bp = getCurrentInstance(true).getBlockedPorts(); - if (bp != null) - blockedPorts.addAll(bp); - - bp = getCurrentInstance(false).getBlockedPorts(); - if (bp != null) - blockedPorts.addAll(bp); - - return blockedPorts; - } - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - - // *************** - // IRoutingService - // *************** - - @Override - public Route getRoute(DatapathId src, DatapathId dst, long cookie) { - return getRoute(src, dst, cookie, true); - } - - @Override - public Route getRoute(DatapathId src, DatapathId dst, long cookie, boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getRoute(src, dst, cookie); - } - - @Override - public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, long cookie) { - return getRoute(src, srcPort, dst, dstPort, cookie, true); - } - - @Override - public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, long cookie, - boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getRoute(null, src, srcPort, dst, dstPort, cookie); - } - - @Override - public boolean routeExists(DatapathId src, DatapathId dst) { - return routeExists(src, dst, true); - } - - @Override - public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled) { - TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.routeExists(src, dst); - } - - @Override - public ArrayList<Route> getRoutes(DatapathId srcDpid, DatapathId dstDpid, - boolean tunnelEnabled) { - // Floodlight supports single path routing now - - // return single path now - ArrayList<Route> result=new ArrayList<Route>(); - result.add(getRoute(srcDpid, dstDpid, 0, tunnelEnabled)); - return result; - } - - // ****************** - // IOFMessageListener - // ****************** - - @Override - public String getName() { - return MODULE_NAME; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - return "linkdiscovery".equals(name); - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - return false; - } - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, - FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - ctrIncoming.increment(); - return this.processPacketInMessage(sw, - (OFPacketIn) msg, cntx); - default: - break; - } - - return Command.CONTINUE; - } - - // *************** - // IHAListener - // *************** - - private class HAListenerDelegate implements IHAListener { - @Override - public void transitionToActive() { - role = HARole.ACTIVE; - log.debug("Re-computing topology due " + - "to HA change from STANDBY->ACTIVE"); - newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, - TimeUnit.MILLISECONDS); - } - - @Override - public void controllerNodeIPsChanged( - Map<String, String> curControllerNodeIPs, - Map<String, String> addedControllerNodeIPs, - Map<String, String> removedControllerNodeIPs) { - // no-op - } - - @Override - public String getName() { - return TopologyManager.this.getName(); - } - - @Override - public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type, - String name) { - return "linkdiscovery".equals(name) || - "tunnelmanager".equals(name); - } - - @Override - public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type, - String name) { - // TODO Auto-generated method stub - return false; - } - - @Override - public void transitionToStandby() { - // TODO Auto-generated method stub - - } - } - - // ***************** - // IFloodlightModule - // ***************** - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(ITopologyService.class); - l.add(IRoutingService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - // We are the class that implements the service - m.put(ITopologyService.class, this); - m.put(IRoutingService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(ILinkDiscoveryService.class); - l.add(IThreadPoolService.class); - l.add(IFloodlightProviderService.class); - l.add(IOFSwitchService.class); - l.add(ICounterStoreService.class); - l.add(IRestApiService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class); - threadPool = context.getServiceImpl(IThreadPoolService.class); - floodlightProvider = - context.getServiceImpl(IFloodlightProviderService.class); - switchService = context.getServiceImpl(IOFSwitchService.class); - restApi = context.getServiceImpl(IRestApiService.class); - debugCounters = context.getServiceImpl(IDebugCounterService.class); - debugEvents = context.getServiceImpl(IDebugEventService.class); - - switchPorts = new HashMap<DatapathId, Set<OFPort>>(); - switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); - directLinks = new HashMap<NodePortTuple, Set<Link>>(); - portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>(); - tunnelPorts = new HashSet<NodePortTuple>(); - topologyAware = new ArrayList<ITopologyListener>(); - ldUpdates = new LinkedBlockingQueue<LDUpdate>(); - haListener = new HAListenerDelegate(); - registerTopologyDebugCounters(); - registerTopologyDebugEvents(); - } - - protected void registerTopologyDebugEvents() throws FloodlightModuleException { - if (debugEvents == null) { - debugEvents = new NullDebugEvent(); - } - try { - evTopology = - debugEvents.registerEvent(PACKAGE, "topologyevent", - "Topology Computation", - EventType.ALWAYS_LOG, - TopologyEvent.class, 100); - } catch (MaxEventsRegistered e) { - throw new FloodlightModuleException("Max events registered", e); - } - } - - @Override - public void startUp(FloodlightModuleContext context) { - clearCurrentTopology(); - // Initialize role to floodlight provider role. - this.role = floodlightProvider.getRole(); - - ScheduledExecutorService ses = threadPool.getScheduledExecutor(); - newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker()); - - if (role != HARole.STANDBY) - newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, - TimeUnit.MILLISECONDS); - - linkDiscovery.addListener(this); - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - floodlightProvider.addHAListener(this.haListener); - addRestletRoutable(); - } - - private void registerTopologyDebugCounters() throws FloodlightModuleException { - if (debugCounters == null) { - log.error("Debug Counter Service not found."); - debugCounters = new NullDebugCounter(); - } - try { - ctrIncoming = debugCounters.registerCounter(PACKAGE, "incoming", - "All incoming packets seen by this module", - CounterType.ALWAYS_COUNT); - } catch (CounterException e) { - throw new FloodlightModuleException(e.getMessage()); - } - } - - protected void addRestletRoutable() { - restApi.addRestletRoutable(new TopologyWebRoutable()); - } - - // **************** - // Internal methods - // **************** - /** - * If the packet-in switch port is disabled for all data traffic, then - * the packet will be dropped. Otherwise, the packet will follow the - * normal processing chain. - * @param sw - * @param pi - * @param cntx - * @return - */ - protected Command dropFilter(DatapathId sw, OFPacketIn pi, - FloodlightContext cntx) { - Command result = Command.CONTINUE; - OFPort port = pi.getInPort(); - - // If the input port is not allowed for data traffic, drop everything. - // BDDP packets will not reach this stage. - if (isAllowed(sw, port) == false) { - if (log.isTraceEnabled()) { - log.trace("Ignoring packet because of topology " + - "restriction on switch={}, port={}", sw.getLong(), port.getPortNumber()); - result = Command.STOP; - } - } - return result; - } - - /** - * TODO This method must be moved to a layer below forwarding - * so that anyone can use it. - * @param packetData - * @param sw - * @param ports - * @param cntx - */ - @LogMessageDoc(level="ERROR", - message="Failed to clear all flows on switch {switch}", - explanation="An I/O error occured while trying send " + - "topology discovery packet", - recommendation=LogMessageDoc.CHECK_SWITCH) - public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw, - Set<OFPort> ports, - FloodlightContext cntx) { - - if (ports == null) return; - if (packetData == null || packetData.length <= 0) return; - - //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); - OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut(); - List<OFAction> actions = new ArrayList<OFAction>(); - for(OFPort p: ports) { - //actions.add(new OFActionOutput(p, (short) 0)); - actions.add(sw.getOFFactory().actions().output(p, 0)); - } - - // set actions - pob.setActions(actions); - // set action length - //po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * ports.size())); - // set buffer-id to BUFFER_ID_NONE - pob.setBufferId(OFBufferId.NO_BUFFER); - // set in-port to OFPP_NONE - pob.setInPort(OFPort.ZERO); - - // set packet data - pob.setData(packetData); - - // compute and set packet length. - //short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length); - - //po.setLength(poLength); - - try { - //counterStore.updatePktOutFMCounterStore(sw, po); - if (log.isTraceEnabled()) { - log.trace("write broadcast packet on switch-id={} " + - "interaces={} packet-data={} packet-out={}", - new Object[] {sw.getId(), ports, packetData, pob.build()}); - } - sw.write(pob.build(), LogicalOFMessageCategory.MAIN); - - } catch (IOException e) { - log.error("Failure writing packet out", e); - } - } - - /** - * Get the set of ports to eliminate for sending out BDDP. The method - * returns all the ports that are suppressed for link discovery on the - * switch. - * packets. - * @param sid - * @return - */ - protected Set<OFPort> getPortsToEliminateForBDDP(DatapathId sid) { - Set<NodePortTuple> suppressedNptList = linkDiscovery.getSuppressLLDPsInfo(); - if (suppressedNptList == null) return null; - - Set<OFPort> resultPorts = new HashSet<OFPort>(); - for(NodePortTuple npt: suppressedNptList) { - if (npt.getNodeId() == sid) { - resultPorts.add(npt.getPortId()); - } - } - - return resultPorts; - } - - /** - * The BDDP packets are forwarded out of all the ports out of an - * openflowdomain. Get all the switches in the same openflow - * domain as the sw (disabling tunnels). Then get all the - * external switch ports and send these packets out. - * @param sw - * @param pi - * @param cntx - */ - protected void doFloodBDDP(DatapathId pinSwitch, OFPacketIn pi, - FloodlightContext cntx) { - - TopologyInstance ti = getCurrentInstance(false); - - Set<DatapathId> switches = ti.getSwitchesInOpenflowDomain(pinSwitch); - - if (switches == null) - { - // indicates no links are connected to the switches - switches = new HashSet<DatapathId>(); - switches.add(pinSwitch); - } - - for(DatapathId sid: switches) { - IOFSwitch sw = switchService.getSwitch(sid); - if (sw == null) continue; - Collection<OFPort> enabledPorts = sw.getEnabledPortNumbers(); - if (enabledPorts == null) - continue; - Set<OFPort> ports = new HashSet<OFPort>(); - ports.addAll(enabledPorts); - - // all the ports known to topology // without tunnels. - // out of these, we need to choose only those that are - // broadcast port, otherwise, we should eliminate. - Set<OFPort> portsKnownToTopo = ti.getPortsWithLinks(sid); - - if (portsKnownToTopo != null) { - for(OFPort p: portsKnownToTopo) { - NodePortTuple npt = - new NodePortTuple(sid, p); - if (ti.isBroadcastDomainPort(npt) == false) { - ports.remove(p); - } - } - } - - Set<OFPort> portsToEliminate = getPortsToEliminateForBDDP(sid); - if (portsToEliminate != null) { - ports.removeAll(portsToEliminate); - } - - // remove the incoming switch port - if (pinSwitch == sid) { - ports.remove(pi.getInPort()); - } - - // we have all the switch ports to which we need to broadcast. - doMultiActionPacketOut(pi.getData(), sw, ports, cntx); - } - - } - - protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, - FloodlightContext cntx) { - - // get the packet-in switch. - Ethernet eth = - IFloodlightProviderService.bcStore. - get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - - if (eth.getPayload() instanceof BSN) { - BSN bsn = (BSN) eth.getPayload(); - if (bsn == null) return Command.STOP; - if (bsn.getPayload() == null) return Command.STOP; - - // It could be a packet other than BSN LLDP, therefore - // continue with the regular processing. - if (bsn.getPayload() instanceof LLDP == false) - return Command.CONTINUE; - - doFloodBDDP(sw.getId(), pi, cntx); - return Command.STOP; - } else { - return dropFilter(sw.getId(), pi, cntx); - } - } - - /** - * Updates concerning switch disconnect and port down are not processed. - * LinkDiscoveryManager is expected to process those messages and send - * multiple link removed messages. However, all the updates from - * LinkDiscoveryManager would be propagated to the listeners of topology. - */ - @LogMessageDoc(level="ERROR", - message="Error reading link discovery update.", - explanation="Unable to process link discovery update", - recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG) - public List<LDUpdate> applyUpdates() { - List<LDUpdate> appliedUpdates = new ArrayList<LDUpdate>(); - LDUpdate update = null; - while (ldUpdates.peek() != null) { - try { - update = ldUpdates.take(); - } catch (Exception e) { - log.error("Error reading link discovery update.", e); - } - if (log.isTraceEnabled()) { - log.trace("Applying update: {}", update); - } - - switch (update.getOperation()) { - case LINK_UPDATED: - addOrUpdateLink(update.getSrc(), update.getSrcPort(), - update.getDst(), update.getDstPort(), - update.getType()); - break; - case LINK_REMOVED: - removeLink(update.getSrc(), update.getSrcPort(), - update.getDst(), update.getDstPort()); - break; - case SWITCH_UPDATED: - addOrUpdateSwitch(update.getSrc()); - break; - case SWITCH_REMOVED: - removeSwitch(update.getSrc()); - break; - case TUNNEL_PORT_ADDED: - addTunnelPort(update.getSrc(), update.getSrcPort()); - break; - case TUNNEL_PORT_REMOVED: - removeTunnelPort(update.getSrc(), update.getSrcPort()); - break; - case PORT_UP: case PORT_DOWN: - break; - } - // Add to the list of applied updates. - appliedUpdates.add(update); - } - return (Collections.unmodifiableList(appliedUpdates)); - } - - protected void addOrUpdateSwitch(DatapathId sw) { - // nothing to do here for the time being. - return; - } - - public void addTunnelPort(DatapathId sw, OFPort port) { - NodePortTuple npt = new NodePortTuple(sw, port); - tunnelPorts.add(npt); - tunnelPortsUpdated = true; - } - - public void removeTunnelPort(DatapathId sw, OFPort port) { - NodePortTuple npt = new NodePortTuple(sw, port); - tunnelPorts.remove(npt); - tunnelPortsUpdated = true; - } - - public boolean createNewInstance() { - return createNewInstance("internal"); - } - - /** - * This function computes a new topology instance. - * It ignores links connected to all broadcast domain ports - * and tunnel ports. The method returns if a new instance of - * topology was created or not. - */ - protected boolean createNewInstance(String reason) { - Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>(); - - if (!linksUpdated) return false; - - Map<NodePortTuple, Set<Link>> openflowLinks; - openflowLinks = - new HashMap<NodePortTuple, Set<Link>>(); - Set<NodePortTuple> nptList = switchPortLinks.keySet(); - - if (nptList != null) { - for(NodePortTuple npt: nptList) { - Set<Link> linkSet = switchPortLinks.get(npt); - if (linkSet == null) continue; - openflowLinks.put(npt, new HashSet<Link>(linkSet)); - } - } - - // Identify all broadcast domain ports. - // Mark any port that has inconsistent set of links - // as broadcast domain ports as well. - Set<NodePortTuple> broadcastDomainPorts = - identifyBroadcastDomainPorts(); - - // Remove all links incident on broadcast domain ports. - for(NodePortTuple npt: broadcastDomainPorts) { - if (switchPortLinks.get(npt) == null) continue; - for(Link link: switchPortLinks.get(npt)) { - removeLinkFromStructure(openflowLinks, link); - } - } - - // Remove all tunnel links. - for(NodePortTuple npt: tunnelPorts) { - if (switchPortLinks.get(npt) == null) continue; - for(Link link: switchPortLinks.get(npt)) { - removeLinkFromStructure(openflowLinks, link); - } - } - - TopologyInstance nt = new TopologyInstance(switchPorts, - blockedPorts, - openflowLinks, - broadcastDomainPorts, - tunnelPorts); - nt.compute(); - // We set the instances with and without tunnels to be identical. - // If needed, we may compute them differently. - currentInstance = nt; - currentInstanceWithoutTunnels = nt; - - TopologyEventInfo topologyInfo = - new TopologyEventInfo(0, nt.getClusters().size(), - new HashMap<DatapathId, List<NodePortTuple>>(), - 0); - evTopology.updateEventWithFlush(new TopologyEvent(reason, - topologyInfo)); - return true; - } - - /** - * We expect every switch port to have at most two links. Both these - * links must be unidirectional links connecting to the same switch port. - * If not, we will mark this as a broadcast domain port. - */ - protected Set<NodePortTuple> identifyBroadcastDomainPorts() { - - Set<NodePortTuple> broadcastDomainPorts = - new HashSet<NodePortTuple>(); - broadcastDomainPorts.addAll(this.portBroadcastDomainLinks.keySet()); - - Set<NodePortTuple> additionalNpt = - new HashSet<NodePortTuple>(); - - // Copy switchPortLinks - Map<NodePortTuple, Set<Link>> spLinks = - new HashMap<NodePortTuple, Set<Link>>(); - for(NodePortTuple npt: switchPortLinks.keySet()) { - spLinks.put(npt, new HashSet<Link>(switchPortLinks.get(npt))); - } - - for(NodePortTuple npt: spLinks.keySet()) { - Set<Link> links = spLinks.get(npt); - boolean bdPort = false; - ArrayList<Link> linkArray = new ArrayList<Link>(); - if (links.size() > 2) { - bdPort = true; - } else if (links.size() == 2) { - for(Link l: links) { - linkArray.add(l); - } - // now, there should be two links in [0] and [1]. - Link l1 = linkArray.get(0); - Link l2 = linkArray.get(1); - - // check if these two are symmetric. - if (l1.getSrc() != l2.getDst() || - l1.getSrcPort() != l2.getDstPort() || - l1.getDst() != l2.getSrc() || - l1.getDstPort() != l2.getSrcPort()) { - bdPort = true; - } - } - - if (bdPort && (broadcastDomainPorts.contains(npt) == false)) { - additionalNpt.add(npt); - } - } - - if (additionalNpt.size() > 0) { - log.warn("The following switch ports have multiple " + - "links incident on them, so these ports will be treated " + - " as braodcast domain ports. {}", additionalNpt); - - broadcastDomainPorts.addAll(additionalNpt); - } - return broadcastDomainPorts; - } - - - - public void informListeners(List<LDUpdate> linkUpdates) { - - if (role != null && role != HARole.ACTIVE) - return; - - for(int i=0; i < topologyAware.size(); ++i) { - ITopologyListener listener = topologyAware.get(i); - listener.topologyChanged(linkUpdates); - } - } - - public void addSwitch(DatapathId sid) { - if (switchPorts.containsKey(sid) == false) { - switchPorts.put(sid, new HashSet<OFPort>()); - } - } - - private void addPortToSwitch(DatapathId s, OFPort p) { - addSwitch(s); - switchPorts.get(s).add(p); - } - - public void removeSwitch(DatapathId sid) { - // Delete all the links in the switch, switch and all - // associated data should be deleted. - if (switchPorts.containsKey(sid) == false) return; - - // Check if any tunnel ports need to be removed. - for(NodePortTuple npt: tunnelPorts) { - if (npt.getNodeId() == sid) { - removeTunnelPort(npt.getNodeId(), npt.getPortId()); - } - } - - Set<Link> linksToRemove = new HashSet<Link>(); - for(OFPort p: switchPorts.get(sid)) { - NodePortTuple n1 = new NodePortTuple(sid, p); - linksToRemove.addAll(switchPortLinks.get(n1)); - } - - if (linksToRemove.isEmpty()) return; - - for(Link link: linksToRemove) { - removeLink(link); - } - } - - /** - * Add the given link to the data structure. Returns true if a link was - * added. - * @param s - * @param l - * @return - */ - private boolean addLinkToStructure(Map<NodePortTuple, - Set<Link>> s, Link l) { - boolean result1 = false, result2 = false; - - NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); - NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); - - if (s.get(n1) == null) { - s.put(n1, new HashSet<Link>()); - } - if (s.get(n2) == null) { - s.put(n2, new HashSet<Link>()); - } - result1 = s.get(n1).add(l); - result2 = s.get(n2).add(l); - - return (result1 || result2); - } - - /** - * Delete the given link from the data strucure. Returns true if the - * link was deleted. - * @param s - * @param l - * @return - */ - private boolean removeLinkFromStructure(Map<NodePortTuple, - Set<Link>> s, Link l) { - - boolean result1 = false, result2 = false; - NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); - NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); - - if (s.get(n1) != null) { - result1 = s.get(n1).remove(l); - if (s.get(n1).isEmpty()) s.remove(n1); - } - if (s.get(n2) != null) { - result2 = s.get(n2).remove(l); - if (s.get(n2).isEmpty()) s.remove(n2); - } - return result1 || result2; - } - - protected void addOrUpdateTunnelLink(DatapathId srcId, OFPort srcPort, DatapathId dstId, - OFPort dstPort) { - // If you need to handle tunnel links, this is a placeholder. - } - - public void addOrUpdateLink(DatapathId srcId, OFPort srcPort, DatapathId dstId, - OFPort dstPort, LinkType type) { - Link link = new Link(srcId, srcPort, dstId, dstPort); - - if (type.equals(LinkType.MULTIHOP_LINK)) { - addPortToSwitch(srcId, srcPort); - addPortToSwitch(dstId, dstPort); - addLinkToStructure(switchPortLinks, link); - - addLinkToStructure(portBroadcastDomainLinks, link); - dtLinksUpdated = removeLinkFromStructure(directLinks, link); - linksUpdated = true; - } else if (type.equals(LinkType.DIRECT_LINK)) { - addPortToSwitch(srcId, srcPort); - addPortToSwitch(dstId, dstPort); - addLinkToStructure(switchPortLinks, link); - - addLinkToStructure(directLinks, link); - removeLinkFromStructure(portBroadcastDomainLinks, link); - dtLinksUpdated = true; - linksUpdated = true; - } else if (type.equals(LinkType.TUNNEL)) { - addOrUpdateTunnelLink(srcId, srcPort, dstId, dstPort); - } - } - - public void removeLink(Link link) { - linksUpdated = true; - dtLinksUpdated = removeLinkFromStructure(directLinks, link); - removeLinkFromStructure(portBroadcastDomainLinks, link); - removeLinkFromStructure(switchPortLinks, link); - - NodePortTuple srcNpt = - new NodePortTuple(link.getSrc(), link.getSrcPort()); - NodePortTuple dstNpt = - new NodePortTuple(link.getDst(), link.getDstPort()); - - // Remove switch ports if there are no links through those switch ports - if (switchPortLinks.get(srcNpt) == null) { - if (switchPorts.get(srcNpt.getNodeId()) != null) - switchPorts.get(srcNpt.getNodeId()).remove(srcNpt.getPortId()); - } - if (switchPortLinks.get(dstNpt) == null) { - if (switchPorts.get(dstNpt.getNodeId()) != null) - switchPorts.get(dstNpt.getNodeId()).remove(dstNpt.getPortId()); - } - - // Remove the node if no ports are present - if (switchPorts.get(srcNpt.getNodeId())!=null && - switchPorts.get(srcNpt.getNodeId()).isEmpty()) { - switchPorts.remove(srcNpt.getNodeId()); - } - if (switchPorts.get(dstNpt.getNodeId())!=null && - switchPorts.get(dstNpt.getNodeId()).isEmpty()) { - switchPorts.remove(dstNpt.getNodeId()); - } - } - - public void removeLink(DatapathId srcId, OFPort srcPort, - DatapathId dstId, OFPort dstPort) { - Link link = new Link(srcId, srcPort, dstId, dstPort); - removeLink(link); - } - - public void clear() { - switchPorts.clear(); - tunnelPorts.clear(); - switchPortLinks.clear(); - portBroadcastDomainLinks.clear(); - directLinks.clear(); - } - - /** - * Clears the current topology. Note that this does NOT - * send out updates. - */ - public void clearCurrentTopology() { - this.clear(); - linksUpdated = true; - dtLinksUpdated = true; - tunnelPortsUpdated = true; - createNewInstance("startup"); - lastUpdateTime = new Date(); - } - - /** - * Getters. No Setters. - */ - public Map<DatapathId, Set<OFPort>> getSwitchPorts() { - return switchPorts; - } - - public Map<NodePortTuple, Set<Link>> getSwitchPortLinks() { - return switchPortLinks; - } - - public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() { - return portBroadcastDomainLinks; - } - - public TopologyInstance getCurrentInstance(boolean tunnelEnabled) { - if (tunnelEnabled) - return currentInstance; - else return this.currentInstanceWithoutTunnels; - } - - public TopologyInstance getCurrentInstance() { - return this.getCurrentInstance(true); - } - - /** - * Switch methods - */ - @Override - public Set<OFPort> getPorts(DatapathId sw) { - IOFSwitch iofSwitch = switchService.getSwitch(sw); - if (iofSwitch == null) return Collections.emptySet(); - - Collection<OFPort> ofpList = iofSwitch.getEnabledPortNumbers(); - if (ofpList == null) return Collections.emptySet(); - - Set<OFPort> ports = new HashSet<OFPort>(ofpList); - Set<OFPort> qPorts = linkDiscovery.getQuarantinedPorts(sw); - if (qPorts != null) - ports.removeAll(qPorts); - - return ports; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java deleted file mode 100644 index bc619e5ae31b2d4809488f2485c6686b43c1f133..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology.web; - -import java.util.Set; - -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class BlockedPortsResource extends ServerResource { - @Get("json") - public Set<NodePortTuple> retrieve() { - ITopologyService topology = - (ITopologyService)getContext().getAttributes(). - get(ITopologyService.class.getCanonicalName()); - - return topology.getBlockedPorts(); - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.java deleted file mode 100644 index ea4ffeb8ebaa8304e43c9096b0ffedb1699476c0..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology.web; - -import java.util.Set; - -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class BroadcastDomainPortsResource extends ServerResource { - @Get("json") - public Set<NodePortTuple> retrieve() { - ITopologyService topology = - (ITopologyService)getContext().getAttributes(). - get(ITopologyService.class.getCanonicalName()); - - return topology.getBroadcastDomainPorts(); - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java deleted file mode 100644 index af1467a2d5544d47290ce879191455ab7263be2d..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology.web; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class EnabledPortsResource extends ServerResource { - @Get("json") - public List<NodePortTuple> retrieve() { - List<NodePortTuple> result = new ArrayList<NodePortTuple>(); - - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); - - ITopologyService topology= - (ITopologyService)getContext().getAttributes(). - get(ITopologyService.class.getCanonicalName()); - - if (floodlightProvider == null || topology == null) - return result; - - Set<Long> switches = floodlightProvider.getAllSwitchDpids(); - if (switches == null) return result; - - for(long sw: switches) { - Set<Short> ports = topology.getPorts(sw); - if (ports == null) continue; - for(short p: ports) { - result.add(new NodePortTuple(sw, p)); - } - } - return result; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java b/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java deleted file mode 100644 index b6bfe8d6615831bf2599febb19529271addf7ea1..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology.web; - -import java.util.List; - -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.topology.NodePortTuple; - -import org.openflow.util.HexString; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RouteResource extends ServerResource { - - protected static Logger log = LoggerFactory.getLogger(RouteResource.class); - - @Get("json") - public List<NodePortTuple> retrieve() { - IRoutingService routing = - (IRoutingService)getContext().getAttributes(). - get(IRoutingService.class.getCanonicalName()); - - String srcDpid = (String) getRequestAttributes().get("src-dpid"); - String srcPort = (String) getRequestAttributes().get("src-port"); - String dstDpid = (String) getRequestAttributes().get("dst-dpid"); - String dstPort = (String) getRequestAttributes().get("dst-port"); - - log.debug( srcDpid + "--" + srcPort + "--" + dstDpid + "--" + dstPort); - - long longSrcDpid = HexString.toLong(srcDpid); - short shortSrcPort = Short.parseShort(srcPort); - long longDstDpid = HexString.toLong(dstDpid); - short shortDstPort = Short.parseShort(dstPort); - - Route result = routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, 0); - - if (result!=null) { - return routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, 0).getPath(); - } - else { - log.debug("ERROR! no route found"); - return null; - } - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java deleted file mode 100644 index 6ba1704967f6b9351fa0b4ea261f618966e23e60..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java +++ /dev/null @@ -1,70 +0,0 @@ -/** -* 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.topology.web; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.topology.ITopologyService; - -import org.openflow.util.HexString; -import org.restlet.data.Form; -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -/** - * Returns a JSON map of <ClusterId, List<SwitchDpids>> - */ -public class SwitchClustersResource extends ServerResource { - @Get("json") - public Map<String, List<String>> retrieve() { - IFloodlightProviderService floodlightProvider = - (IFloodlightProviderService)getContext().getAttributes(). - get(IFloodlightProviderService.class.getCanonicalName()); - ITopologyService topology = - (ITopologyService)getContext().getAttributes(). - get(ITopologyService.class.getCanonicalName()); - - Form form = getQuery(); - String queryType = form.getFirstValue("type", true); - boolean openflowDomain = true; - if (queryType != null && "l2".equals(queryType)) { - openflowDomain = false; - } - - Map<String, List<String>> switchClusterMap = new HashMap<String, List<String>>(); - for (Long dpid: floodlightProvider.getAllSwitchDpids()) { - Long clusterDpid = - (openflowDomain - ? topology.getOpenflowDomainId(dpid) - :topology.getL2DomainId(dpid)); - List<String> switchesInCluster = switchClusterMap.get(HexString.toHexString(clusterDpid)); - if (switchesInCluster != null) { - switchesInCluster.add(HexString.toHexString(dpid)); - } else { - List<String> l = new ArrayList<String>(); - l.add(HexString.toHexString(dpid)); - switchClusterMap.put(HexString.toHexString(clusterDpid), l); - } - } - return switchClusterMap; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java b/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java deleted file mode 100644 index 3174d31ae81a3d104d164b0bca8170fc603b1aa8..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology.web; - -import org.restlet.Context; -import org.restlet.routing.Router; - -import net.floodlightcontroller.linkdiscovery.web.DirectedLinksResource; -import net.floodlightcontroller.linkdiscovery.web.ExternalLinksResource; -import net.floodlightcontroller.linkdiscovery.web.LinksResource; -import net.floodlightcontroller.restserver.RestletRoutable; - -public class TopologyWebRoutable implements RestletRoutable { - /** - * Create the Restlet router and bind to the proper resources. - */ - @Override - public Router getRestlet(Context context) { - Router router = new Router(context); - router.attach("/links/json", LinksResource.class); - router.attach("/directed-links/json", DirectedLinksResource.class); - router.attach("/external-links/json", ExternalLinksResource.class); - router.attach("/tunnellinks/json", TunnelLinksResource.class); - router.attach("/switchclusters/json", SwitchClustersResource.class); - router.attach("/broadcastdomainports/json", BroadcastDomainPortsResource.class); - router.attach("/enabledports/json", EnabledPortsResource.class); - router.attach("/blockedports/json", BlockedPortsResource.class); - router.attach("/route/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", RouteResource.class); - return router; - } - - /** - * Set the base path for the Topology - */ - @Override - public String basePath() { - return "/wm/topology"; - } -} diff --git a/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java b/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java deleted file mode 100644 index 79e4ce438b440f46221320194f7071add73d4749..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology.web; - -import java.util.Set; - -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; - -import org.restlet.resource.Get; -import org.restlet.resource.ServerResource; - -public class TunnelLinksResource extends ServerResource { - @Get("json") - public Set<NodePortTuple> retrieve() { - ITopologyService topology = - (ITopologyService)getContext().getAttributes(). - get(ITopologyService.class.getCanonicalName()); - - return topology.getTunnelPorts(); - } -} diff --git a/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java b/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java deleted file mode 100644 index aab21fb643a6634b9d7693d642e59e14945e7f3e..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.ui.web; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; - -import org.restlet.Client; -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.data.Protocol; -import org.restlet.resource.Directory; -import org.restlet.routing.Router; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestletRoutable; - -public class StaticWebRoutable implements RestletRoutable, IFloodlightModule { - - private IRestApiService restApi; - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IRestApiService.class); - return l; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - return null; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - restApi = context.getServiceImpl(IRestApiService.class); - } - - @Override - public void startUp(FloodlightModuleContext context) { - // Add our REST API - restApi.addRestletRoutable(this); - - } - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("", new Directory(context, "clap://classloader/web/")); - context.setClientDispatcher(new Client(context, Protocol.CLAP)); - return router; - } - - @Override - public String basePath() { - return "/ui/"; - } - -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java b/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java deleted file mode 100644 index 03f0a63ae3b93f20a1b370048fd81884bbd83cf5..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import java.io.IOException; - -import net.floodlightcontroller.util.MACAddress; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.restlet.data.Status; -import org.restlet.resource.Delete; -import org.restlet.resource.Put; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class HostResource extends org.restlet.resource.ServerResource { - protected static Logger log = LoggerFactory.getLogger(HostResource.class); - - public class HostDefinition { - String port = null; // Logical port name - String guid = null; // Network ID - String mac = null; // MAC Address - String attachment = null; // Attachment name - } - - protected void jsonToHostDefinition(String json, HostDefinition host) throws IOException { - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - - try { - jp = f.createJsonParser(json); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - else if (n.equals("attachment")) { - while (jp.nextToken() != JsonToken.END_OBJECT) { - String field = jp.getCurrentName(); - if (field.equals("id")) { - host.attachment = jp.getText(); - } else if (field.equals("mac")) { - host.mac = jp.getText(); - } - } - } - } - - jp.close(); - } - - @Put - public String addHost(String postData) { - IVirtualNetworkService vns = - (IVirtualNetworkService)getContext().getAttributes(). - get(IVirtualNetworkService.class.getCanonicalName()); - HostDefinition host = new HostDefinition(); - host.port = (String) getRequestAttributes().get("port"); - host.guid = (String) getRequestAttributes().get("network"); - try { - jsonToHostDefinition(postData, host); - } catch (IOException e) { - log.error("Could not parse JSON {}", e.getMessage()); - } - vns.addHost(MACAddress.valueOf(host.mac), host.guid, host.port); - setStatus(Status.SUCCESS_OK); - return "{\"status\":\"ok\"}"; - } - - - @Delete - public String deleteHost() { - String port = (String) getRequestAttributes().get("port"); - IVirtualNetworkService vns = - (IVirtualNetworkService)getContext().getAttributes(). - get(IVirtualNetworkService.class.getCanonicalName()); - vns.deleteHost(null, port); - setStatus(Status.SUCCESS_OK); - return "{\"status\":\"ok\"}"; - } -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java b/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java deleted file mode 100644 index 993b2ffd04553bdab3ff9c73f5ac58fa1a0f283b..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import java.util.Collection; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.util.MACAddress; - -public interface IVirtualNetworkService extends IFloodlightService { - /** - * Creates a new virtual network. This can also be called - * to modify a virtual network. To update a network you specify the GUID - * and the fields you want to update. - * @param network The network name. Must be unique. - * @param guid The ID of the network. Must be unique. - * @param gateway The IP address of the network gateway, null if none. - */ - public void createNetwork(String guid, String network, Integer gateway); - - /** - * Deletes a virtual network. - * @param guid The ID (not name) of virtual network to delete. - */ - public void deleteNetwork(String guid); - - /** - * Adds a host to a virtual network. If a mapping already exists the - * new one will override the old mapping. - * @param mac The MAC address of the host to add. - * @param network The network to add the host to. - * @param port The logical port name to attach the host to. Must be unique. - */ - public void addHost(MACAddress mac, String network, String port); - - /** - * Deletes a host from a virtual network. Either the MAC or Port must - * be specified. - * @param mac The MAC address to delete. - * @param port The logical port the host is attached to. - */ - public void deleteHost(MACAddress mac, String port); - - /** - * Return list of all virtual networks. - * @return Collection <VirtualNetwork> - */ - public Collection <VirtualNetwork> listNetworks(); -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java b/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java deleted file mode 100644 index 35ff629f4c557f5185585c3440fbaa22e77d43c9..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import java.io.IOException; -import java.util.Collection; - -import net.floodlightcontroller.packet.IPv4; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import org.restlet.data.Status; -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.restlet.resource.Put; -import org.restlet.resource.ServerResource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NetworkResource extends ServerResource { - protected static Logger log = LoggerFactory.getLogger(NetworkResource.class); - - public class NetworkDefinition { - public String name = null; - public String guid = null; - public String gateway = null; - } - - protected void jsonToNetworkDefinition(String json, NetworkDefinition network) throws IOException { - MappingJsonFactory f = new MappingJsonFactory(); - JsonParser jp; - - try { - jp = f.createJsonParser(json); - } catch (JsonParseException e) { - throw new IOException(e); - } - - jp.nextToken(); - if (jp.getCurrentToken() != JsonToken.START_OBJECT) { - throw new IOException("Expected START_OBJECT"); - } - - while (jp.nextToken() != JsonToken.END_OBJECT) { - if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { - throw new IOException("Expected FIELD_NAME"); - } - - String n = jp.getCurrentName(); - jp.nextToken(); - if (jp.getText().equals("")) - continue; - else if (n.equals("network")) { - while (jp.nextToken() != JsonToken.END_OBJECT) { - String field = jp.getCurrentName(); - if (field == null) continue; - if (field.equals("name")) { - network.name = jp.getText(); - } else if (field.equals("gateway")) { - String gw = jp.getText(); - if ((gw != null) && (!gw.equals("null"))) - network.gateway = gw; - } else if (field.equals("id")) { - network.guid = jp.getText(); - } else { - log.warn("Unrecognized field {} in " + - "parsing network definition", - jp.getText()); - } - } - } - } - - jp.close(); - } - - @Get("json") - public Collection <VirtualNetwork> retrieve() { - IVirtualNetworkService vns = - (IVirtualNetworkService)getContext().getAttributes(). - get(IVirtualNetworkService.class.getCanonicalName()); - - return vns.listNetworks(); - } - - @Put - @Post - public String createNetwork(String postData) { - NetworkDefinition network = new NetworkDefinition(); - try { - jsonToNetworkDefinition(postData, network); - } catch (IOException e) { - log.error("Could not parse JSON {}", e.getMessage()); - } - - // We try to get the ID from the URI only if it's not - // in the POST data - if (network.guid == null) { - String guid = (String) getRequestAttributes().get("network"); - if ((guid != null) && (!guid.equals("null"))) - network.guid = guid; - } - - IVirtualNetworkService vns = - (IVirtualNetworkService)getContext().getAttributes(). - get(IVirtualNetworkService.class.getCanonicalName()); - - Integer gw = null; - if (network.gateway != null) { - try { - gw = IPv4.toIPv4Address(network.gateway); - } catch (IllegalArgumentException e) { - log.warn("Could not parse gateway {} as IP for network {}, setting as null", - network.gateway, network.name); - network.gateway = null; - } - } - vns.createNetwork(network.guid, network.name, gw); - setStatus(Status.SUCCESS_OK); - return "{\"status\":\"ok\"}"; - } - - @Delete - public String deleteNetwork() { - IVirtualNetworkService vns = - (IVirtualNetworkService)getContext().getAttributes(). - get(IVirtualNetworkService.class.getCanonicalName()); - String guid = (String) getRequestAttributes().get("network"); - vns.deleteNetwork(guid); - setStatus(Status.SUCCESS_OK); - return "{\"status\":\"ok\"}"; - } -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java b/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java deleted file mode 100644 index 9533056297b1b5ac0d10120040b27356b3808283..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/NoOp.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import org.restlet.data.Status; -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.restlet.resource.Put; -import org.restlet.resource.ServerResource; - -public class NoOp extends ServerResource { - /** - * Does nothing and returns 200 OK with a status message - * - * @return status: ok - */ - @Get - @Put - @Post - @Delete - public String noOp(String postdata) { - setStatus(Status.SUCCESS_OK); - return "{\"status\":\"ok\"}"; - } -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java deleted file mode 100644 index 829be702a36039fcfafa1140c68c6c958dffed2c..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import net.floodlightcontroller.util.MACAddress; - -/** - * Data structure for storing and outputing information of a virtual network created - * by VirtualNetworkFilter - * - * @author KC Wang - */ - -@JsonSerialize(using=VirtualNetworkSerializer.class) -public class VirtualNetwork{ - protected String name; // network name - protected String guid; // network id - protected String gateway; // network gateway - protected Map<String,MACAddress> portToMac; //port's logical namd and the host's mac address connected - /** - * Constructor requires network name and id - * @param name: network name - * @param guid: network id - */ - public VirtualNetwork(String name, String guid) { - this.name = name; - this.guid = guid; - this.gateway = null; - this.portToMac = new ConcurrentHashMap<String,MACAddress>(); - return; - } - - /** - * Sets network name - * @param gateway: IP address as String - */ - public void setName(String name){ - this.name = name; - return; - } - - /** - * Sets network gateway IP address - * @param gateway: IP address as String - */ - public void setGateway(String gateway){ - this.gateway = gateway; - return; - } - - /** - * Adds a host to this network record - * @param host: MAC address as MACAddress - */ - public void addHost(String port,MACAddress host){ - this.portToMac.put(port,host); // ignore old mapping - return; - } - - /** - * Removes a host from this network record - * @param host: MAC address as MACAddress - * @return boolean: true: removed, false: host not found - */ - public boolean removeHost(MACAddress host){ - for (Entry<String,MACAddress> entry : this.portToMac.entrySet()){ - if(entry.getValue().equals(host)){ - this.portToMac.remove(entry.getKey()); - return true; - } - } - return false; - } - - /** - * Removes all hosts from this network record - */ - public void clearHosts(){ - this.portToMac.clear(); - } -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java deleted file mode 100644 index 258368329d1a5c71023c73c2037e7d59c23c31ab..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java +++ /dev/null @@ -1,564 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.projectfloodlight.openflow.protocol.OFFlowMod; -import org.projectfloodlight.openflow.protocol.OFMatch; -import org.projectfloodlight.openflow.protocol.OFMessage; -import org.projectfloodlight.openflow.protocol.OFPacketIn; -import org.projectfloodlight.openflow.protocol.OFPacketOut; -import org.projectfloodlight.openflow.protocol.OFType; -import org.projectfloodlight.openflow.protocol.action.OFAction; -import org.projectfloodlight.util.HexString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.core.util.AppCookie; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceListener; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.packet.DHCP; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.routing.ForwardingBase; -import net.floodlightcontroller.util.MACAddress; - -/** - * A simple Layer 2 (MAC based) network virtualization module. This module allows - * you to create simple L2 networks (host + gateway) and will drop traffic if - * they are not on the same virtual network. - * - * LIMITATIONS - * - This module does not allow overlapping of IPs or MACs - * - You can only have 1 gateway per virtual network (can be shared) - * - There is filtering of multicast/broadcast traffic - * - All DHCP traffic will be allowed, regardless of unicast/broadcast - * - * @author alexreimers - */ -public class VirtualNetworkFilter - implements IFloodlightModule, IVirtualNetworkService, IOFMessageListener { - protected static Logger log = LoggerFactory.getLogger(VirtualNetworkFilter.class); - - private static final short APP_ID = 20; - static { - AppCookie.registerApp(APP_ID, "VirtualNetworkFilter"); - } - - // Our dependencies - IFloodlightProviderService floodlightProvider; - IRestApiService restApi; - IDeviceService deviceService; - - // Our internal state - protected Map<String, VirtualNetwork> vNetsByGuid; // List of all created virtual networks - protected Map<String, String> nameToGuid; // Logical name -> Network ID - protected Map<String, Integer> guidToGateway; // Network ID -> Gateway IP - protected Map<Integer, Set<String>> gatewayToGuid; // Gateway IP -> Network ID - protected Map<MACAddress, Integer> macToGateway; // Gateway MAC -> Gateway IP - protected Map<MACAddress, String> macToGuid; // Host MAC -> Network ID - protected Map<String, MACAddress> portToMac; // Host MAC -> logical port name - - // Device Listener impl class - protected DeviceListenerImpl deviceListener; - - /** - * Adds a gateway to a virtual network. - * @param guid The ID (not name) of the network. - * @param ip The IP addresses of the gateway. - */ - protected void addGateway(String guid, Integer ip) { - if (ip.intValue() != 0) { - if (log.isDebugEnabled()) { - log.debug("Adding {} as gateway for GUID {}", - IPv4.fromIPv4Address(ip), guid); - } - - guidToGateway.put(guid, ip); - if (vNetsByGuid.get(guid) != null) - vNetsByGuid.get(guid).setGateway(IPv4.fromIPv4Address(ip)); - if (gatewayToGuid.containsKey(ip)) { - Set<String> gSet = gatewayToGuid.get(ip); - gSet.add(guid); - } else { - Set<String> gSet = Collections.synchronizedSet(new HashSet<String>()); - gSet.add(guid); - gatewayToGuid.put(ip, gSet); - } - } - } - - /** - * Deletes a gateway for a virtual network. - * @param guid The ID (not name) of the network to delete - * the gateway for. - */ - protected void deleteGateway(String guid) { - Integer gwIp = guidToGateway.remove(guid); - if (gwIp == null) return; - Set<String> gSet = gatewayToGuid.get(gwIp); - gSet.remove(guid); - if(vNetsByGuid.get(guid)!=null) - vNetsByGuid.get(guid).setGateway(null); - } - - // IVirtualNetworkService - - @Override - public void createNetwork(String guid, String network, Integer gateway) { - if (log.isDebugEnabled()) { - String gw = null; - try { - gw = IPv4.fromIPv4Address(gateway); - } catch (Exception e) { - // fail silently - } - log.debug("Creating network {} with ID {} and gateway {}", - new Object[] {network, guid, gw}); - } - - if (!nameToGuid.isEmpty()) { - // We have to iterate all the networks to handle name/gateway changes - for (Entry<String, String> entry : nameToGuid.entrySet()) { - if (entry.getValue().equals(guid)) { - nameToGuid.remove(entry.getKey()); - break; - } - } - } - if(network != null) - nameToGuid.put(network, guid); - if (vNetsByGuid.containsKey(guid)) - vNetsByGuid.get(guid).setName(network); //network already exists, just updating name - else - vNetsByGuid.put(guid, new VirtualNetwork(network, guid)); //new network - - // If they don't specify a new gateway the old one will be preserved - if ((gateway != null) && (gateway != 0)) { - addGateway(guid, gateway); - if(vNetsByGuid.get(guid)!=null) - vNetsByGuid.get(guid).setGateway(IPv4.fromIPv4Address(gateway)); - } - } - - @Override - public void deleteNetwork(String guid) { - String name = null; - if (nameToGuid.isEmpty()) { - log.warn("Could not delete network with ID {}, network doesn't exist", - guid); - return; - } - for (Entry<String, String> entry : nameToGuid.entrySet()) { - if (entry.getValue().equals(guid)) { - name = entry.getKey(); - break; - } - log.warn("Could not delete network with ID {}, network doesn't exist", - guid); - } - - if (log.isDebugEnabled()) - log.debug("Deleting network with name {} ID {}", name, guid); - - nameToGuid.remove(name); - deleteGateway(guid); - if(vNetsByGuid.get(guid)!=null){ - vNetsByGuid.get(guid).clearHosts(); - vNetsByGuid.remove(guid); - } - Collection<MACAddress> deleteList = new ArrayList<MACAddress>(); - for (MACAddress host : macToGuid.keySet()) { - if (macToGuid.get(host).equals(guid)) { - deleteList.add(host); - } - } - for (MACAddress mac : deleteList) { - if (log.isDebugEnabled()) { - log.debug("Removing host {} from network {}", - HexString.toHexString(mac.toBytes()), guid); - } - macToGuid.remove(mac); - for (Entry<String, MACAddress> entry : portToMac.entrySet()) { - if (entry.getValue().equals(mac)) { - portToMac.remove(entry.getKey()); - break; - } - } - } - } - - @Override - public void addHost(MACAddress mac, String guid, String port) { - if (guid != null) { - if (log.isDebugEnabled()) { - log.debug("Adding {} to network ID {} on port {}", - new Object[] {mac, guid, port}); - } - // We ignore old mappings - macToGuid.put(mac, guid); - portToMac.put(port, mac); - if(vNetsByGuid.get(guid)!=null) - vNetsByGuid.get(guid).addHost(port,new MACAddress(mac.toBytes())); - } else { - log.warn("Could not add MAC {} to network ID {} on port {}, the network does not exist", - new Object[] {mac, guid, port}); - } - } - - @Override - public void deleteHost(MACAddress mac, String port) { - if (log.isDebugEnabled()) { - log.debug("Removing host {} from port {}", mac, port); - } - if (mac == null && port == null) return; - if (port != null) { - MACAddress host = portToMac.remove(port); - if(host !=null && vNetsByGuid.get(macToGuid.get(host)) != null) - vNetsByGuid.get(macToGuid.get(host)).removeHost(host); - if(host !=null) - macToGuid.remove(host); - } else if (mac != null) { - if (!portToMac.isEmpty()) { - for (Entry<String, MACAddress> entry : portToMac.entrySet()) { - if (entry.getValue().equals(mac)) { - if(vNetsByGuid.get(macToGuid.get(entry.getValue())) != null) - vNetsByGuid.get(macToGuid.get(entry.getValue())).removeHost(entry.getValue()); - portToMac.remove(entry.getKey()); - macToGuid.remove(entry.getValue()); - return; - } - } - } - } - } - - // IFloodlightModule - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IVirtualNetworkService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(IVirtualNetworkService.class, this); - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IFloodlightProviderService.class); - l.add(IRestApiService.class); - l.add(IDeviceService.class); - return l; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); - restApi = context.getServiceImpl(IRestApiService.class); - deviceService = context.getServiceImpl(IDeviceService.class); - - vNetsByGuid = new ConcurrentHashMap<String, VirtualNetwork>(); - nameToGuid = new ConcurrentHashMap<String, String>(); - guidToGateway = new ConcurrentHashMap<String, Integer>(); - gatewayToGuid = new ConcurrentHashMap<Integer, Set<String>>(); - macToGuid = new ConcurrentHashMap<MACAddress, String>(); - portToMac = new ConcurrentHashMap<String, MACAddress>(); - macToGateway = new ConcurrentHashMap<MACAddress, Integer>(); - deviceListener = new DeviceListenerImpl(); - - } - - @Override - public void startUp(FloodlightModuleContext context) { - floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); - restApi.addRestletRoutable(new VirtualNetworkWebRoutable()); - deviceService.addListener(this.deviceListener); - } - - // IOFMessageListener - - @Override - public String getName() { - return "virtualizer"; - } - - @Override - public boolean isCallbackOrderingPrereq(OFType type, String name) { - // Link discovery should go before us so we don't block LLDPs - return (type.equals(OFType.PACKET_IN) && - (name.equals("linkdiscovery") || (name.equals("devicemanager")))); - } - - @Override - public boolean isCallbackOrderingPostreq(OFType type, String name) { - // We need to go before forwarding - return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")); - } - - @Override - public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { - switch (msg.getType()) { - case PACKET_IN: - return processPacketIn(sw, (OFPacketIn)msg, cntx); - default: - break; - } - log.warn("Received unexpected message {}", msg); - return Command.CONTINUE; - } - - /** - * Checks whether the frame is destined to or from a gateway. - * @param frame The ethernet frame to check. - * @return True if it is to/from a gateway, false otherwise. - */ - protected boolean isDefaultGateway(Ethernet frame) { - if (macToGateway.containsKey(frame.getSourceMAC())) - return true; - - Integer gwIp = macToGateway.get(frame.getDestinationMAC()); - if (gwIp != null) { - MACAddress host = frame.getSourceMAC(); - String srcNet = macToGuid.get(host); - if (srcNet != null) { - Integer gwIpSrcNet = guidToGateway.get(srcNet); - if ((gwIpSrcNet != null) && (gwIp.equals(gwIpSrcNet))) - return true; - } - } - - return false; - } - - /** - * Checks to see if two MAC Addresses are on the same network. - * @param m1 The first MAC. - * @param m2 The second MAC. - * @return True if they are on the same virtual network, - * false otherwise. - */ - protected boolean oneSameNetwork(MACAddress m1, MACAddress m2) { - String net1 = macToGuid.get(m1); - String net2 = macToGuid.get(m2); - if (net1 == null) return false; - if (net2 == null) return false; - return net1.equals(net2); - } - - /** - * Checks to see if an Ethernet frame is a DHCP packet. - * @param frame The Ethernet frame. - * @return True if it is a DHCP frame, false otherwise. - */ - protected boolean isDhcpPacket(Ethernet frame) { - IPacket payload = frame.getPayload(); // IP - if (payload == null) return false; - IPacket p2 = payload.getPayload(); // TCP or UDP - if (p2 == null) return false; - IPacket p3 = p2.getPayload(); // Application - if ((p3 != null) && (p3 instanceof DHCP)) return true; - return false; - } - - /** - * Processes an OFPacketIn message and decides if the OFPacketIn should be dropped - * or the processing should continue. - * @param sw The switch the PacketIn came from. - * @param msg The OFPacketIn message from the switch. - * @param cntx The FloodlightContext for this message. - * @return Command.CONTINUE if processing should be continued, Command.STOP otherwise. - */ - protected Command processPacketIn(IOFSwitch sw, OFPacketIn msg, FloodlightContext cntx) { - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - Command ret = Command.STOP; - String srcNetwork = macToGuid.get(eth.getSourceMAC()); - // If the host is on an unknown network we deny it. - // We make exceptions for ARP and DHCP. - if (eth.isBroadcast() || eth.isMulticast() || isDefaultGateway(eth) || isDhcpPacket(eth)) { - ret = Command.CONTINUE; - } else if (srcNetwork == null) { - log.trace("Blocking traffic from host {} because it is not attached to any network.", - HexString.toHexString(eth.getSourceMACAddress())); - ret = Command.STOP; - } else if (oneSameNetwork(eth.getSourceMAC(), eth.getDestinationMAC())) { - // if they are on the same network continue - ret = Command.CONTINUE; - } - - if (log.isTraceEnabled()) - log.trace("Results for flow between {} and {} is {}", - new Object[] {eth.getSourceMAC(), eth.getDestinationMAC(), ret}); - /* - * TODO - figure out how to still detect gateways while using - * drop mods - if (ret == Command.STOP) { - if (!(eth.getPayload() instanceof ARP)) - doDropFlow(sw, msg, cntx); - } - */ - return ret; - } - - /** - * Writes a FlowMod to a switch that inserts a drop flow. - * @param sw The switch to write the FlowMod to. - * @param pi The corresponding OFPacketIn. Used to create the OFMatch structure. - * @param cntx The FloodlightContext that gets passed to the switch. - */ - protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { - if (log.isTraceEnabled()) { - log.trace("doDropFlow pi={} srcSwitch={}", - new Object[] { pi, sw }); - } - - if (sw == null) { - log.warn("Switch is null, not installing drop flowmod for PacketIn {}", pi); - return; - } - - // Create flow-mod based on packet-in and src-switch - OFFlowMod fm = - (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); - OFMatch match = new OFMatch(); - match.loadFromPacket(pi.getPacketData(), pi.getInPort()); - List<OFAction> actions = new ArrayList<OFAction>(); // no actions = drop - long cookie = AppCookie.makeCookie(APP_ID, 0); - fm.setCookie(cookie) - .setIdleTimeout(ForwardingBase.FLOWMOD_DEFAULT_IDLE_TIMEOUT) - .setHardTimeout(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setMatch(match) - .setActions(actions) - .setLengthU(OFFlowMod.MINIMUM_LENGTH); -// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM); - try { - if (log.isTraceEnabled()) { - log.trace("write drop flow-mod srcSwitch={} match={} " + - "pi={} flow-mod={}", - new Object[] {sw, match, pi, fm}); - } - sw.write(fm, cntx); - } catch (IOException e) { - log.error("Failure writing drop flow mod", e); - } - return; - } - - @Override - public Collection <VirtualNetwork> listNetworks() { - return vNetsByGuid.values(); - } - - // IDeviceListener - class DeviceListenerImpl implements IDeviceListener{ - @Override - public void deviceAdded(IDevice device) { - if (device.getIPv4Addresses() == null) return; - for (Integer i : device.getIPv4Addresses()) { - if (gatewayToGuid.containsKey(i)) { - MACAddress mac = MACAddress.valueOf(device.getMACAddress()); - if (log.isDebugEnabled()) - log.debug("Adding MAC {} with IP {} a a gateway", - HexString.toHexString(mac.toBytes()), - IPv4.fromIPv4Address(i)); - macToGateway.put(mac, i); - } - } - } - - @Override - public void deviceRemoved(IDevice device) { - // if device is a gateway remove - MACAddress mac = MACAddress.valueOf(device.getMACAddress()); - if (macToGateway.containsKey(mac)) { - if (log.isDebugEnabled()) - log.debug("Removing MAC {} as a gateway", - HexString.toHexString(mac.toBytes())); - macToGateway.remove(mac); - } - } - - @Override - public void deviceIPV4AddrChanged(IDevice device) { - // add or remove entry as gateway - deviceAdded(device); - } - - @Override - public void deviceMoved(IDevice device) { - // ignore - } - - @Override - public void deviceVlanChanged(IDevice device) { - // ignore - } - - @Override - public String getName() { - return VirtualNetworkFilter.this.getName(); - } - - @Override - public boolean isCallbackOrderingPrereq(String type, String name) { - return false; - } - - @Override - public boolean isCallbackOrderingPostreq(String type, String name) { - // We need to go before forwarding - return false; - } - } -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java deleted file mode 100644 index 190432ab7aeacefcaa89054ecebbb59e26845811..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import java.io.IOException; -import java.util.Iterator; -import java.util.Map.Entry; - -import net.floodlightcontroller.util.MACAddress; - -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 a VirtualNetwork object - * @author KC Wang - */ -public class VirtualNetworkSerializer extends JsonSerializer<VirtualNetwork> { - - @Override - public void serialize(VirtualNetwork vNet, JsonGenerator jGen, - SerializerProvider serializer) throws IOException, - JsonProcessingException { - jGen.writeStartObject(); - - jGen.writeStringField("name", vNet.name); - jGen.writeStringField("guid", vNet.guid); - jGen.writeStringField("gateway", vNet.gateway); - - jGen.writeArrayFieldStart("portMac"); - Iterator entries = vNet.portToMac.entrySet().iterator(); - while (entries.hasNext()){ - jGen.writeStartObject(); - Entry entry = (Entry)entries.next(); - jGen.writeStringField("port",entry.getKey().toString()); - jGen.writeStringField("mac",entry.getValue().toString()); - jGen.writeEndObject(); - } - jGen.writeEndArray(); - - jGen.writeEndObject(); - } - -} diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkWebRoutable.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkWebRoutable.java deleted file mode 100644 index 8e857095004242997ff5ba12b33f1bdb7446f808..0000000000000000000000000000000000000000 --- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkWebRoutable.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import org.restlet.Context; -import org.restlet.Restlet; -import org.restlet.routing.Router; - -import net.floodlightcontroller.restserver.RestletRoutable; - -public class VirtualNetworkWebRoutable implements RestletRoutable { - - @Override - public Restlet getRestlet(Context context) { - Router router = new Router(context); - router.attach("/tenants/{tenant}/networks", NetworkResource.class); // GET - router.attach("/tenants/{tenant}/networks/{network}", NetworkResource.class); // PUT, DELETE - router.attach("/tenants/{tenant}/networks", NetworkResource.class); // POST - router.attach("/tenants/{tenant}/networks/{network}/ports/{port}/attachment", HostResource.class); - router.attachDefault(NoOp.class); - return router; - } - - @Override - public String basePath() { - return "/networkService/v1.1"; - } -} \ No newline at end of file diff --git a/src/main/java/org/sdnplatform/sync/internal/SyncManager.java b/src/main/java/org/sdnplatform/sync/internal/SyncManager.java index 952918c50217c91cc5a2c30b39a1f9c7cbf4b60b..86d1260504ef3c643dbd9108c9be00a42c62e47a 100644 --- a/src/main/java/org/sdnplatform/sync/internal/SyncManager.java +++ b/src/main/java/org/sdnplatform/sync/internal/SyncManager.java @@ -60,8 +60,6 @@ import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.SingletonTask; import net.floodlightcontroller.debugcounter.IDebugCounter; import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.threadpool.IThreadPoolService; @@ -513,39 +511,27 @@ public class SyncManager extends AbstractSyncManager { private void registerDebugCounters(FloodlightModuleContext context) throws FloodlightModuleException { - if (context != null) { - try { - counterHints = debugCounter.registerCounter(PACKAGE, "hints", - "Queued sync events processed", - CounterType.ALWAYS_COUNT); - counterSentValues = debugCounter.registerCounter(PACKAGE, "sent-values", - "Values synced to remote node", - CounterType.ALWAYS_COUNT); - counterReceivedValues = debugCounter.registerCounter(PACKAGE, "received-values", - "Values received from remote node", - CounterType.ALWAYS_COUNT); - counterPuts = debugCounter.registerCounter(PACKAGE, "puts", - "Local puts to store", - CounterType.ALWAYS_COUNT); - counterGets = debugCounter.registerCounter(PACKAGE, "gets", - "Local gets from store", - CounterType.ALWAYS_COUNT); - counterIterators = debugCounter.registerCounter(PACKAGE, "iterators", - "Local iterators created over store", - CounterType.ALWAYS_COUNT); - counterErrorRemote = debugCounter.registerCounter(PACKAGE, "error-remote", - "Number of errors sent from remote clients", - CounterType.ALWAYS_COUNT, - IDebugCounterService.CTR_MDATA_ERROR); - counterErrorProcessing = debugCounter.registerCounter(PACKAGE, - "error-processing", - "Number of errors processing messages from remote clients", - CounterType.ALWAYS_COUNT, - IDebugCounterService.CTR_MDATA_ERROR); - } catch (CounterException e) { - throw new FloodlightModuleException(e.getMessage()); - } - } + if (context != null) { + counterHints = debugCounter.registerCounter(PACKAGE, "hints", + "Queued sync events processed"); + counterSentValues = debugCounter.registerCounter(PACKAGE, "sent-values", + "Values synced to remote node"); + counterReceivedValues = debugCounter.registerCounter(PACKAGE, "received-values", + "Values received from remote node"); + counterPuts = debugCounter.registerCounter(PACKAGE, "puts", + "Local puts to store"); + counterGets = debugCounter.registerCounter(PACKAGE, "gets", + "Local gets from store"); + counterIterators = debugCounter.registerCounter(PACKAGE, "iterators", + "Local iterators created over store"); + counterErrorRemote = debugCounter.registerCounter(PACKAGE, "error-remote", + "Number of errors sent from remote clients", + IDebugCounterService.MetaData.ERROR); + counterErrorProcessing = debugCounter.registerCounter(PACKAGE, + "error-processing", + "Number of errors processing messages from remote clients", + IDebugCounterService.MetaData.ERROR); + } } @@ -780,7 +766,7 @@ public class SyncManager extends AbstractSyncManager { // XXX - todo - handle hints targeted to specific nodes storeRegistry.takeHints(tasks, 50); for (Hint task : tasks) { - counterHints.updateCounterWithFlush(); + counterHints.increment(); SynchronizingStorageEngine store = storeRegistry.get(task.getHintKey(). getStoreName()); @@ -811,10 +797,8 @@ public class SyncManager extends AbstractSyncManager { } svm.getHeader(). - setTransactionId(rpcService. - getTransactionId()); - counterSentValues.updateCounterWithFlush(bsm.getSyncValue(). - getValuesSize()); + setTransactionId(rpcService.getTransactionId()); + counterSentValues.add(bsm.getSyncValue().getValuesSize()); rpcService.writeToNode(n.getNodeId(), bsm); } } diff --git a/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java b/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java index af5dafb1b147a247cd696834618cb4c4b7f349ab..516f387a291f2b655c1a6d0af2cd4f2fc7abed29 100644 --- a/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java +++ b/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java @@ -596,7 +596,7 @@ public class RPCChannelHandler extends AbstractRPCChannelHandler { // ***************** protected void updateCounter(IDebugCounter counter, int incr) { - counter.updateCounterWithFlush(incr); + counter.add(incr); } protected void startAntientropy() { diff --git a/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java b/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java index d6e730c21484b050df395dbe6b68d4aa66c7093a..9d6f9d79e9e1612eaaf9a98620d3add0941e5b95 100644 --- a/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java +++ b/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java @@ -160,7 +160,7 @@ public class ListenerStorageEngine protected void updateCounter(IDebugCounter counter) { if (debugCounter != null) { - counter.updateCounterWithFlush(); + counter.increment(); } } } diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule index ce4fea11dd6e2355e6ede131d8ee5816e9efa29f..a3251672a384d137c5b2c1bd702fffcb12712838 100644 --- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule +++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule @@ -1,28 +1,18 @@ -net.floodlightcontroller.core.module.ApplicationLoader net.floodlightcontroller.core.internal.FloodlightProvider net.floodlightcontroller.storage.memory.MemoryStorageSource -net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl -net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager -net.floodlightcontroller.topology.TopologyManager -net.floodlightcontroller.forwarding.Forwarding net.floodlightcontroller.flowcache.FlowReconcileManager -net.floodlightcontroller.core.OFMessageFilterManager -net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher -net.floodlightcontroller.perfmon.PktInProcessingTime -net.floodlightcontroller.perfmon.NullPktInProcessingTime -net.floodlightcontroller.restserver.RestApiServer -net.floodlightcontroller.learningswitch.LearningSwitch net.floodlightcontroller.hub.Hub net.floodlightcontroller.jython.JythonDebugInterface -net.floodlightcontroller.counter.CounterStore -net.floodlightcontroller.counter.NullCounterStore -net.floodlightcontroller.debugcounter.DebugCounter -net.floodlightcontroller.debugevent.DebugEvent +net.floodlightcontroller.debugcounter.DebugCounterServiceImpl +net.floodlightcontroller.debugevent.DebugEventService net.floodlightcontroller.threadpool.ThreadPool +net.floodlightcontroller.perfmon.PktInProcessingTime +net.floodlightcontroller.restserver.RestApiServer net.floodlightcontroller.ui.web.StaticWebRoutable net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter -net.floodlightcontroller.firewall.Firewall -net.floodlightcontroller.loadbalancer.LoadBalancer -org.sdnplatform.sync.internal.SyncManager -org.sdnplatform.sync.internal.SyncTorture net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier +net.floodlightcontroller.core.internal.OFSwitchManager +net.floodlightcontroller.threadpool.ThreadPool +net.floodlightcontroller.core.internal.ShutdownServiceImpl +org.sdnplatform.sync.internal.SyncManager +org.sdnplatform.sync.internal.SyncTorture \ No newline at end of file diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties index 47d2ae4c164061064f6aae682f6a5993321f51fe..402e483383fefe12638643eea9b50be7ac850ef1 100644 --- a/src/main/resources/floodlightdefault.properties +++ b/src/main/resources/floodlightdefault.properties @@ -1,24 +1,13 @@ floodlight.modules=\ net.floodlightcontroller.jython.JythonDebugInterface,\ -net.floodlightcontroller.counter.CounterStore,\ net.floodlightcontroller.storage.memory.MemoryStorageSource,\ net.floodlightcontroller.core.internal.FloodlightProvider,\ net.floodlightcontroller.threadpool.ThreadPool,\ -net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\ -net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier,\ -net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\ -net.floodlightcontroller.firewall.Firewall,\ -net.floodlightcontroller.forwarding.Forwarding,\ -net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager,\ -net.floodlightcontroller.topology.TopologyManager,\ -net.floodlightcontroller.flowcache.FlowReconcileManager,\ -net.floodlightcontroller.debugcounter.DebugCounter,\ -net.floodlightcontroller.debugevent.DebugEvent,\ +net.floodlightcontroller.debugcounter.DebugCounterServiceImpl,\ +net.floodlightcontroller.restserver.RestApiServer,\ net.floodlightcontroller.perfmon.PktInProcessingTime,\ -net.floodlightcontroller.ui.web.StaticWebRoutable,\ -net.floodlightcontroller.loadbalancer.LoadBalancer,\ -org.sdnplatform.sync.internal.SyncManager,\ -net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier +net.floodligthcontroller.hub.Hub,\ +net.floodlightcontroller.debugevent.DebugEventService org.sdnplatform.sync.internal.SyncManager.authScheme=CHALLENGE_RESPONSE org.sdnplatform.sync.internal.SyncManager.keyStorePath=/etc/floodlight/auth_credentials.jceks org.sdnplatform.sync.internal.SyncManager.dbPath=/var/lib/floodlight/ diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java index e5b3347805af7289e2e8abe90234f38df54b0ee8..a7d5a1d019c3322f7ba08988f4105652d1f73583 100644 --- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java +++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java @@ -18,44 +18,27 @@ package net.floodlightcontroller.core.internal; import static org.easymock.EasyMock.*; - import static org.junit.Assert.*; -import java.util.ArrayList; -import java.util.Collections; -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.concurrent.ConcurrentHashMap; + import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.HAListenerTypeMarker; +import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IListener; import net.floodlightcontroller.core.IListener.Command; -import net.floodlightcontroller.core.IOFMessageFilterManagerService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IOFSwitch.PortChangeType; -import net.floodlightcontroller.core.IOFSwitchDriver; -import net.floodlightcontroller.core.IOFSwitchListener; -import net.floodlightcontroller.core.IReadyForReconcileListener; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.OFMessageFilterManager; import net.floodlightcontroller.core.RoleInfo; -import net.floodlightcontroller.core.SwitchSyncRepresentation; +import net.floodlightcontroller.core.SwitchDescription; import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockFloodlightProvider; import net.floodlightcontroller.core.test.MockThreadPoolService; import net.floodlightcontroller.counter.CounterStore; import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.debugcounter.DebugCounter; import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugevent.DebugEvent; +import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl; +import net.floodlightcontroller.debugevent.DebugEventService; import net.floodlightcontroller.debugevent.IDebugEventService; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.Ethernet; @@ -65,57 +48,70 @@ import net.floodlightcontroller.perfmon.IPktInProcessingTimeService; import net.floodlightcontroller.perfmon.PktInProcessingTime; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.RestApiServer; +//import net.floodlightcontroller.restserver.IRestApiService; +//import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.memory.MemoryStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; import net.floodlightcontroller.threadpool.IThreadPoolService; +import net.floodlightcontroller.threadpool.ThreadPool; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.openflow.protocol.OFFeaturesReply; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPhysicalPort; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.factory.BasicFactory; -import org.openflow.protocol.statistics.OFDescriptionStatistics; -import org.openflow.util.HexString; -import org.sdnplatform.sync.IStoreClient; + +import net.floodlightcontroller.core.IShutdownListener; +import net.floodlightcontroller.core.IShutdownService; +import net.floodlightcontroller.core.internal.IOFSwitchService; +import net.floodlightcontroller.core.test.MockSwitchManager; + +import net.floodlightcontroller.core.IOFSwitchBackend; +import org.projectfloodlight.openflow.protocol.OFControllerRole; +import org.projectfloodlight.openflow.protocol.OFFactories; +import org.projectfloodlight.openflow.protocol.OFFeaturesReply; +import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFPacketIn; +import org.projectfloodlight.openflow.protocol.OFPacketInReason; +import org.projectfloodlight.openflow.protocol.OFVersion; +import org.projectfloodlight.openflow.types.DatapathId; +import org.projectfloodlight.openflow.types.OFBufferId; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.protocol.OFPortDesc; +import org.projectfloodlight.openflow.protocol.OFType; +import org.projectfloodlight.openflow.protocol.OFFactory; import org.sdnplatform.sync.ISyncService; -import org.sdnplatform.sync.IStoreListener.UpdateType; import org.sdnplatform.sync.test.MockSyncService; +import com.google.common.collect.ImmutableList; + public class ControllerTest extends FloodlightTestCase { - private OLD__Controller controller; + private Controller controller; private MockThreadPoolService tp; private MockSyncService syncService; - private IStoreClient<Long, SwitchSyncRepresentation> storeClient; private IPacket testPacket; private OFPacketIn pi; + + // FIXME:LOJI: For now just work with OF 1.0 + private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_10); + private static DatapathId DATAPATH_ID_0 = DatapathId.of(0); @Override @Before public void setUp() throws Exception { - doSetUp(Role.MASTER); + doSetUp(HARole.ACTIVE); } - public void doSetUp(Role role) throws Exception { + public void doSetUp(HARole role) throws Exception { super.setUp(); FloodlightModuleContext fmc = new FloodlightModuleContext(); - FloodlightProvider cm = new FloodlightProvider(); + fmc.addConfigParam(cm, "role", role.toString()); - controller = (OLD__Controller)cm.getServiceImpls().get(IFloodlightProviderService.class); + controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class); fmc.addService(IFloodlightProviderService.class, controller); MemoryStorageSource memstorage = new MemoryStorageSource(); @@ -123,6 +119,12 @@ public class ControllerTest extends FloodlightTestCase { RestApiServer restApi = new RestApiServer(); fmc.addService(IRestApiService.class, restApi); + + ThreadPool threadPool = new ThreadPool(); + fmc.addService(IThreadPoolService.class, threadPool); + + MockSwitchManager switchService = new MockSwitchManager(); + fmc.addService(IOFSwitchService.class, switchService); CounterStore cs = new CounterStore(); fmc.addService(ICounterStoreService.class, cs); @@ -132,22 +134,28 @@ public class ControllerTest extends FloodlightTestCase { // TODO: should mock IDebugCounterService and make sure // the expected counters are updated. - DebugCounter debugCounterService = new DebugCounter(); + DebugCounterServiceImpl debugCounterService = new DebugCounterServiceImpl(); fmc.addService(IDebugCounterService.class, debugCounterService); - DebugEvent debugEventService = new DebugEvent(); + DebugEventService debugEventService = new DebugEventService(); fmc.addService(IDebugEventService.class, debugEventService); + IShutdownService shutdownService = createMock(IShutdownService.class); + shutdownService.registerShutdownListener(anyObject(IShutdownListener.class)); + expectLastCall().anyTimes(); + replay(shutdownService); + fmc.addService(IShutdownService.class, shutdownService); + verify(shutdownService); + tp = new MockThreadPoolService(); fmc.addService(IThreadPoolService.class, tp); syncService = new MockSyncService(); fmc.addService(ISyncService.class, syncService); - - ppt.init(fmc); restApi.init(fmc); + threadPool.init(fmc); memstorage.init(fmc); tp.init(fmc); debugCounterService.init(fmc); @@ -157,6 +165,7 @@ public class ControllerTest extends FloodlightTestCase { ppt.startUp(fmc); restApi.startUp(fmc); + threadPool.startUp(fmc); memstorage.startUp(fmc); tp.startUp(fmc); debugCounterService.startUp(fmc); @@ -164,11 +173,6 @@ public class ControllerTest extends FloodlightTestCase { syncService.startUp(fmc); cm.startUp(fmc); - storeClient = - syncService.getStoreClient(OLD__Controller.SWITCH_SYNC_STORE_NAME, - Long.class, - SwitchSyncRepresentation.class); - testPacket = new Ethernet() .setSourceMACAddress("00:44:33:22:11:00") .setDestinationMACAddress("00:11:22:33:44:55") @@ -186,12 +190,14 @@ public class ControllerTest extends FloodlightTestCase { .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); byte[] testPacketSerialized = testPacket.serialize(); - pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(testPacketSerialized) + //TODO @Ryan should this be for any version? Should 1.0 and 1.3 be tested here? + // The specific factory can be obtained from the switch, but we don't have one + pi = (OFPacketIn) factory.buildPacketIn() + .setBufferId(OFBufferId.NO_BUFFER) + .setInPort(OFPort.of(1)) + .setData(testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) testPacketSerialized.length); + .setTotalLen(testPacketSerialized.length).build(); } @@ -204,23 +210,20 @@ public class ControllerTest extends FloodlightTestCase { controller.isUpdateQueueEmptyForTesting()); } - public OLD__Controller getController() { + public Controller getController() { return controller; } - private static OFDescriptionStatistics createOFDescriptionStatistics() { - OFDescriptionStatistics desc = new OFDescriptionStatistics(); - desc.setDatapathDescription(""); - desc.setHardwareDescription(""); - desc.setManufacturerDescription(""); - desc.setSerialNumber(""); - desc.setSoftwareDescription(""); - return desc; + private static SwitchDescription createSwitchDescription() { + return new SwitchDescription(); } - private static OFFeaturesReply createOFFeaturesReply() { - OFFeaturesReply fr = new OFFeaturesReply(); - fr.setPorts(Collections.<OFPhysicalPort>emptyList()); + private OFFeaturesReply createOFFeaturesReply(DatapathId datapathId) { + OFFeaturesReply fr = factory.buildFeaturesReply() + .setXid(0) + .setDatapathId(datapathId) + .setPorts(ImmutableList.<OFPortDesc>of()) + .build(); return fr; } @@ -228,28 +231,26 @@ public class ControllerTest extends FloodlightTestCase { /** Set the mock expectations for sw when sw is passed to addSwitch * The same expectations can be used when a new SwitchSyncRepresentation * is created from the given mocked switch */ - protected void setupSwitchForAddSwitch(IOFSwitch sw, long dpid, - OFDescriptionStatistics desc, + protected void setupSwitchForAddSwitch(IOFSwitch sw, DatapathId datapathId, + SwitchDescription description, OFFeaturesReply featuresReply) { - String dpidString = HexString.toHexString(dpid); - - if (desc == null) { - desc = createOFDescriptionStatistics(); + String dpidString = datapathId.toString(); + if (description == null) { + description = createSwitchDescription(); } if (featuresReply == null) { - featuresReply = createOFFeaturesReply(); - featuresReply.setDatapathId(dpid); + featuresReply = createOFFeaturesReply(datapathId); } - List<ImmutablePort> ports = - ImmutablePort.immutablePortListOf(featuresReply.getPorts()); + List<OFPortDesc> ports = featuresReply.getPorts(); - expect(sw.getId()).andReturn(dpid).anyTimes(); + expect(sw.getOFFactory()).andReturn(OFFactories.getFactory(OFVersion.OF_10)).anyTimes(); + expect(sw.getId()).andReturn(datapathId).anyTimes(); expect(sw.getStringId()).andReturn(dpidString).anyTimes(); - expect(sw.getDescriptionStatistics()) .andReturn(desc).atLeastOnce(); + expect(sw.getSwitchDescription()).andReturn(description).atLeastOnce(); expect(sw.getBuffers()) - .andReturn(featuresReply.getBuffers()).atLeastOnce(); + .andReturn(featuresReply.getNBuffers()).atLeastOnce(); expect(sw.getTables()) - .andReturn(featuresReply.getTables()).atLeastOnce(); + .andReturn(featuresReply.getNTables()).atLeastOnce(); expect(sw.getCapabilities()) .andReturn(featuresReply.getCapabilities()).atLeastOnce(); expect(sw.getActions()) @@ -274,9 +275,9 @@ public class ControllerTest extends FloodlightTestCase { @Test public void testHandleMessagesNoListeners() throws Exception { - IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); + IOFSwitch sw = createMock(IOFSwitch.class); + expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes(); + expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes(); replay(sw); controller.handleMessage(sw, pi, null); verify(sw); @@ -296,7 +297,7 @@ public class ControllerTest extends FloodlightTestCase { controller.removeOFMessageListeners(OFType.PACKET_IN); IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(0L).anyTimes(); + expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes(); expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); // Setup listener orderings @@ -390,8 +391,7 @@ public class ControllerTest extends FloodlightTestCase { verify(test2); verify(test3); - OFFlowMod fm = (OFFlowMod) - BasicFactory.getInstance().getMessage(OFType.FLOW_MOD); + OFFlowMod fm = (OFFlowMod) factory.buildFlowModify().build(); //------------------ // Test FlowMod handling: all listeners return CONTINUE @@ -425,10 +425,10 @@ public class ControllerTest extends FloodlightTestCase { @Test public void testHandleMessagesSlave() throws Exception { - doSetUp(Role.SLAVE); + doSetUp(HARole.STANDBY); IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); + expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes(); + expect(sw.getStringId()).andReturn(DatapathId.NONE.toString()).anyTimes(); IOFMessageListener test1 = createMock(IOFMessageListener.class); expect(test1.getName()).andReturn("test1").atLeastOnce(); @@ -448,7 +448,7 @@ public class ControllerTest extends FloodlightTestCase { //--------------------------------- // transition to Master //-------------------------------- - controller.setRole(Role.MASTER, "FooBar"); + controller.setRole(HARole.ACTIVE, "FooBar"); // transitioned but HA listeneres not yet notified. // message should not be dispatched @@ -473,8 +473,8 @@ public class ControllerTest extends FloodlightTestCase { @Test public void testHandleMessageWithContext() throws Exception { IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); + expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes(); + expect(sw.getStringId()).andReturn(DatapathId.NONE.toString()).anyTimes(); IOFMessageListener test1 = createMock(IOFMessageListener.class); expect(test1.getName()).andReturn("test1").anyTimes(); @@ -509,129 +509,16 @@ public class ControllerTest extends FloodlightTestCase { assertArrayEquals(testPacket.serialize(), eth.serialize()); } - - /** - * Test injectMessage and also do some more tests for listener ordering - * and handling of Command.STOP - * @throws Exception - */ - @Test - public void testInjectMessage() throws Exception { - FloodlightContext cntx = new FloodlightContext(); - IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); - - // Add listeners - IOFMessageListener test1 = createMock(IOFMessageListener.class); - expect(test1.getName()).andReturn("test1").anyTimes(); - setupListenerOrdering(test1); - - IOFMessageListener test2 = createMock(IOFMessageListener.class); - expect(test2.getName()).andReturn("test2").anyTimes(); - test2.isCallbackOrderingPostreq(OFType.PACKET_IN, "test1"); - expectLastCall().andReturn(true).atLeastOnce(); - setupListenerOrdering(test2); - replay(test1, test2); - controller.addOFMessageListener(OFType.PACKET_IN, test1); - controller.addOFMessageListener(OFType.PACKET_IN, test2); - verify(test1); - verify(test2); - - // Test inject with null switch and no message. Should not work. - reset(test1, test2); - replay(test1, test2, sw); - try { - controller.injectOfMessage(null, pi); - fail("InjectOfMessage should have thrown a NPE"); - } catch (NullPointerException e) { - // expected - } - try { - controller.injectOfMessage(null, pi, cntx); - fail("InjectOfMessage should have thrown a NPE"); - } catch (NullPointerException e) { - // expected - } - try { - controller.injectOfMessage(sw, null); - fail("InjectOfMessage should have thrown a NPE"); - } catch (NullPointerException e) { - // expected - } - try { - controller.injectOfMessage(sw, null, cntx); - fail("InjectOfMessage should have thrown a NPE"); - } catch (NullPointerException e) { - // expected - } - verify(test1); - verify(test2); - verify(sw); - - // - // Test inject with inActive switch. Should not work. - reset(test1, test2, sw); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); - expect(sw.isActive()).andReturn(false).atLeastOnce(); - replay(test1, test2, sw); - assertFalse("Inject should have failed", - controller.injectOfMessage(sw, pi)); - assertFalse("Inject should have failed", - controller.injectOfMessage(sw, pi, cntx)); - verify(test1); - verify(test2); - verify(sw); - - - // Test inject in the "normal" case without context - reset(test1, test2, sw); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); - expect(sw.isActive()).andReturn(true).atLeastOnce(); - expect(test2.receive(same(sw), same(pi) , isA(FloodlightContext.class))) - .andReturn(Command.STOP); - // test1 will not receive any message! - replay(test1, test2, sw); - assertTrue("Inject should have worked", - controller.injectOfMessage(sw, pi)); - verify(test1); - verify(test2); - verify(sw); - - // Test inject in the "normal" case with context - reset(test1, test2, sw); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); - expect(sw.isActive()).andReturn(true).atLeastOnce(); - expect(test2.receive(same(sw), same(pi) , same(cntx))) - .andReturn(Command.STOP); - // test1 will not receive any message! - replay(test1, test2, sw); - assertTrue("Inject should have worked", - controller.injectOfMessage(sw, pi, cntx)); - verify(test1); - verify(test2); - verify(sw); - - Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - assertArrayEquals(testPacket.serialize(), eth.serialize()); - } - - /** * Test handleOutgoingMessage and also test listener ordering * @throws Exception */ @Test public void testHandleOutgoingMessage() throws Exception { - OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REQUEST); - FloodlightContext cntx = new FloodlightContext(); - IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); + OFMessage m = factory.buildEchoRequest().build(); + IOFSwitchBackend sw = createMock(IOFSwitchBackend.class); + expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes(); + expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes(); // Add listeners IOFMessageListener test1 = createMock(IOFMessageListener.class); @@ -664,13 +551,13 @@ public class ControllerTest extends FloodlightTestCase { reset(test1, test2, test3); replay(test1, test2, test3, sw); try { - controller.handleOutgoingMessage(null, pi, cntx); + controller.handleOutgoingMessage(null, pi); fail("handleOutgoindMessage should have thrown a NPE"); } catch (NullPointerException e) { // expected } try { - controller.handleOutgoingMessage(sw, null, cntx); + controller.handleOutgoingMessage(sw, null); fail("handleOutgoingMessage should have thrown a NPE"); } catch (NullPointerException e) { // expected @@ -682,15 +569,15 @@ public class ControllerTest extends FloodlightTestCase { // Test the handleOutgoingMessage reset(test1, test2, test3, sw); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); - expect(test2.receive(same(sw), same(m) , same(cntx))) + expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes(); + expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes(); + expect(test2.receive(same(sw), same(m) , isA(FloodlightContext.class))) .andReturn(Command.STOP); - expect(test3.receive(same(sw), same(m) , same(cntx))) + expect(test3.receive(same(sw), same(m) , isA(FloodlightContext.class))) .andReturn(Command.CONTINUE); // test1 will not receive any message! replay(test1, test2, test3, sw); - controller.handleOutgoingMessage(sw, m, cntx); + controller.handleOutgoingMessage(sw, m); verify(test1); verify(test2); verify(test3); @@ -698,15 +585,15 @@ public class ControllerTest extends FloodlightTestCase { // Test the handleOutgoingMessage with null context reset(test1, test2, test3, sw); - expect(sw.getId()).andReturn(0L).anyTimes(); - expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes(); + expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes(); + expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes(); expect(test2.receive(same(sw), same(m) , isA(FloodlightContext.class))) .andReturn(Command.STOP); expect(test3.receive(same(sw), same(m) , isA(FloodlightContext.class))) .andReturn(Command.CONTINUE); // test1 will not receive any message! replay(test1, test2, test3, sw); - controller.handleOutgoingMessage(sw, m, null); + controller.handleOutgoingMessage(sw, m); verify(test1); verify(test2); verify(test3); @@ -715,141 +602,20 @@ public class ControllerTest extends FloodlightTestCase { // Test for message without listeners reset(test1, test2, test3, sw); replay(test1, test2, test3, sw); - m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY); - controller.handleOutgoingMessage(sw, m, cntx); + m = factory.buildEchoReply().build(); + controller.handleOutgoingMessage(sw, m); verify(test1); verify(test2); verify(test3); verify(sw); } - - @Test - public void testMessageFilterManager() throws Exception { - class MyOFMessageFilterManager extends OFMessageFilterManager { - public MyOFMessageFilterManager(int timer_interval) { - super(); - TIMER_INTERVAL = timer_interval; - } - } - FloodlightModuleContext fmCntx = new FloodlightModuleContext(); - MockFloodlightProvider mfp = new MockFloodlightProvider(); - OFMessageFilterManager mfm = new MyOFMessageFilterManager(100); - MockThreadPoolService mtp = new MockThreadPoolService(); - fmCntx.addService(IOFMessageFilterManagerService.class, mfm); - fmCntx.addService(IFloodlightProviderService.class, mfp); - fmCntx.addService(IThreadPoolService.class, mtp); - String sid = null; - - mfm.init(fmCntx); - mfm.startUp(fmCntx); - - ConcurrentHashMap <String, String> filter; - int i; - - //Adding the filter works -- adds up to the maximum filter size. - for(i=mfm.getMaxFilterSize(); i > 0; --i) { - filter = new ConcurrentHashMap<String,String>(); - filter.put("mac", String.format("00:11:22:33:44:%d%d", i,i)); - sid = mfm.setupFilter(null, filter, 60); - assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize() - i +1); - } - - // Add one more to see if you can't - filter = new ConcurrentHashMap<String,String>(); - filter.put("mac", "mac2"); - mfm.setupFilter(null, filter, 10*1000); - - assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize()); - - // Deleting the filter works. - mfm.setupFilter(sid, null, -1); - assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize()-1); - - // Creating mock switch to which we will send packet out and - IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(new Long(0)); - - // Mock Packet-in - IPacket testPacket = new Ethernet() - .setSourceMACAddress("00:44:33:22:11:00") - .setDestinationMACAddress("00:11:22:33:44:55") - .setEtherType(Ethernet.TYPE_ARP) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REPLY) - .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) - .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) - .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) - .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); - byte[] testPacketSerialized = testPacket.serialize(); - - // Build the PacketIn - OFPacketIn pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(testPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) testPacketSerialized.length); - - // Mock Packet-out - OFPacketOut packetOut = - (OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); - packetOut.setBufferId(pi.getBufferId()) - .setInPort(pi.getInPort()); - List<OFAction> poactions = new ArrayList<OFAction>(); - poactions.add(new OFActionOutput(OFPort.OFPP_TABLE.getValue(), (short) 0)); - packetOut.setActions(poactions) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setPacketData(testPacketSerialized) - .setLengthU(OFPacketOut.MINIMUM_LENGTH+packetOut.getActionsLength()+testPacketSerialized.length); - - FloodlightContext cntx = new FloodlightContext(); - IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet) testPacket); - - - // Let's check the listeners. - List <IOFMessageListener> lm; - - // Check to see if all the listeners are active. - lm = mfp.getListeners().get(OFType.PACKET_OUT); - assertTrue(lm.size() == 1); - assertTrue(lm.get(0).equals(mfm)); - - lm = mfp.getListeners().get(OFType.FLOW_MOD); - assertTrue(lm.size() == 1); - assertTrue(lm.get(0).equals(mfm)); - - lm = mfp.getListeners().get(OFType.PACKET_IN); - assertTrue(lm.size() == 1); - assertTrue(lm.get(0).equals(mfm)); - - HashSet<String> matchedFilters; - - // Send a packet in and check if it matches a filter. - matchedFilters = mfm.getMatchedFilters(pi, cntx); - assertTrue(matchedFilters.size() == 1); - - // Send a packet out and check if it matches a filter - matchedFilters = mfm.getMatchedFilters(packetOut, cntx); - assertTrue(matchedFilters.size() == 1); - - // Wait for all filters to be timed out. - Thread.sleep(150); - assertEquals(0, mfm.getNumberOfFilters()); - } - - @Test public void testGetRoleInfoDefault() { RoleInfo info = controller.getRoleInfo(); - assertEquals(Role.MASTER.toString(), info.getRole()); + assertEquals(HARole.ACTIVE, info.getRole()); assertNotNull(info.getRoleChangeDescription()); - assertEquals(Role.MASTER, controller.getRole()); + assertEquals(HARole.ACTIVE, controller.getRole()); // FIXME: RoleInfo's date. but the format is kinda broken } @@ -859,26 +625,19 @@ public class ControllerTest extends FloodlightTestCase { */ @Test public void testChannelHandlerMaster() { - OFChannelHandler h = createMock(OFChannelHandler.class); - - // Add the handler. The controller should call sendRoleRequest - h.sendRoleRequest(Role.MASTER); - expectLastCall().once(); - replay(h); - controller.addSwitchChannelAndSendInitialRole(h); - verify(h); + OFSwitchHandshakeHandler h = createMock(OFSwitchHandshakeHandler.class); // Reassert the role. reset(h); - h.sendRoleRequestIfNotPending(Role.MASTER); + h.sendRoleRequestIfNotPending(OFControllerRole.ROLE_MASTER); replay(h); - controller.reassertRole(h, Role.MASTER); + controller.reassertRole(h, HARole.ACTIVE); verify(h); // reassert a different role: no-op reset(h); replay(h); - controller.reassertRole(h, Role.SLAVE); + controller.reassertRole(h, HARole.STANDBY); verify(h); } @@ -889,56 +648,41 @@ public class ControllerTest extends FloodlightTestCase { */ @Test public void testSetRole() throws Exception { - doSetUp(Role.SLAVE); + doSetUp(HARole.STANDBY); RoleInfo info = controller.getRoleInfo(); - assertEquals(Role.SLAVE.toString(), info.getRole()); - assertEquals(Role.SLAVE, controller.getRole()); + assertEquals(HARole.STANDBY, info.getRole()); + assertEquals(HARole.STANDBY, controller.getRole()); - OFChannelHandler h = createMock(OFChannelHandler.class); - - // Add the channel handler. The controller should call sendRoleRequest - h.sendRoleRequest(Role.SLAVE); - expectLastCall().once(); - replay(h); - controller.addSwitchChannelAndSendInitialRole(h); - verify(h); + OFSwitchHandshakeHandler h = createMock(OFSwitchHandshakeHandler.class); // Reassert the role. reset(h); - h.sendRoleRequestIfNotPending(Role.SLAVE); + h.sendRoleRequestIfNotPending(OFControllerRole.ROLE_SLAVE); replay(h); - controller.reassertRole(h, Role.SLAVE); + controller.reassertRole(h, HARole.STANDBY); verify(h); // reassert a different role: no-op reset(h); replay(h); - controller.reassertRole(h, Role.MASTER); + controller.reassertRole(h, HARole.ACTIVE); verify(h); - // Change role to MASTER - reset(h); - h.sendRoleRequest(Role.MASTER); - expectLastCall().once(); IHAListener listener = createMock(IHAListener.class); expect(listener.getName()).andReturn("foo").anyTimes(); setupListenerOrdering(listener); - listener.transitionToMaster(); + listener.transitionToActive(); expectLastCall().once(); replay(listener); - replay(h); controller.addHAListener(listener); - controller.setRole(Role.MASTER, "FooBar"); + controller.setRole(HARole.ACTIVE, "FooBar"); controller.processUpdateQueueForTesting(); - verify(h); verify(listener); info = controller.getRoleInfo(); - assertEquals(Role.MASTER.toString(), info.getRole()); + assertEquals(HARole.ACTIVE, info.getRole()); assertEquals("FooBar", info.getRoleChangeDescription()); - assertEquals(Role.MASTER, controller.getRole()); - - + assertEquals(HARole.ACTIVE, controller.getRole()); } /** Test other setRole cases: re-setting role to the current role, @@ -946,21 +690,7 @@ public class ControllerTest extends FloodlightTestCase { */ @Test public void testSetRoleOthercases() throws Exception { - doSetUp(Role.SLAVE); - - OFChannelHandler h = createMock(OFChannelHandler.class); - - // Add the channel handler. The controller should call sendRoleRequest - h.sendRoleRequest(Role.SLAVE); - expectLastCall().once(); - replay(h); - controller.addSwitchChannelAndSendInitialRole(h); - verify(h); - - // remove the channel. Nothing should - reset(h); - replay(h); - controller.removeSwitchChannel(h); + doSetUp(HARole.STANDBY); // Create and add the HA listener IHAListener listener = createMock(IHAListener.class); @@ -970,30 +700,17 @@ public class ControllerTest extends FloodlightTestCase { controller.addHAListener(listener); // Set role to slave again. Nothing should happen - controller.setRole(Role.SLAVE, "FooBar"); + controller.setRole(HARole.STANDBY, "FooBar"); controller.processUpdateQueueForTesting(); verify(listener); reset(listener); - listener.transitionToMaster(); + expect(listener.getName()).andReturn("foo").anyTimes(); + listener.transitionToActive(); expectLastCall().once(); replay(listener); - - // set role to equal. Should set to master internally - controller.setRole(Role.EQUAL, "ToEqual"); - controller.processUpdateQueueForTesting(); - verify(listener); - RoleInfo info = controller.getRoleInfo(); - assertEquals(Role.MASTER.toString(), info.getRole()); - assertEquals("ToEqual", info.getRoleChangeDescription()); - assertEquals(Role.MASTER, controller.getRole()); - - - verify(h); // no calls should have happened on h } - - @Test public void testSetRoleNPE() { try { @@ -1004,1432 +721,11 @@ public class ControllerTest extends FloodlightTestCase { //exptected } try { - controller.setRole(Role.MASTER, null); + controller.setRole(HARole.ACTIVE, null); fail("Should have thrown an Exception"); } catch (NullPointerException e) { //exptected } } - - - - - - @Test - /** - * Test switchActivated for a new switch, i.e., a switch that was not - * previously known to the controller cluser. We expect that all - * flow mods are cleared and we expect a switchAdded - */ - public void testNewSwitchActivated() throws Exception { - // We set AlwaysClearFlowsOnSwActivate to false but we still - // expect a clearAllFlowMods() because the AlwaysClearFlowsOnSwActivate - // is only relevant if a switch that was previously known is activated!! - controller.setAlwaysClearFlowsOnSwActivate(false); - - IOFSwitch sw = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw, 0L, null, null); - sw.clearAllFlowMods(); - expectLastCall().once(); - - // strict mock. Order of events matters! - IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class); - listener.switchAdded(0L); - expectLastCall().once(); - listener.switchActivated(0L); - expectLastCall().once(); - replay(listener); - controller.addOFSwitchListener(listener); - - replay(sw); - controller.switchActivated(sw); - verify(sw); - assertEquals(sw, controller.getSwitch(0L)); - controller.processUpdateQueueForTesting(); - verify(listener); - - SwitchSyncRepresentation storedSwitch = storeClient.getValue(0L); - assertEquals(createOFFeaturesReply(), storedSwitch.getFeaturesReply()); - assertEquals(createOFDescriptionStatistics(), - storedSwitch.getDescription()); - } - - /** - * Test switchActivated for a new switch while in slave: a no-op - */ - @Test - public void testNewSwitchActivatedWhileSlave() throws Exception { - doSetUp(Role.SLAVE); - IOFSwitch sw = createMock(IOFSwitch.class); - - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - - replay(sw, listener); // nothing recorded - controller.switchActivated(sw); - verify(sw); - verify(listener); - } - - - /** - * Create and activate a switch, either completely new or reconnected - * The mocked switch instance will be returned. It wil be reset. - */ - private IOFSwitch doActivateSwitchInt(long dpid, - OFDescriptionStatistics desc, - OFFeaturesReply featuresReply, - boolean clearFlows) - throws Exception { - controller.setAlwaysClearFlowsOnSwActivate(true); - - IOFSwitch sw = createMock(IOFSwitch.class); - if (featuresReply == null) { - featuresReply = createOFFeaturesReply(); - featuresReply.setDatapathId(dpid); - } - if (desc == null) { - desc = createOFDescriptionStatistics(); - } - setupSwitchForAddSwitch(sw, dpid, desc, featuresReply); - if (clearFlows) { - sw.clearAllFlowMods(); - expectLastCall().once(); - } - - replay(sw); - controller.switchActivated(sw); - verify(sw); - assertEquals(sw, controller.getSwitch(dpid)); - // drain updates and ignore - controller.processUpdateQueueForTesting(); - - SwitchSyncRepresentation storedSwitch = storeClient.getValue(dpid); - assertEquals(featuresReply, storedSwitch.getFeaturesReply()); - assertEquals(desc, storedSwitch.getDescription()); - reset(sw); - return sw; - } - - /** - * Create and activate a new switch with the given dpid, features reply - * and description. If description and/or features reply are null we'll - * allocate the default one - * The mocked switch instance will be returned. It wil be reset. - */ - private IOFSwitch doActivateNewSwitch(long dpid, - OFDescriptionStatistics desc, - OFFeaturesReply featuresReply) - throws Exception { - return doActivateSwitchInt(dpid, desc, featuresReply, true); - } - - /** - * Create and activate a switch that's just been disconnected. - * The mocked switch instance will be returned. It wil be reset. - */ - private IOFSwitch doActivateOldSwitch(long dpid, - OFDescriptionStatistics desc, - OFFeaturesReply featuresReply) - throws Exception { - return doActivateSwitchInt(dpid, desc, featuresReply, false); - } - - - /** - * Create a switch sync representation and add it to the store and - * notify the store listener. - * If the description and/or features reply are null, we'll allocate - * the default one - */ - public void doAddSwitchToStore(long dpid, - OFDescriptionStatistics desc, - OFFeaturesReply featuresReply) - throws Exception { - if (featuresReply == null) { - featuresReply = createOFFeaturesReply(); - featuresReply.setDatapathId(dpid); - } - if (desc == null) { - desc = createOFDescriptionStatistics(); - } - - SwitchSyncRepresentation ssr = - new SwitchSyncRepresentation(featuresReply, desc); - storeClient.put(dpid, ssr); - - Iterator<Long> keysToNotify = Collections.singletonList(dpid).iterator(); - controller.getStoreListener().keysModified(keysToNotify, - UpdateType.REMOTE); - } - - /** - * Remove a switch from the sync store and - * notify the store listener. - */ - public void doRemoveSwitchFromStore(long dpid) throws Exception { - storeClient.delete(dpid); - - Iterator<Long> keysToNotify = Collections.singletonList(dpid).iterator(); - controller.getStoreListener().keysModified(keysToNotify, - UpdateType.REMOTE); - } - - - /** (remotely) add switch to store and then remove while master. no-op */ - @Test - public void testAddSwitchToStoreMaster() throws Exception { - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - replay(listener); - - //-------------- - // add switch - doAddSwitchToStore(1L, null, null); - controller.processUpdateQueueForTesting(); - IOFSwitch sw = controller.getSwitch(1L); - assertNull("There shouldn't be a switch", sw); - verify(listener); - - //-------------- - // add a real switch - controller.setAlwaysClearFlowsOnSwActivate(true); - sw = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw, 1L, null, null); - sw.clearAllFlowMods(); - expectLastCall().once(); - reset(listener); - listener.switchAdded(1L); - expectLastCall().once(); - listener.switchActivated(1L); - expectLastCall().once(); - replay(listener); - replay(sw); - controller.switchActivated(sw); - verify(sw); - assertEquals(sw, controller.getSwitch(1L)); - controller.processUpdateQueueForTesting(); - verify(listener); - - //----------- - // remove switch from store. - reset(listener); - replay(listener); - doRemoveSwitchFromStore(1L); - controller.processUpdateQueueForTesting(); - verify(listener); - assertEquals(sw, controller.getSwitch(1L)); - } - - - /** - * add switch to store then remove it again while slave. - * should get notification and switch should be added and then removed - */ - @Test - public void testAddSwitchRemoveSwitchStoreSlave() throws Exception { - doSetUp(Role.SLAVE); - - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - - //------ - // Add switch - listener.switchAdded(1L); - expectLastCall().once(); - replay(listener); - - OFDescriptionStatistics desc = createOFDescriptionStatistics(); - desc.setDatapathDescription("The Switch"); - doAddSwitchToStore(1L, desc, null); - controller.processUpdateQueueForTesting(); - verify(listener); - - IOFSwitch sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertEquals(1L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - assertEquals("The Switch", - sw.getDescriptionStatistics().getDatapathDescription()); - - //------ - // remove switch - reset(listener); - listener.switchRemoved(1L); - replay(listener); - doRemoveSwitchFromStore(1L); - controller.processUpdateQueueForTesting(); - verify(listener); - assertNull("Switch should not exist anymore", controller.getSwitch(1L)); - } - - /** Add switch to store with inconsistent DPID - * @throws Exception - */ - @Test - public void testInconsistentStoreDpid() throws Exception { - doSetUp(Role.SLAVE); - - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - replay(listener); - - - OFFeaturesReply featuresReply = createOFFeaturesReply(); - featuresReply.setDatapathId(42L); - OFDescriptionStatistics desc = createOFDescriptionStatistics(); - SwitchSyncRepresentation ssr = - new SwitchSyncRepresentation(featuresReply, desc); - storeClient.put(1L, ssr); - - Iterator<Long> keysToNotify = Collections.singletonList(1L).iterator(); - controller.getStoreListener().keysModified(keysToNotify, - UpdateType.REMOTE); - controller.processUpdateQueueForTesting(); - verify(listener); - - assertNull("Switch should not have been added", - controller.getSwitch(1L)); - assertNull("Switch should not have been added", - controller.getSwitch(42L)); - } - - - /** - * This test goes through the SLAVE->MASTER program flow. We'll start as - * SLAVE. Add switches to the store while slave, update these switches - * then transition to master, make most (but not all switches) "connect" - * We also check correct behavior of getAllSwitchDpids() and - * getAllSwitchMap() - * - * We also change ports to verify that we receive port changed notifications - * if ports are changes in the sync store or when we transition from - * inactive to active - */ - @Test - public void testSwitchAddWithRoleChangeSomeReconnect() throws Exception { - int consolidateStoreDelayMs = 50; - doSetUp(Role.SLAVE); - - // Add HA Listener - IHAListener haListener = createMock(IHAListener.class); - expect(haListener.getName()).andReturn("foo").anyTimes(); - setupListenerOrdering(haListener); - replay(haListener); - controller.addHAListener(haListener); - verify(haListener); - reset(haListener); - - // Add switch listener - IOFSwitchListener switchListener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(switchListener); - - // Add readyForReconcile listener - IReadyForReconcileListener readyForReconcileListener = - createMock(IReadyForReconcileListener.class); - controller.addReadyForReconcileListener(readyForReconcileListener); - - //--------------------------------------- - // Initialization - //--------------------------------------- - - // Switch 1 - // no actual IOFSwitch here because we simply add features reply - // and desc stats to store - OFFeaturesReply fr1a = createOFFeaturesReply(); - fr1a.setDatapathId(1L); - OFPhysicalPort p = createOFPhysicalPort("P1", 1); - ImmutablePort sw1p1 = ImmutablePort.fromOFPhysicalPort(p); - List<OFPhysicalPort> ports1a = Collections.singletonList(p); - fr1a.setPorts(ports1a); - List<ImmutablePort> ports1aImmutable = - ImmutablePort.immutablePortListOf(ports1a); - // an alternative featuers reply - OFFeaturesReply fr1b = createOFFeaturesReply(); - fr1b.setDatapathId(1L); - p = new OFPhysicalPort(); - p = createOFPhysicalPort("P1", 1); // same port as above - List<OFPhysicalPort> ports1b = new ArrayList<OFPhysicalPort>(); - ports1b.add(p); - p = createOFPhysicalPort("P2", 42000); - ImmutablePort sw1p2 = ImmutablePort.fromOFPhysicalPort(p); - ports1b.add(p); - fr1b.setPorts(ports1b); - List<ImmutablePort> ports1bImmutable = - ImmutablePort.immutablePortListOf(ports1b); - - // Switch 2 - // no actual IOFSwitch here because we simply add features reply - // and desc stats to store - OFFeaturesReply fr2a = createOFFeaturesReply(); - fr2a.setDatapathId(2L); - ImmutablePort sw2p1 = sw1p1; - List<OFPhysicalPort> ports2a = new ArrayList<OFPhysicalPort>(ports1a); - fr2a.setPorts(ports2a); - List<ImmutablePort> ports2aImmutable = - ImmutablePort.immutablePortListOf(ports2a); - // an alternative features reply - OFFeaturesReply fr2b = createOFFeaturesReply(); - fr2b.setDatapathId(2L); - p = new OFPhysicalPort(); - p = createOFPhysicalPort("P1", 2); // port number changed - ImmutablePort sw2p1Changed = ImmutablePort.fromOFPhysicalPort(p); - List<OFPhysicalPort> ports2b = Collections.singletonList(p); - fr2b.setPorts(ports2b); - - // Switches 3 and 4 are create with default features reply and desc - // so nothing to do here - - //--------------------------------------- - // Adding switches to store - //--------------------------------------- - - replay(haListener); // nothing should happen to haListener - replay(readyForReconcileListener); // nothing should happen to - // readyForReconcileListener - - // add switch1 with fr1a to store - reset(switchListener); - switchListener.switchAdded(1L); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(1L, null, fr1a); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - IOFSwitch sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertEquals(1L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - assertEquals(new HashSet<ImmutablePort>(ports1aImmutable), - new HashSet<ImmutablePort>(sw.getPorts())); - - // add switch 2 with fr2a to store - reset(switchListener); - switchListener.switchAdded(2L); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(2L, null, fr2a); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - sw = controller.getSwitch(2L); - assertNotNull("Switch should be present", sw); - assertEquals(2L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - assertEquals(new HashSet<ImmutablePort>(ports2aImmutable), - new HashSet<ImmutablePort>(sw.getPorts())); - - // add switch 3 to store - reset(switchListener); - switchListener.switchAdded(3L); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(3L, null, null); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - sw = controller.getSwitch(3L); - assertNotNull("Switch should be present", sw); - assertEquals(3L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - // add switch 4 to store - reset(switchListener); - switchListener.switchAdded(4L); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(4L, null, null); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - sw = controller.getSwitch(4L); - assertNotNull("Switch should be present", sw); - assertEquals(4L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - // update switch 1 with fr1b - reset(switchListener); - switchListener.switchPortChanged(1L, sw1p2, PortChangeType.ADD); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(1L, null, fr1b); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertEquals(1L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - assertEquals(new HashSet<ImmutablePort>(ports1bImmutable), - new HashSet<ImmutablePort>(sw.getPorts())); - - // Check getAllSwitchDpids() and getAllSwitchMap() - Set<Long> expectedDpids = new HashSet<Long>(); - expectedDpids.add(1L); - expectedDpids.add(2L); - expectedDpids.add(3L); - expectedDpids.add(4L); - assertEquals(expectedDpids, controller.getAllSwitchDpids()); - Map<Long, IOFSwitch> expectedSwitchMap = new HashMap<Long, IOFSwitch>(); - expectedSwitchMap.put(1L, controller.getSwitch(1L)); - expectedSwitchMap.put(2L, controller.getSwitch(2L)); - expectedSwitchMap.put(3L, controller.getSwitch(3L)); - expectedSwitchMap.put(4L, controller.getSwitch(4L)); - assertEquals(expectedSwitchMap, controller.getAllSwitchMap()); - - verify(haListener); - //-------------------------------------- - // Transition to master - //-------------------------------------- - reset(haListener); - haListener.transitionToMaster(); - expectLastCall().once(); - replay(haListener); - controller.setConsolidateStoreTaskDelay(consolidateStoreDelayMs); - controller.setRole(Role.MASTER, "FooBar"); - controller.processUpdateQueueForTesting(); - verify(haListener); - reset(haListener); - replay(haListener); - - //-------------------------------------- - // Activate switches - //-------------------------------------- - - // Activate switch 1 - IOFSwitch sw1 = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw1, 1L, null, fr1b); - reset(switchListener); - switchListener.switchActivated(1L); - expectLastCall().once(); - replay(sw1); - replay(switchListener); - controller.switchActivated(sw1); - controller.processUpdateQueueForTesting(); - verify(switchListener); - verify(sw1); - - sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertSame(sw1, sw); // the mock switch should be returned - - // Activate switch 2 with different features reply - // should get portChanged - // also set alwaysClearFlorModOnSwAcitvate to true; - controller.setAlwaysClearFlowsOnSwActivate(true); - IOFSwitch sw2 = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw2, 2L, null, fr2b); - sw2.clearAllFlowMods(); - expectLastCall().once(); - reset(switchListener); - switchListener.switchActivated(2L); - expectLastCall().once(); - switchListener.switchPortChanged(2L, sw2p1, PortChangeType.DELETE); - switchListener.switchPortChanged(2L, sw2p1Changed, PortChangeType.ADD); - expectLastCall().once(); - replay(sw2); - replay(switchListener); - controller.switchActivated(sw2); - controller.processUpdateQueueForTesting(); - verify(switchListener); - verify(sw2); - - sw = controller.getSwitch(2L); - assertNotNull("Switch should be present", sw); - assertSame(sw2, sw); // the mock switch should be returned - - - // Do not activate switch 3, but it should still be present - sw = controller.getSwitch(3L); - IOFSwitch sw3 = sw; - assertNotNull("Switch should be present", sw); - assertEquals(3L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - // Do not activate switch 4, but it should still be present - sw = controller.getSwitch(4L); - IOFSwitch sw4 = sw; - assertNotNull("Switch should be present", sw); - assertEquals(4L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - // Check getAllSwitchDpids() and getAllSwitchMap() - expectedDpids = new HashSet<Long>(); - expectedDpids.add(1L); - expectedDpids.add(2L); - expectedDpids.add(3L); - expectedDpids.add(4L); - assertEquals(expectedDpids, controller.getAllSwitchDpids()); - expectedSwitchMap = new HashMap<Long, IOFSwitch>(); - expectedSwitchMap.put(1L, sw1); - expectedSwitchMap.put(2L, sw2); - expectedSwitchMap.put(3L, sw3); - expectedSwitchMap.put(4L, sw4); - assertEquals(expectedSwitchMap, controller.getAllSwitchMap()); - - // silently remove switch 4 from the store and notify the - // store listener. Since the controller is MASTER it will ignore - // this notification. - reset(switchListener); - replay(switchListener); - doRemoveSwitchFromStore(4L); - controller.processUpdateQueueForTesting(); - verify(switchListener); - // Switch should still be queryable - sw = controller.getSwitch(4L); - assertNotNull("Switch should be present", sw); - assertEquals(4L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - //-------------------------------- - // Wait for consolidateStore - //-------------------------------- - verify(readyForReconcileListener); - reset(readyForReconcileListener); - readyForReconcileListener.readyForReconcile(); - replay(readyForReconcileListener); - reset(switchListener); - switchListener.switchRemoved(3L); - switchListener.switchRemoved(4L); - replay(switchListener); - Thread.sleep(2*consolidateStoreDelayMs); - controller.processUpdateQueueForTesting(); - verify(switchListener); - verify(readyForReconcileListener); - reset(readyForReconcileListener); - replay(readyForReconcileListener); - - // Verify the expected switches are all there. no more no less - sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertSame(sw1, sw); // the mock switch should be returned - - sw = controller.getSwitch(2L); - assertNotNull("Switch should be present", sw); - assertSame(sw2, sw); // the mock switch should be returned - - // Do not activate switch 3, but it should still be present - sw = controller.getSwitch(3L); - assertNull("Switch should NOT be present", sw); - - // Check getAllSwitchDpids() and getAllSwitchMap() - expectedDpids = new HashSet<Long>(); - expectedDpids.add(1L); - expectedDpids.add(2L); - assertEquals(expectedDpids, controller.getAllSwitchDpids()); - expectedSwitchMap = new HashMap<Long, IOFSwitch>(); - expectedSwitchMap.put(1L, sw1); - expectedSwitchMap.put(2L, sw2); - assertEquals(expectedSwitchMap, controller.getAllSwitchMap()); - - verify(haListener); - verify(readyForReconcileListener); - } - - /** - * This test goes through the SLAVE->MASTER program flow. We'll start as - * SLAVE. Add switches to the store while slave, update these switches - * then transition to master, make all "connect" - * - * Supplements testSwitchAddWithRoleChangeSomeReconnect() and thus does - * less extensive testing. We are really only interested in verifying - * that we get the readyForReconciliation event before - * consolidateStore runs. - */ - @Test - public void testSwitchAddWithRoleChangeAllReconnect() throws Exception { - int consolidateStoreDelayMs = 50; - doSetUp(Role.SLAVE); - - // Add HA Listener - IHAListener haListener = createMock(IHAListener.class); - expect(haListener.getName()).andReturn("foo").anyTimes(); - setupListenerOrdering(haListener); - replay(haListener); - controller.addHAListener(haListener); - verify(haListener); - reset(haListener); - - // Add switch listener - IOFSwitchListener switchListener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(switchListener); - - // Add readyForReconcile listener - IReadyForReconcileListener readyForReconcileListener = - createMock(IReadyForReconcileListener.class); - controller.addReadyForReconcileListener(readyForReconcileListener); - - //--------------------------------------- - // Adding switches to store - //--------------------------------------- - - replay(haListener); // nothing should happen to haListener - replay(readyForReconcileListener); // nothing should happen to - // readyForReconcileListener - - // add switch 1 to store - reset(switchListener); - switchListener.switchAdded(1L); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(1L, null, null); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - IOFSwitch sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertEquals(1L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - // add switch 2 to store - reset(switchListener); - switchListener.switchAdded(2L); - expectLastCall().once(); - replay(switchListener); - doAddSwitchToStore(2L, null, null); - controller.processUpdateQueueForTesting(); - verify(switchListener); - reset(switchListener); - - sw = controller.getSwitch(2L); - assertNotNull("Switch should be present", sw); - assertEquals(2L, sw.getId()); - assertFalse("Switch should be inactive", sw.isActive()); - - // Check getAllSwitchDpids() and getAllSwitchMap() - Set<Long> expectedDpids = new HashSet<Long>(); - expectedDpids.add(1L); - expectedDpids.add(2L); - assertEquals(expectedDpids, controller.getAllSwitchDpids()); - Map<Long, IOFSwitch> expectedSwitchMap = new HashMap<Long, IOFSwitch>(); - expectedSwitchMap.put(1L, controller.getSwitch(1L)); - expectedSwitchMap.put(2L, controller.getSwitch(2L)); - assertEquals(expectedSwitchMap, controller.getAllSwitchMap()); - - verify(haListener); - //-------------------------------------- - // Transition to master - //-------------------------------------- - reset(haListener); - haListener.transitionToMaster(); - expectLastCall().once(); - replay(haListener); - controller.setConsolidateStoreTaskDelay(consolidateStoreDelayMs); - controller.setRole(Role.MASTER, "FooBar"); - controller.processUpdateQueueForTesting(); - verify(haListener); - reset(haListener); - replay(haListener); - - //-------------------------------------- - // Activate switches - //-------------------------------------- - - // Activate switch 1 - IOFSwitch sw1 = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw1, 1L, null, null); - reset(switchListener); - switchListener.switchActivated(1L); - expectLastCall().once(); - replay(sw1); - replay(switchListener); - controller.switchActivated(sw1); - controller.processUpdateQueueForTesting(); - verify(switchListener); - verify(sw1); - - sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertSame(sw1, sw); // the mock switch should be returned - - // Activate switch 2 - // Since this is the last inactive switch to activate we should - // get the readyForReconcile notifiction - verify(readyForReconcileListener); - reset(readyForReconcileListener); - readyForReconcileListener.readyForReconcile(); - replay(readyForReconcileListener); - controller.setAlwaysClearFlowsOnSwActivate(true); - IOFSwitch sw2 = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw2, 2L, null, null); - sw2.clearAllFlowMods(); - expectLastCall().once(); - reset(switchListener); - switchListener.switchActivated(2L); - expectLastCall().once(); - replay(sw2); - replay(switchListener); - controller.switchActivated(sw2); - controller.processUpdateQueueForTesting(); - verify(switchListener); - verify(sw2); - verify(readyForReconcileListener); - - - sw = controller.getSwitch(2L); - assertNotNull("Switch should be present", sw); - assertSame(sw2, sw); // the mock switch should be returned - - - // Check getAllSwitchDpids() and getAllSwitchMap() - expectedDpids = new HashSet<Long>(); - expectedDpids.add(1L); - expectedDpids.add(2L); - assertEquals(expectedDpids, controller.getAllSwitchDpids()); - expectedSwitchMap = new HashMap<Long, IOFSwitch>(); - expectedSwitchMap.put(1L, sw1); - expectedSwitchMap.put(2L, sw2); - assertEquals(expectedSwitchMap, controller.getAllSwitchMap()); - - //-------------------------------- - // Wait for consolidateStore: a no-op - //-------------------------------- - reset(switchListener); - replay(switchListener); - reset(readyForReconcileListener); - replay(readyForReconcileListener); - Thread.sleep(2*consolidateStoreDelayMs); - controller.processUpdateQueueForTesting(); - verify(switchListener); - verify(readyForReconcileListener); - - // Verify the expected switches are all there. no more no less - sw = controller.getSwitch(1L); - assertNotNull("Switch should be present", sw); - assertSame(sw1, sw); // the mock switch should be returned - - sw = controller.getSwitch(2L); - assertNotNull("Switch should be present", sw); - assertSame(sw2, sw); // the mock switch should be returned - - // Check getAllSwitchDpids() and getAllSwitchMap() - expectedDpids = new HashSet<Long>(); - expectedDpids.add(1L); - expectedDpids.add(2L); - assertEquals(expectedDpids, controller.getAllSwitchDpids()); - expectedSwitchMap = new HashMap<Long, IOFSwitch>(); - expectedSwitchMap.put(1L, sw1); - expectedSwitchMap.put(2L, sw2); - assertEquals(expectedSwitchMap, controller.getAllSwitchMap()); - - verify(haListener); - } - - /** - * Disconnect a switch. normal program flow - */ - @Test - private void doTestSwitchConnectReconnect(boolean reconnect) - throws Exception { - IOFSwitch sw = doActivateNewSwitch(1L, null, null); - expect(sw.getId()).andReturn(1L).anyTimes(); - expect(sw.getStringId()).andReturn(HexString.toHexString(1L)).anyTimes(); - sw.cancelAllStatisticsReplies(); - expectLastCall().once(); - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - listener.switchRemoved(1L); - expectLastCall().once(); - controller.addOFSwitchListener(listener); - replay(sw, listener); - controller.switchDisconnected(sw); - controller.processUpdateQueueForTesting(); - verify(sw, listener); - - assertNull(controller.getSwitch(1L)); - assertNull(storeClient.getValue(1L)); - if (reconnect) { - controller.removeOFSwitchListener(listener); - sw = doActivateOldSwitch(1L, null, null); - } - } - - @Test - public void testSwitchDisconnected() throws Exception { - doTestSwitchConnectReconnect(false); - } - - /** - * Disconnect a switch and reconnect, verify no clearAllFlowmods() - */ - @Test - public void testSwitchReconnect() throws Exception { - doTestSwitchConnectReconnect(true); - } - - /** - * Remove a nonexisting switch. should be ignored - */ - @Test - public void testNonexistingSwitchDisconnected() throws Exception { - IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(1L).anyTimes(); - expect(sw.getStringId()).andReturn(HexString.toHexString(1L)).anyTimes(); - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - replay(sw, listener); - controller.switchDisconnected(sw); - controller.processUpdateQueueForTesting(); - verify(sw, listener); - - assertNull(controller.getSwitch(1L)); - assertNull(storeClient.getValue(1L)); - } - - /** - * Try to remove a switch that's different from what's in the active - * switch map. Should be ignored - */ - @Test - public void testSwitchDisconnectedOther() throws Exception { - IOFSwitch origSw = doActivateNewSwitch(1L, null, null); - // create a new mock switch - IOFSwitch sw = createMock(IOFSwitch.class); - expect(sw.getId()).andReturn(1L).anyTimes(); - expect(sw.getStringId()).andReturn(HexString.toHexString(1L)).anyTimes(); - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - replay(sw, listener); - controller.switchDisconnected(sw); - controller.processUpdateQueueForTesting(); - verify(sw, listener); - - assertSame(origSw, controller.getSwitch(1L)); - assertNotNull(storeClient.getValue(1L)); - } - - - - /** - * Try to activate a switch that's already active (which can happen if - * two different switches have the same DPIP or if a switch reconnects - * while the old TCP connection is still alive - */ - @Test - public void testSwitchActivatedWithAlreadyActiveSwitch() throws Exception { - OFDescriptionStatistics oldDesc = createOFDescriptionStatistics(); - oldDesc.setDatapathDescription("Ye Olde Switch"); - OFDescriptionStatistics newDesc = createOFDescriptionStatistics(); - newDesc.setDatapathDescription("The new Switch"); - OFFeaturesReply featuresReply = createOFFeaturesReply(); - - - // Setup: add a switch to the controller - IOFSwitch oldsw = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(oldsw, 0L, oldDesc, featuresReply); - oldsw.clearAllFlowMods(); - expectLastCall().once(); - replay(oldsw); - controller.switchActivated(oldsw); - verify(oldsw); - // drain the queue, we don't care what's in it - controller.processUpdateQueueForTesting(); - assertEquals(oldsw, controller.getSwitch(0L)); - - // Now the actual test: add a new switch with the same dpid to - // the controller - reset(oldsw); - expect(oldsw.getId()).andReturn(0L).anyTimes(); - oldsw.cancelAllStatisticsReplies(); - expectLastCall().once(); - oldsw.disconnectOutputStream(); - expectLastCall().once(); - - - IOFSwitch newsw = createMock(IOFSwitch.class); - setupSwitchForAddSwitch(newsw, 0L, newDesc, featuresReply); - newsw.clearAllFlowMods(); - expectLastCall().once(); - - // Strict mock. We need to get the removed notification before the - // add notification - IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class); - listener.switchRemoved(0L); - listener.switchAdded(0L); - listener.switchActivated(0L); - replay(listener); - controller.addOFSwitchListener(listener); - - - replay(newsw, oldsw); - controller.switchActivated(newsw); - verify(newsw, oldsw); - - assertEquals(newsw, controller.getSwitch(0L)); - controller.processUpdateQueueForTesting(); - verify(listener); - } - - - - /** - * Tests that you can't remove a switch from the map returned by - * getSwitches() (because getSwitches should return an unmodifiable - * map) - */ - @Test - public void testRemoveActiveSwitch() { - IOFSwitch sw = createNiceMock(IOFSwitch.class); - setupSwitchForAddSwitch(sw, 1L, null, null); - replay(sw); - getController().switchActivated(sw); - assertEquals(sw, getController().getSwitch(1L)); - getController().getAllSwitchMap().remove(1L); - assertEquals(sw, getController().getSwitch(1L)); - verify(sw); - // we don't care for updates. drain queue. - controller.processUpdateQueueForTesting(); - } - - - - /** - * Test that notifyPortChanged() results in an IOFSwitchListener - * update and that its arguments are passed through to - * the listener call - */ - @Test - public void testNotifySwitchPoArtChanged() throws Exception { - long dpid = 42L; - - OFFeaturesReply fr1 = createOFFeaturesReply(); - fr1.setDatapathId(dpid); - OFPhysicalPort p1 = createOFPhysicalPort("Port1", 1); - fr1.setPorts(Collections.singletonList(p1)); - - OFFeaturesReply fr2 = createOFFeaturesReply(); - fr1.setDatapathId(dpid); - OFPhysicalPort p2 = createOFPhysicalPort("Port1", 1); - p2.setAdvertisedFeatures(0x2); // just some bogus values - fr2.setPorts(Collections.singletonList(p2)); - - OFDescriptionStatistics desc = createOFDescriptionStatistics(); - - // activate switch - IOFSwitch sw = doActivateNewSwitch(dpid, desc, fr1); - - // check the store - SwitchSyncRepresentation ssr = storeClient.getValue(dpid); - assertNotNull(ssr); - assertEquals(dpid, ssr.getDpid()); - assertEquals(1, ssr.getPorts().size()); - assertEquals(p1, ssr.getPorts().get(0).toOFPhysicalPort()); - - IOFSwitchListener listener = createMock(IOFSwitchListener.class); - controller.addOFSwitchListener(listener); - // setup switch with the new, second features reply (and thus ports) - setupSwitchForAddSwitch(sw, dpid, desc, fr2); - listener.switchPortChanged(dpid, ImmutablePort.fromOFPhysicalPort(p2), - PortChangeType.OTHER_UPDATE); - expectLastCall().once(); - replay(listener); - replay(sw); - controller.notifyPortChanged(sw, ImmutablePort.fromOFPhysicalPort(p2), - PortChangeType.OTHER_UPDATE); - controller.processUpdateQueueForTesting(); - verify(listener); - verify(sw); - - // check the store - ssr = storeClient.getValue(dpid); - assertNotNull(ssr); - assertEquals(dpid, ssr.getDpid()); - assertEquals(1, ssr.getPorts().size()); - assertEquals(p2, ssr.getPorts().get(0).toOFPhysicalPort()); - } - - private Map<String,Object> getFakeControllerIPRow(String id, String controllerId, - String type, int number, String discoveredIP ) { - HashMap<String, Object> row = new HashMap<String,Object>(); - row.put(OLD__Controller.CONTROLLER_INTERFACE_ID, id); - row.put(OLD__Controller.CONTROLLER_INTERFACE_CONTROLLER_ID, controllerId); - row.put(OLD__Controller.CONTROLLER_INTERFACE_TYPE, type); - row.put(OLD__Controller.CONTROLLER_INTERFACE_NUMBER, number); - row.put(OLD__Controller.CONTROLLER_INTERFACE_DISCOVERED_IP, discoveredIP); - return row; - } - - /** - * Test notifications for controller node IP changes. This requires - * synchronization between the main test thread and another thread - * that runs Controller's main loop and takes / handles updates. We - * synchronize with wait(timeout) / notifyAll(). We check for the - * expected condition after the wait returns. However, if wait returns - * due to the timeout (or due to spurious awaking) and the check fails we - * might just not have waited long enough. Using a long enough timeout - * mitigates this but we cannot get rid of the fundamental "issue". - * - * @throws Exception - */ - @Test - public void testControllerNodeIPChanges() throws Exception { - class DummyHAListener implements IHAListener { - public Map<String, String> curControllerNodeIPs; - public Map<String, String> addedControllerNodeIPs; - public Map<String, String> removedControllerNodeIPs; - public int nCalled; - - public DummyHAListener() { - this.nCalled = 0; - } - - @Override - public synchronized void controllerNodeIPsChanged( - Map<String, String> curControllerNodeIPs, - Map<String, String> addedControllerNodeIPs, - Map<String, String> removedControllerNodeIPs) { - this.curControllerNodeIPs = curControllerNodeIPs; - this.addedControllerNodeIPs = addedControllerNodeIPs; - this.removedControllerNodeIPs = removedControllerNodeIPs; - this.nCalled++; - notifyAll(); - } - - public void do_assert(int nCalled, - Map<String, String> curControllerNodeIPs, - Map<String, String> addedControllerNodeIPs, - Map<String, String> removedControllerNodeIPs) { - assertEquals("nCalled is not as expected", nCalled, this.nCalled); - assertEquals("curControllerNodeIPs is not as expected", - curControllerNodeIPs, this.curControllerNodeIPs); - assertEquals("addedControllerNodeIPs is not as expected", - addedControllerNodeIPs, this.addedControllerNodeIPs); - assertEquals("removedControllerNodeIPs is not as expected", - removedControllerNodeIPs, this.removedControllerNodeIPs); - - } - - @Override - public String getName() { - return null; - } - - @Override - public boolean - isCallbackOrderingPrereq(HAListenerTypeMarker type, - String name) { - return false; - } - - @Override - public boolean - isCallbackOrderingPostreq(HAListenerTypeMarker type, - String name) { - return false; - } - - @Override - public void transitionToMaster() { - } - } - DummyHAListener listener = new DummyHAListener(); - HashMap<String,String> expectedCurMap = new HashMap<String, String>(); - HashMap<String,String> expectedAddedMap = new HashMap<String, String>(); - HashMap<String,String> expectedRemovedMap = new HashMap<String, String>(); - - controller.addHAListener(listener); - - synchronized(listener) { - // Insert a first entry - controller.getStorageSourceService() - .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1")); - expectedCurMap.clear(); - expectedAddedMap.clear(); - expectedRemovedMap.clear(); - expectedCurMap.put("c1", "1.1.1.1"); - expectedAddedMap.put("c1", "1.1.1.1"); - controller.processUpdateQueueForTesting(); - listener.do_assert(1, expectedCurMap, expectedAddedMap, expectedRemovedMap); - - // Add an interface that we want to ignore. - controller.getStorageSourceService() - .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2")); - // TODO: do a different check. This call will have to wait for the timeout - controller.processUpdateQueueForTesting(); - assertTrue("controllerNodeIPsChanged() should not have been called here", - listener.nCalled == 1); - - // Add another entry - controller.getStorageSourceService() - .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2")); - expectedCurMap.clear(); - expectedAddedMap.clear(); - expectedRemovedMap.clear(); - expectedCurMap.put("c1", "1.1.1.1"); - expectedCurMap.put("c2", "2.2.2.2"); - expectedAddedMap.put("c2", "2.2.2.2"); - controller.processUpdateQueueForTesting(); - listener.do_assert(2, expectedCurMap, expectedAddedMap, expectedRemovedMap); - - - // Update an entry - controller.getStorageSourceService() - .updateRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - "row3", getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.3")); - expectedCurMap.clear(); - expectedAddedMap.clear(); - expectedRemovedMap.clear(); - expectedCurMap.put("c1", "1.1.1.1"); - expectedCurMap.put("c2", "2.2.2.3"); - expectedAddedMap.put("c2", "2.2.2.3"); - expectedRemovedMap.put("c2", "2.2.2.2"); - controller.processUpdateQueueForTesting(); - listener.do_assert(3, expectedCurMap, expectedAddedMap, expectedRemovedMap); - - // Delete an entry - controller.getStorageSourceService() - .deleteRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, "row3"); - expectedCurMap.clear(); - expectedAddedMap.clear(); - expectedRemovedMap.clear(); - expectedCurMap.put("c1", "1.1.1.1"); - expectedRemovedMap.put("c2", "2.2.2.3"); - controller.processUpdateQueueForTesting(); - listener.do_assert(4, expectedCurMap, expectedAddedMap, expectedRemovedMap); - } - } - - @Test - public void testGetControllerNodeIPs() { - HashMap<String,String> expectedCurMap = new HashMap<String, String>(); - - controller.getStorageSourceService() - .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1")); - controller.getStorageSourceService() - .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2")); - controller.getStorageSourceService() - .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, - getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2")); - expectedCurMap.put("c1", "1.1.1.1"); - expectedCurMap.put("c2", "2.2.2.2"); - assertEquals("expectedControllerNodeIPs is not as expected", - expectedCurMap, controller.getControllerNodeIPs()); - // we don't care for updates. drain update queue - controller.processUpdateQueueForTesting(); - } - - - /** - * Test the driver registry: test the bind order - */ - @Test - public void testSwitchDriverRegistryBindOrder() { - IOFSwitchDriver driver1 = createMock(IOFSwitchDriver.class); - IOFSwitchDriver driver2 = createMock(IOFSwitchDriver.class); - IOFSwitchDriver driver3 = createMock(IOFSwitchDriver.class); - IOFSwitch returnedSwitch = null; - IOFSwitch mockSwitch = createMock(IOFSwitch.class); - controller.addOFSwitchDriver("", driver3); - controller.addOFSwitchDriver("test switch", driver1); - controller.addOFSwitchDriver("test", driver2); - - replay(driver1); - replay(driver2); - replay(driver3); - replay(mockSwitch); - - OFDescriptionStatistics desc = createOFDescriptionStatistics(); - desc.setManufacturerDescription("test switch"); - desc.setHardwareDescription("version 0.9"); - reset(driver1); - reset(driver2); - reset(driver3); - reset(mockSwitch); - mockSwitch.setSwitchProperties(desc); - expectLastCall().once(); - expect(driver1.getOFSwitchImpl(desc)).andReturn(mockSwitch).once(); - replay(driver1); - replay(driver2); - replay(driver3); - replay(mockSwitch); - returnedSwitch = controller.getOFSwitchInstance(desc); - assertSame(mockSwitch, returnedSwitch); - verify(driver1); - verify(driver2); - verify(driver3); - verify(mockSwitch); - - desc = createOFDescriptionStatistics(); - desc.setManufacturerDescription("testFooBar"); - desc.setHardwareDescription("version 0.9"); - reset(driver1); - reset(driver2); - reset(driver3); - reset(mockSwitch); - mockSwitch.setSwitchProperties(desc); - expectLastCall().once(); - expect(driver2.getOFSwitchImpl(desc)).andReturn(mockSwitch).once(); - replay(driver1); - replay(driver2); - replay(driver3); - replay(mockSwitch); - returnedSwitch = controller.getOFSwitchInstance(desc); - assertSame(mockSwitch, returnedSwitch); - verify(driver1); - verify(driver2); - verify(driver3); - verify(mockSwitch); - - desc = createOFDescriptionStatistics(); - desc.setManufacturerDescription("FooBar"); - desc.setHardwareDescription("version 0.9"); - reset(driver1); - reset(driver2); - reset(driver3); - reset(mockSwitch); - mockSwitch.setSwitchProperties(desc); - expectLastCall().once(); - expect(driver3.getOFSwitchImpl(desc)).andReturn(mockSwitch).once(); - replay(driver1); - replay(driver2); - replay(driver3); - replay(mockSwitch); - returnedSwitch = controller.getOFSwitchInstance(desc); - assertSame(mockSwitch, returnedSwitch); - verify(driver1); - verify(driver2); - verify(driver3); - verify(mockSwitch); - } - - /** - * Test SwitchDriverRegistry - * Test fallback to default if no switch driver is registered for a - * particular prefix - */ - @Test - public void testSwitchDriverRegistryNoDriver() { - IOFSwitchDriver driver = createMock(IOFSwitchDriver.class); - IOFSwitch returnedSwitch = null; - IOFSwitch mockSwitch = createMock(IOFSwitch.class); - controller.addOFSwitchDriver("test switch", driver); - - replay(driver); - replay(mockSwitch); - - OFDescriptionStatistics desc = createOFDescriptionStatistics(); - desc.setManufacturerDescription("test switch"); - desc.setHardwareDescription("version 0.9"); - reset(driver); - reset(mockSwitch); - mockSwitch.setSwitchProperties(desc); - expectLastCall().once(); - expect(driver.getOFSwitchImpl(desc)).andReturn(mockSwitch).once(); - replay(driver); - replay(mockSwitch); - returnedSwitch = controller.getOFSwitchInstance(desc); - assertSame(mockSwitch, returnedSwitch); - verify(driver); - verify(mockSwitch); - - - desc = createOFDescriptionStatistics(); - desc.setManufacturerDescription("Foo Bar test switch"); - desc.setHardwareDescription("version 0.9"); - reset(driver); - reset(mockSwitch); - replay(driver); - replay(mockSwitch); - returnedSwitch = controller.getOFSwitchInstance(desc); - assertNotNull(returnedSwitch); - assertTrue("Returned switch should be OFSwitchImpl", - returnedSwitch instanceof OFSwitchImpl); - assertEquals(desc, returnedSwitch.getDescriptionStatistics()); - verify(driver); - verify(mockSwitch); - } - - /** - * - */ - @Test - public void testDriverRegistryExceptions() { - IOFSwitchDriver driver = createMock(IOFSwitchDriver.class); - IOFSwitchDriver driver2 = createMock(IOFSwitchDriver.class); - replay(driver, driver2); // no calls expected on driver - - //--------------- - // Test exception handling when registering driver - try { - controller.addOFSwitchDriver("foobar", null); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - - try { - controller.addOFSwitchDriver(null, driver); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - - // test that we can register each prefix only once! - controller.addOFSwitchDriver("foobar", driver); - try { - controller.addOFSwitchDriver("foobar", driver); - fail("Expected IllegalStateException not thrown"); - } catch (IllegalStateException e) { - //expected - } - - try { - controller.addOFSwitchDriver("foobar", driver2); - fail("Expected IllegalStateException not thrown"); - } catch (IllegalStateException e) { - //expected - } - - OFDescriptionStatistics desc = createOFDescriptionStatistics(); - - desc.setDatapathDescription(null); - try { - controller.getOFSwitchInstance(desc); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - desc.setHardwareDescription(null); - try { - controller.getOFSwitchInstance(desc); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - desc.setManufacturerDescription(null); - try { - controller.getOFSwitchInstance(desc); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - desc.setSerialNumber(null); - try { - controller.getOFSwitchInstance(desc); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - desc.setSoftwareDescription(null); - try { - controller.getOFSwitchInstance(desc); - fail("Expected NullPointerException not thrown"); - } catch (NullPointerException e) { - //expected - } - verify(driver, driver2); - } - } diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java deleted file mode 100644 index bc4490e73aa34e96c0dc716783999a8e8f59a54d..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java +++ /dev/null @@ -1,1419 +0,0 @@ -package net.floodlightcontroller.core.internal; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; -import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent; -import net.floodlightcontroller.core.IOFSwitch.PortChangeType; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.debugcounter.DebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException; -import net.floodlightcontroller.storage.IResultSet; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.util.OrderedCollection; -import net.floodlightcontroller.util.LinkedHashSetWrapper; - -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.easymock.EasyMock; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.MessageEvent; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFError; -import org.openflow.protocol.OFError.OFBadRequestCode; -import org.openflow.protocol.OFError.OFErrorType; -import org.openflow.protocol.OFFeaturesReply; -import org.openflow.protocol.OFGetConfigReply; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPhysicalPort; -import org.openflow.protocol.OFPortStatus; -import org.openflow.protocol.OFPortStatus.OFPortReason; -import org.openflow.protocol.OFSetConfig; -import org.openflow.protocol.OFStatisticsReply; -import org.openflow.protocol.OFStatisticsRequest; -import org.openflow.protocol.OFType; -import org.openflow.protocol.OFVendor; -import org.openflow.protocol.factory.BasicFactory; -import org.openflow.protocol.statistics.OFDescriptionStatistics; -import org.openflow.protocol.statistics.OFStatisticsType; -import org.openflow.util.HexString; -import org.openflow.vendor.nicira.OFNiciraVendorData; -import org.openflow.vendor.nicira.OFRoleReplyVendorData; -import org.openflow.vendor.nicira.OFRoleRequestVendorData; - -import static org.easymock.EasyMock.*; - -import static org.junit.Assert.*; - - -public class OFChannelHandlerTest { - private static final short CORE_PRIORITY = 4242; - private static final short ACCESS_PRIORITY = 42; - private OLD__Controller controller; - private IThreadPoolService threadPool; - private IDebugCounterService debugCounterService; - private OFChannelHandler handler; - private Channel channel; - private ChannelHandlerContext ctx; - private MessageEvent messageEvent; - private ChannelStateEvent channelStateEvent; - private ChannelPipeline pipeline; - - - private Capture<ExceptionEvent> exceptionEventCapture; - private Capture<List<OFMessage>> writeCapture; - - private OFFeaturesReply featuresReply; - - private Set<Integer> seenXids = null; - private IStorageSourceService storageSource; - private IResultSet storageResultSet; - private IOFSwitch sw; - - - - @Before - public void setUpFeaturesReply() { - featuresReply = (OFFeaturesReply)BasicFactory.getInstance() - .getMessage(OFType.FEATURES_REPLY); - featuresReply.setDatapathId(0x42L); - featuresReply.setBuffers(1); - featuresReply.setTables((byte)1); - featuresReply.setCapabilities(3); - featuresReply.setActions(4); - List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>(); - // A dummy port. - OFPhysicalPort p = new OFPhysicalPort(); - p.setName("Eth1"); - p.setPortNumber((short)1); - ports.add(p); - featuresReply.setPorts(ports); - } - - - @Before - public void setUp() throws Exception { - controller = createMock(OLD__Controller.class); - threadPool = createMock(IThreadPoolService.class); - ctx = createMock(ChannelHandlerContext.class); - channelStateEvent = createMock(ChannelStateEvent.class); - channel = createMock(Channel.class); - messageEvent = createMock(MessageEvent.class); - exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL); - pipeline = createMock(ChannelPipeline.class); - writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL); - sw = createMock(IOFSwitch.class); - seenXids = null; - - // TODO: should mock IDebugCounterService and make sure - // the expected counters are updated. - debugCounterService = new DebugCounter(); - OLD__Controller.Counters counters = - new OLD__Controller.Counters(); - counters.createCounters(debugCounterService); - expect(controller.getCounters()).andReturn(counters).anyTimes(); - replay(controller); - handler = new OFChannelHandler(controller); - verify(controller); - reset(controller); - - resetChannel(); - - // thread pool is usually not called, so start empty replay - replay(threadPool); - - // replay controller. Reset it if you need more specific behavior - replay(controller); - - // replay switch. Reset it if you need more specific behavior - replay(sw); - - // Mock ctx and channelStateEvent - expect(ctx.getChannel()).andReturn(channel).anyTimes(); - expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes(); - replay(ctx, channelStateEvent); - - /* Setup an exception event capture on the channel. Right now - * we only expect exception events to be send up the channel. - * However, it's easy to extend to other events if we need it - */ - pipeline.sendUpstream(capture(exceptionEventCapture)); - expectLastCall().anyTimes(); - replay(pipeline); - } - - @After - public void tearDown() { - /* ensure no exception was thrown */ - if (exceptionEventCapture.hasCaptured()) { - Throwable ex = exceptionEventCapture.getValue().getCause(); - throw new AssertionError("Unexpected exception: " + - ex.getClass().getName() + "(" + ex + ")"); - } - assertFalse("Unexpected messages have been captured", - writeCapture.hasCaptured()); - // verify all mocks. - verify(channel); - verify(messageEvent); - verify(controller); - verify(threadPool); - verify(ctx); - verify(channelStateEvent); - verify(pipeline); - verify(sw); - } - - /** Reset the channel mock and set basic method call expectations */ - void resetChannel() { - reset(channel); - expect(channel.getPipeline()).andReturn(pipeline).anyTimes(); - expect(channel.getRemoteAddress()).andReturn(null).anyTimes(); - } - - - /** reset, setup, and replay the messageEvent mock for the given - * messages - */ - void setupMessageEvent(List<OFMessage> messages) { - reset(messageEvent); - expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce(); - replay(messageEvent); - } - - - /** reset, setup, and replay the messageEvent mock for the given - * messages, mock controller send message to channel handler - * - * This method will reset, start replay on controller, and then verify - */ - void sendMessageToHandlerWithControllerReset(List<OFMessage> messages) - throws Exception { - verify(controller); - reset(controller); - - sendMessageToHandlerNoControllerReset(messages); - } - - /** reset, setup, and replay the messageEvent mock for the given - * messages, mock controller send message to channel handler - * - * This method will start replay on controller, and then verify - */ - void sendMessageToHandlerNoControllerReset(List<OFMessage> messages) - throws Exception { - setupMessageEvent(messages); - - // mock controller - controller.flushAll(); - expectLastCall().atLeastOnce(); - replay(controller); - handler.messageReceived(ctx, messageEvent); - verify(controller); - } - - /** - * Extract the list of OFMessages that was captured by the Channel.write() - * capture. Will check that something was actually captured first. We'll - * collapse the messages from multiple writes into a single list of - * OFMessages. - * Resets the channelWriteCapture. - */ - List<OFMessage> getMessagesFromCapture() { - List<OFMessage> msgs = new ArrayList<OFMessage>(); - - assertTrue("No write on channel was captured", - writeCapture.hasCaptured()); - List<List<OFMessage>> capturedVals = writeCapture.getValues(); - - for (List<OFMessage> oneWriteList: capturedVals) - msgs.addAll(oneWriteList); - writeCapture.reset(); - return msgs; - } - - - /** - * Verify that the given exception event capture (as returned by - * getAndInitExceptionCapture) has thrown an exception of the given - * expectedExceptionClass. - * Resets the capture - */ - void verifyExceptionCaptured( - Class<? extends Throwable> expectedExceptionClass) { - assertTrue("Excpected exception not thrown", - exceptionEventCapture.hasCaptured()); - Throwable caughtEx = exceptionEventCapture.getValue().getCause(); - assertEquals(expectedExceptionClass, caughtEx.getClass()); - exceptionEventCapture.reset(); - } - - /** make sure that the transaction ids in the given messages are - * not 0 and differ between each other. - * While it's not a defect per se if the xids are we want to ensure - * we use different ones for each message we send. - */ - void verifyUniqueXids(List<OFMessage> msgs) { - if (seenXids == null) - seenXids = new HashSet<Integer>(); - for (OFMessage m: msgs) { - int xid = m.getXid(); - assertTrue("Xid in messags is 0", xid != 0); - assertFalse("Xid " + xid + " has already been used", - seenXids.contains(xid)); - seenXids.add(xid); - } - } - - - @Test - public void testInitState() throws Exception { - // Message event needs to be list - expect(messageEvent.getMessage()).andReturn(null); - replay(channel, messageEvent); - handler.messageReceived(ctx, messageEvent); - verify(channel, messageEvent); - verifyExceptionCaptured(AssertionError.class); - - // Message event needs to be list *of OFMessages* - // TODO: messageReceived can throw exceptions that don't get send - // back into the channel (e.g., the ClassCastException below). - // Do we need to care? - /* - reset(channel, messageEvent); - List<String> listOfWrongType = Collections.singletonList("FooBar"); - expect(messageEvent.getMessage()).andReturn(listOfWrongType) - .atLeastOnce(); - replay(channel, messageEvent); - handler.messageReceived(ctx, messageEvent); - verify(channel, messageEvent); - verifyExceptionCaptured(ClassCastException.class); - */ - - // We don't expect to receive /any/ messages in init state since - // channelConnected moves us to a different state - OFMessage m = BasicFactory.getInstance().getMessage(OFType.HELLO); - sendMessageToHandlerWithControllerReset(Collections.singletonList(m)); - - verifyExceptionCaptured(SwitchStateException.class); - assertEquals(OFChannelHandler.ChannelState.INIT, - handler.getStateForTesting()); - } - - /* Move the channel from scratch to WAIT_HELLO state */ - @Test - public void moveToWaitHello() throws Exception { - resetChannel(); - channel.write(capture(writeCapture)); - expectLastCall().andReturn(null).once(); - replay(channel); - // replay unused mocks - replay(messageEvent); - - handler.channelConnected(ctx, channelStateEvent); - - List<OFMessage> msgs = getMessagesFromCapture(); - assertEquals(1, msgs.size()); - assertEquals(OFType.HELLO, msgs.get(0).getType()); - assertEquals(OFChannelHandler.ChannelState.WAIT_HELLO, - handler.getStateForTesting()); - verifyUniqueXids(msgs); - } - - /** Move the channel from scratch to WAIT_FEATURES_REPLY state - * Builds on moveToWaitHello() - * adds testing for WAIT_HELLO state - */ - @Test - public void moveToWaitFeaturesReply() throws Exception { - moveToWaitHello(); - resetChannel(); - channel.write(capture(writeCapture)); - expectLastCall().andReturn(null).atLeastOnce(); - replay(channel); - - OFMessage hello = BasicFactory.getInstance().getMessage(OFType.HELLO); - sendMessageToHandlerWithControllerReset(Collections.singletonList(hello)); - - List<OFMessage> msgs = getMessagesFromCapture(); - assertEquals(1, msgs.size()); - assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType()); - verifyUniqueXids(msgs); - - assertEquals(OFChannelHandler.ChannelState.WAIT_FEATURES_REPLY, - handler.getStateForTesting()); - } - - - /** Move the channel from scratch to WAIT_CONFIG_REPLY state - * Builds on moveToWaitFeaturesReply - * adds testing for WAIT_FEATURES_REPLY state - */ - @Test - public void moveToWaitConfigReply() throws Exception { - moveToWaitFeaturesReply(); - resetChannel(); - channel.write(capture(writeCapture)); - expectLastCall().andReturn(null).atLeastOnce(); - replay(channel); - - sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply)); - - List<OFMessage> msgs = getMessagesFromCapture(); - assertEquals(3, msgs.size()); - assertEquals(OFType.SET_CONFIG, msgs.get(0).getType()); - OFSetConfig sc = (OFSetConfig)msgs.get(0); - assertEquals((short)0xffff, sc.getMissSendLength()); - assertEquals(OFType.BARRIER_REQUEST, msgs.get(1).getType()); - assertEquals(OFType.GET_CONFIG_REQUEST, msgs.get(2).getType()); - verifyUniqueXids(msgs); - assertEquals(OFChannelHandler.ChannelState.WAIT_CONFIG_REPLY, - handler.getStateForTesting()); - } - - /** Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state - * Builds on moveToWaitConfigReply() - * adds testing for WAIT_CONFIG_REPLY state - */ - @Test - public void moveToWaitDescriptionStatReply() throws Exception { - moveToWaitConfigReply(); - resetChannel(); - channel.write(capture(writeCapture)); - expectLastCall().andReturn(null).atLeastOnce(); - replay(channel); - - OFGetConfigReply cr = (OFGetConfigReply)BasicFactory.getInstance() - .getMessage(OFType.GET_CONFIG_REPLY); - cr.setMissSendLength((short)0xffff); - - sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(cr)); - - List<OFMessage> msgs = getMessagesFromCapture(); - assertEquals(1, msgs.size()); - assertEquals(OFType.STATS_REQUEST, msgs.get(0).getType()); - OFStatisticsRequest sr = (OFStatisticsRequest)msgs.get(0); - assertEquals(OFStatisticsType.DESC, sr.getStatisticType()); - // no idea why an OFStatisticsRequest even /has/ a getStatistics() - // methods. It really shouldn't - assertNull(sr.getStatistics()); - verifyUniqueXids(msgs); - assertEquals(OFChannelHandler.ChannelState.WAIT_DESCRIPTION_STAT_REPLY, - handler.getStateForTesting()); - } - - - /** A helper bean that represents the config for a particular switch in - * the storage source. - */ - private class MockStorageSourceConfig { - // the dpid - public String dpid; - // true if the given dpid should be present in the storage source - // if false the storage source will return an empty result - public boolean isPresent; - // the value of isCoreSwitch - public boolean isCoreSwitch; - } - /** setup and replay a mock storage source and result set that - * contains the IsCoreSwitch setting - */ - private void setupMockStorageSource(MockStorageSourceConfig cfg) { - - storageSource = createMock(IStorageSourceService.class); - storageResultSet = createMock(IResultSet.class); - - Iterator<IResultSet> it = null; - - if (cfg.isPresent) { - storageResultSet.getBoolean(OLD__Controller.SWITCH_CONFIG_CORE_SWITCH); - expectLastCall().andReturn(cfg.isCoreSwitch).atLeastOnce(); - it = Collections.singletonList(storageResultSet).iterator(); - } else { - it = Collections.<IResultSet>emptyList().iterator(); - } - - storageResultSet.close(); - expectLastCall().atLeastOnce(); - expect(storageResultSet.iterator()).andReturn(it).atLeastOnce(); - storageSource.getRow(OLD__Controller.SWITCH_CONFIG_TABLE_NAME, cfg.dpid); - expectLastCall().andReturn(storageResultSet).atLeastOnce(); - replay(storageResultSet, storageSource); - } - - private void verifyStorageSource() { - verify(storageSource); - verify(storageResultSet); - } - - private static OFStatisticsReply createDescriptionStatsReply() { - OFStatisticsReply sr = (OFStatisticsReply)BasicFactory.getInstance() - .getMessage(OFType.STATS_REPLY); - sr.setStatisticType(OFStatisticsType.DESC); - OFDescriptionStatistics desc = new OFDescriptionStatistics(); - desc.setDatapathDescription("Datapath Description"); - desc.setHardwareDescription("Hardware Description"); - desc.setManufacturerDescription("Manufacturer Description"); - desc.setSerialNumber("Serial Number"); - desc.setSoftwareDescription("Software Description"); - sr.setStatistics(Collections.singletonList(desc)); - return sr; - } - - /** - * setup the expectations for the mock switch that are needed - * after the switch is instantiated in the WAIT_DESCRIPTION_STATS STATE - * Will reset the switch - * @throws CounterException - */ - private void setupSwitchForInstantiationWithReset(String dpid) - throws Exception { - reset(sw); - sw.setChannel(channel); - expectLastCall().once(); - sw.setFloodlightProvider(controller); - expectLastCall().once(); - sw.setThreadPoolService(threadPool); - expectLastCall().once(); - sw.setDebugCounterService(debugCounterService); - expectLastCall().once(); - sw.setFeaturesReply(featuresReply); - expectLastCall().once(); - sw.setConnected(true); - expectLastCall().once(); - sw.getStringId(); - expectLastCall().andReturn(dpid).atLeastOnce(); - sw.isWriteThrottleEnabled(); // used for log message only - expectLastCall().andReturn(false).anyTimes(); - sw.setAccessFlowPriority(ACCESS_PRIORITY); - expectLastCall().once(); - sw.setCoreFlowPriority(CORE_PRIORITY); - expectLastCall().once(); - } - - /** Move the channel from scratch to WAIT_INITIAL_ROLE state - * for a switch that does not have a sub-handshake - * Builds on moveToWaitDescriptionStatReply() - * adds testing for WAIT_DESCRIPTION_STAT_REPLY state - * @param storageSourceConfig paramterizes the contents of the storage - * source (for IS_CORE_SWITCH) - */ - public void doMoveToWaitInitialRole(MockStorageSourceConfig cfg) - throws Exception { - moveToWaitDescriptionStatReply(); - - // We do not expect a write to the channel for the role request. We add - // the channel to the controller and the controller would in turn - // call handler.sendRoleRequest(). Since we mock the controller so - // we won't see the handler.sendRoleRequest() call and therefore we - // won't see any calls on the channel. - resetChannel(); - replay(channel); - - // build the stats reply - OFStatisticsReply sr = createDescriptionStatsReply(); - OFDescriptionStatistics desc = - (OFDescriptionStatistics) sr.getFirstStatistics(); - - setupMessageEvent(Collections.<OFMessage>singletonList(sr)); - setupMockStorageSource(cfg); - - setupSwitchForInstantiationWithReset(cfg.dpid); - sw.startDriverHandshake(); - expectLastCall().once(); - sw.isDriverHandshakeComplete(); - expectLastCall().andReturn(true).once(); - - if (cfg.isPresent) - sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch); - replay(sw); - - // mock controller - reset(controller); - expect(controller.getDebugCounter()).andReturn(debugCounterService) - .once(); - controller.flushAll(); - expectLastCall().once(); - expect(controller.getThreadPoolService()) - .andReturn(threadPool).once(); - expect(controller.getOFSwitchInstance(eq(desc))) - .andReturn(sw).once(); - expect(controller.getCoreFlowPriority()) - .andReturn(CORE_PRIORITY).once(); - expect(controller.getAccessFlowPriority()) - .andReturn(ACCESS_PRIORITY).once(); - controller.addSwitchChannelAndSendInitialRole(handler); - expectLastCall().once(); - expect(controller.getStorageSourceService()) - .andReturn(storageSource).atLeastOnce(); - replay(controller); - - // send the description stats reply - handler.messageReceived(ctx, messageEvent); - - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - verifyStorageSource(); - } - - /** - * Move the channel from scratch to WAIT_INITIAL_ROLE state via - * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE - * Does extensive testing for the WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state - * - */ - @Test - public void testSwitchDriverSubHandshake() - throws Exception { - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - - moveToWaitDescriptionStatReply(); - - resetChannel(); - channel.write(capture(writeCapture)); - expectLastCall().andReturn(null).atLeastOnce(); - replay(channel); - - // build the stats reply - OFStatisticsReply sr = createDescriptionStatsReply(); - OFDescriptionStatistics desc = - (OFDescriptionStatistics) sr.getFirstStatistics(); - - setupMessageEvent(Collections.<OFMessage>singletonList(sr)); - setupMockStorageSource(cfg); - - // Start the sub-handshake. Switch will indicate that it's not - // complete yet - setupSwitchForInstantiationWithReset(cfg.dpid); - sw.startDriverHandshake(); - expectLastCall().once(); - sw.isDriverHandshakeComplete(); - expectLastCall().andReturn(false).once(); - - if (cfg.isPresent) - sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch); - replay(sw); - - // mock controller - reset(controller); - expect(controller.getDebugCounter()).andReturn(debugCounterService) - .once(); - controller.flushAll(); - expectLastCall().once(); - expect(controller.getThreadPoolService()) - .andReturn(threadPool).once(); - expect(controller.getOFSwitchInstance(eq(desc))) - .andReturn(sw).once(); - expect(controller.getCoreFlowPriority()) - .andReturn(CORE_PRIORITY).once(); - expect(controller.getAccessFlowPriority()) - .andReturn(ACCESS_PRIORITY).once(); - expect(controller.getStorageSourceService()) - .andReturn(storageSource).atLeastOnce(); - replay(controller); - - // send the description stats reply - handler.messageReceived(ctx, messageEvent); - - assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE, - handler.getStateForTesting()); - assertFalse("Unexpected message captured", writeCapture.hasCaptured()); - verifyStorageSource(); - verify(sw); - - - //------------------------------------------------- - // Send a message to the handler, it should be passed to the - // switch's sub-handshake handling. - OFMessage m = BasicFactory.getInstance().getMessage(OFType.HELLO); - resetToStrict(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.processDriverHandshakeMessage(m); - expectLastCall().once(); - expect(sw.isDriverHandshakeComplete()).andReturn(false).once(); - replay(sw); - - sendMessageToHandlerWithControllerReset(Collections.singletonList(m)); - assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE, - handler.getStateForTesting()); - assertFalse("Unexpected message captured", writeCapture.hasCaptured()); - verify(sw); - - //------------------------------------------------- - // Send a ECHO_REQUEST. This should be handled by the OFChannelHandler - // and *not* passed to switch sub-handshake - // TODO: should this be also passed to the switch handshake instead? - m = BasicFactory.getInstance().getMessage(OFType.ECHO_REQUEST); - m.setXid(0x042042); - - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - replay(sw); - sendMessageToHandlerWithControllerReset(Collections.singletonList(m)); - assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE, - handler.getStateForTesting()); - List<OFMessage> msgs = getMessagesFromCapture(); - assertEquals(1, msgs.size()); - assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType()); - assertEquals(0x42042, msgs.get(0).getXid()); - verify(sw); - - - //------------------------------------------------- - //------------------------------------------------- - // Send a message to the handler, it should be passed to the - // switch's sub-handshake handling. After this message the - // sub-handshake will be complete - m = BasicFactory.getInstance().getMessage(OFType.FLOW_REMOVED); - resetToStrict(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.processDriverHandshakeMessage(m); - expectLastCall().once(); - expect(sw.isDriverHandshakeComplete()).andReturn(true).once(); - replay(sw); - - verify(controller); - reset(controller); - controller.addSwitchChannelAndSendInitialRole(handler); - expectLastCall().once(); - sendMessageToHandlerNoControllerReset(Collections.singletonList(m)); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - assertFalse("Unexpected message captured", writeCapture.hasCaptured()); - verify(sw); - - //------------------------------------------------- - - //------------------------------------------------- - } - - @Test - /** Test WaitDescriptionReplyState. No config for switch in storage */ - public void testWaitDescriptionReplyState1() throws Exception { - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - } - - @Test - /** Test WaitDescriptionReplyState. switch is core switch */ - public void testWaitDescriptionReplyState2() throws Exception { - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = true; - cfg.isCoreSwitch = true; - doMoveToWaitInitialRole(cfg); - } - - @Test - /** Test WaitDescriptionReplyState. switch is NOT core switch */ - public void testWaitDescriptionReplyState3() throws Exception { - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = true; - cfg.isCoreSwitch = true; - doMoveToWaitInitialRole(cfg); - } - - /** - * Helper - * Verify that the given OFMessage is a correct Nicira RoleRequest message - * for the given role using the given xid. - */ - private void verifyRoleRequest(OFMessage m, - int expectedXid, - Role expectedRole) { - assertEquals(OFType.VENDOR, m.getType()); - OFVendor vendorMsg = (OFVendor)m; - assertEquals(expectedXid, vendorMsg.getXid()); - assertEquals(OFNiciraVendorData.NX_VENDOR_ID, vendorMsg.getVendor()); - assertTrue("Vendor data is not an instance of OFRoleRequestVendorData" - + " its class is: " + vendorMsg.getVendorData().getClass().getName(), - vendorMsg.getVendorData() instanceof OFRoleRequestVendorData); - OFRoleRequestVendorData requestData = - (OFRoleRequestVendorData)vendorMsg.getVendorData(); - assertEquals(expectedRole.toNxRole(), requestData.getRole()); - } - - /** - * Setup the mock switch and write capture for a role request, set the - * role and verify mocks. - * @param supportsNxRole whether the switch supports role request messages - * to setup the attribute. This must be null (don't yet know if roles - * supported: send to check) or true. - * @param xid The xid to use in the role request - * @param role The role to send - * @throws IOException - */ - private void setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole, - int xid, - Role role) throws IOException { - assertTrue("This internal test helper method most not be called " + - "with supportsNxRole==false. Test setup broken", - supportsNxRole == null || supportsNxRole == true); - reset(sw); - expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) - .andReturn(supportsNxRole).atLeastOnce(); - expect(sw.getNextTransactionId()).andReturn(xid).once(); - sw.write(capture(writeCapture), EasyMock.<FloodlightContext>anyObject()); - expectLastCall().anyTimes(); - replay(sw); - - handler.sendRoleRequest(role); - - List<OFMessage> msgs = getMessagesFromCapture(); - assertEquals(1, msgs.size()); - verifyRoleRequest(msgs.get(0), xid, role); - verify(sw); - } - - /** - * Setup the mock switch for a role change request where the switch - * does not support roles. - * - * Needs to verify and reset the controller since we need to set - * an expectation - */ - private void setupSwitchRoleChangeUnsupported(int xid, - Role role) { - boolean supportsNxRole = false; - reset(sw); - expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) - .andReturn(supportsNxRole).atLeastOnce(); - // TODO: hmmm. While it's not incorrect that we set the attribute - // again it looks odd. Maybe change - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole); - expectLastCall().anyTimes(); - sw.setHARole(role); - expectLastCall().once(); - if (role == Role.SLAVE) { - sw.disconnectOutputStream(); - expectLastCall().once(); - } else { - verify(controller); - reset(controller); - controller.switchActivated(sw); - replay(controller); - } - replay(sw); - - handler.sendRoleRequest(role); - - verify(sw); - } - - /** Return a Nicira RoleReply message for the given role */ - private OFMessage getRoleReply(int xid, Role role) { - OFVendor vm = (OFVendor)BasicFactory.getInstance() - .getMessage(OFType.VENDOR); - vm.setXid(xid); - vm.setVendor(OFNiciraVendorData.NX_VENDOR_ID); - OFRoleReplyVendorData replyData = new OFRoleReplyVendorData(); - replyData.setRole(role.toNxRole()); - vm.setVendorData(replyData); - return vm; - } - - /** Return an OFError of the given type with the given xid */ - private OFMessage getErrorMessage(OFErrorType type, - int i, - int xid) { - OFError e = (OFError) BasicFactory.getInstance() - .getMessage(OFType.ERROR); - e.setErrorType(type); - e.setErrorCode((short)i); - e.setXid(xid); - return e; - } - - - /** Move the channel from scratch to MASTER state - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - * - * This method tests only the simple case that the switch supports roles - * and transitions to MASTER - */ - @Test - public void testInitialMoveToMasterWithRole() throws Exception { - int xid = 42; - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); - expectLastCall().once(); - sw.setHARole(Role.MASTER); - expectLastCall().once(); - replay(sw); - - verify(controller); - reset(controller); - controller.switchActivated(sw); - expectLastCall().once(); - OFMessage reply = getRoleReply(xid, Role.MASTER); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerNoControllerReset(Collections.singletonList(reply)); - - assertEquals(OFChannelHandler.ChannelState.MASTER, - handler.getStateForTesting()); - } - - /** Move the channel from scratch to SLAVE state - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - * - * This method tests only the simple case that the switch supports roles - * and transitions to SLAVE - */ - @Test - public void testInitialMoveToSlaveWithRole() throws Exception { - int xid = 42; - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); - expectLastCall().once(); - sw.setHARole(Role.SLAVE); - expectLastCall().once(); - replay(sw); - - verify(controller); - reset(controller); - controller.switchDeactivated(sw); - expectLastCall().once(); - OFMessage reply = getRoleReply(xid, Role.SLAVE); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerNoControllerReset(Collections.singletonList(reply)); - - assertEquals(OFChannelHandler.ChannelState.SLAVE, - handler.getStateForTesting()); - } - - /** Move the channel from scratch to MASTER state - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - * - * This method tests the case that the switch does NOT support roles. - * The channel handler still needs to send the initial request to find - * out that whether the switch supports roles. - */ - @Test - public void testInitialMoveToMasterNoRole() throws Exception { - int xid = 43; - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false); - expectLastCall().once(); - sw.setHARole(Role.MASTER); - expectLastCall().once(); - replay(sw); - - // FIXME: shouldn't use ordinal(), but OFError is broken - - // Error with incorrect xid and type. Should be ignored. - OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION, - 0, - xid+1); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerWithControllerReset(Collections.singletonList(err)); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Error with correct xid. Should trigger state transition - err = getErrorMessage(OFErrorType.OFPET_BAD_REQUEST, - OFError.OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal(), - xid); - verify(controller); - reset(controller); - controller.switchActivated(sw); - expectLastCall().once(); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerNoControllerReset(Collections.singletonList(err)); - - assertEquals(OFChannelHandler.ChannelState.MASTER, - handler.getStateForTesting()); - - } - - /** Move the channel from scratch to MASTER state - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - * - * We let the initial role request time out. Role support should be - * disabled but the switch should be activated. - */ - @Test - public void testInitialMoveToMasterTimeout() throws Exception { - int timeout = 50; - handler.useRoleChangerWithOtherTimeoutForTesting(timeout); - int xid = 4343; - - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false); - expectLastCall().once(); - sw.setHARole(Role.MASTER); - expectLastCall().once(); - replay(sw); - - OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY); - - Thread.sleep(timeout+5); - - verify(controller); - reset(controller); - controller.switchActivated(sw); - expectLastCall().once(); - sendMessageToHandlerNoControllerReset(Collections.singletonList(m)); - - assertEquals(OFChannelHandler.ChannelState.MASTER, - handler.getStateForTesting()); - - } - - - /** Move the channel from scratch to SLAVE state - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - * - * This method tests the case that the switch does NOT support roles. - * The channel handler still needs to send the initial request to find - * out that whether the switch supports roles. - * - */ - @Test - public void testInitialMoveToSlaveNoRole() throws Exception { - int xid = 44; - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false); - expectLastCall().once(); - sw.setHARole(Role.SLAVE); - expectLastCall().once(); - sw.disconnectOutputStream(); // Make sure we disconnect - expectLastCall().once(); - replay(sw); - - - // FIXME: shouldn't use ordinal(), but OFError is broken - - // Error with incorrect xid and type. Should be ignored. - OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION, - 0, - xid+1); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerWithControllerReset(Collections.singletonList(err)); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Error with correct xid. Should trigger state transition - err = getErrorMessage(OFErrorType.OFPET_BAD_REQUEST, - OFError.OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal(), - xid); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerWithControllerReset(Collections.singletonList(err)); - } - - - /** Move the channel from scratch to SLAVE state - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - * - * We let the initial role request time out. The switch should be - * disconnected - */ - @Test - public void testInitialMoveToSlaveTimeout() throws Exception { - int timeout = 50; - handler.useRoleChangerWithOtherTimeoutForTesting(timeout); - int xid = 4444; - - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false); - expectLastCall().once(); - sw.setHARole(Role.SLAVE); - expectLastCall().once(); - sw.disconnectOutputStream(); // Make sure we disconnect - expectLastCall().once(); - replay(sw); - - OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY); - - Thread.sleep(timeout+5); - - sendMessageToHandlerWithControllerReset(Collections.singletonList(m)); - } - - - /** Move channel from scratch to WAIT_INITIAL_STATE, then MASTER, - * then SLAVE for cases where the switch does not support roles. - * I.e., the final SLAVE transition should disconnect the switch. - */ - @Test - public void testNoRoleInitialToMasterToSlave() throws Exception { - int xid = 46; - // First, lets move the state to MASTER without role support - testInitialMoveToMasterNoRole(); - assertEquals(OFChannelHandler.ChannelState.MASTER, - handler.getStateForTesting()); - - // try to set master role again. should be a no-op - setupSwitchRoleChangeUnsupported(xid, Role.MASTER); - assertEquals(OFChannelHandler.ChannelState.MASTER, - handler.getStateForTesting()); - - - setupSwitchRoleChangeUnsupported(xid, Role.SLAVE); - assertEquals(OFChannelHandler.ChannelState.SLAVE, - handler.getStateForTesting()); - - } - - /** Move the channel to MASTER state - * Expects that the channel is in MASTER or SLAVE state. - * - */ - public void changeRoleToMasterWithRequest() throws Exception { - int xid = 4242; - - assertTrue("This method can only be called when handler is in " + - "MASTER or SLAVE role", handler.isHandshakeComplete()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); - expectLastCall().once(); - sw.setHARole(Role.MASTER); - expectLastCall().once(); - replay(sw); - - verify(controller); - reset(controller); - controller.switchActivated(sw); - expectLastCall().once(); - OFMessage reply = getRoleReply(xid, Role.MASTER); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerNoControllerReset(Collections.singletonList(reply)); - - assertEquals(OFChannelHandler.ChannelState.MASTER, - handler.getStateForTesting()); - } - - /** Move the channel to SLAVE state - * Expects that the channel is in MASTER or SLAVE state. - * - */ - public void changeRoleToSlaveWithRequest() throws Exception { - int xid = 2323; - - assertTrue("This method can only be called when handler is in " + - "MASTER or SLAVE role", handler.isHandshakeComplete()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE); - - // prepare mocks and inject the role reply message - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true); - expectLastCall().once(); - sw.setHARole(Role.SLAVE); - expectLastCall().once(); - replay(sw); - - verify(controller); - reset(controller); - controller.switchDeactivated(sw); - expectLastCall().once(); - OFMessage reply = getRoleReply(xid, Role.SLAVE); - // sendMessageToHandler will verify and rest controller mock - sendMessageToHandlerNoControllerReset(Collections.singletonList(reply)); - - assertEquals(OFChannelHandler.ChannelState.SLAVE, - handler.getStateForTesting()); - } - - @Test - public void testMultiRoleChange1() throws Exception { - testInitialMoveToMasterWithRole(); - changeRoleToMasterWithRequest(); - changeRoleToSlaveWithRequest(); - changeRoleToSlaveWithRequest(); - changeRoleToMasterWithRequest(); - changeRoleToSlaveWithRequest(); - } - - @Test - public void testMultiRoleChange2() throws Exception { - testInitialMoveToSlaveWithRole(); - changeRoleToMasterWithRequest(); - changeRoleToSlaveWithRequest(); - changeRoleToSlaveWithRequest(); - changeRoleToMasterWithRequest(); - changeRoleToSlaveWithRequest(); - } - - /** Start from scratch and reply with an unexpected error to the role - * change request - * Builds on doMoveToWaitInitialRole() - * adds testing for WAIT_INITAL_ROLE state - */ - @Test - public void testInitialRoleChangeOtherError() throws Exception { - int xid = 4343; - // first, move us to WAIT_INITIAL_ROLE_STATE - MockStorageSourceConfig cfg = new MockStorageSourceConfig(); - cfg.dpid = HexString.toHexString(featuresReply.getDatapathId()); - cfg.isPresent = false; - doMoveToWaitInitialRole(cfg); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - // Set the role - setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER); - assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE, - handler.getStateForTesting()); - - - // FIXME: shouldn't use ordinal(), but OFError is broken - - OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION, - 0, - xid); - verify(sw); - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - replay(sw); - sendMessageToHandlerWithControllerReset(Collections.singletonList(err)); - - verifyExceptionCaptured(SwitchStateException.class); - } - - /** - * Test dispatch of messages while in MASTER role - */ - @Test - public void testMessageDispatchMaster() throws Exception { - testInitialMoveToMasterWithRole(); - - // Send packet in. expect dispatch - OFPacketIn pi = (OFPacketIn) - BasicFactory.getInstance().getMessage(OFType.PACKET_IN); - reset(controller); - controller.handleMessage(sw, pi, null); - expectLastCall().once(); - sendMessageToHandlerNoControllerReset( - Collections.<OFMessage>singletonList(pi)); - verify(controller); - // TODO: many more to go - } - - /** - * Test port status message handling while MASTER - * - */ - @Test - public void testPortStatusMessageMaster() throws Exception { - long dpid = featuresReply.getDatapathId(); - testInitialMoveToMasterWithRole(); - - OFPhysicalPort p = new OFPhysicalPort(); - p.setName("Port1"); - p.setPortNumber((short)1); - OFPortStatus ps = (OFPortStatus) - BasicFactory.getInstance().getMessage(OFType.PORT_STATUS); - ps.setDesc(p); - - // The events we expect sw.handlePortStatus to return - // We'll just use the same list for all valid OFPortReasons and add - // arbitrary events for arbitrary ports that are not necessarily - // related to the port status message. Our goal - // here is not to return the correct set of events but the make sure - // that a) sw.handlePortStatus is called - // b) the list of events sw.handlePortStatus returns is sent - // as IOFSwitchListener notifications. - OrderedCollection<PortChangeEvent> events = - new LinkedHashSetWrapper<PortChangeEvent>(); - ImmutablePort p1 = ImmutablePort.create("eth1", (short)1); - ImmutablePort p2 = ImmutablePort.create("eth2", (short)2); - ImmutablePort p3 = ImmutablePort.create("eth3", (short)3); - ImmutablePort p4 = ImmutablePort.create("eth4", (short)4); - ImmutablePort p5 = ImmutablePort.create("eth5", (short)5); - events.add(new PortChangeEvent(p1, PortChangeType.ADD)); - events.add(new PortChangeEvent(p2, PortChangeType.DELETE)); - events.add(new PortChangeEvent(p3, PortChangeType.UP)); - events.add(new PortChangeEvent(p4, PortChangeType.DOWN)); - events.add(new PortChangeEvent(p5, PortChangeType.OTHER_UPDATE)); - - - for (OFPortReason reason: OFPortReason.values()) { - ps.setReason(reason.getReasonCode()); - - reset(sw); - expect(sw.inputThrottled(anyObject(OFMessage.class))) - .andReturn(false).anyTimes(); - expect(sw.getId()).andReturn(dpid).anyTimes(); - - expect(sw.processOFPortStatus(ps)).andReturn(events).once(); - replay(sw); - - reset(controller); - controller.notifyPortChanged(sw, p1, PortChangeType.ADD); - controller.notifyPortChanged(sw, p2, PortChangeType.DELETE); - controller.notifyPortChanged(sw, p3, PortChangeType.UP); - controller.notifyPortChanged(sw, p4, PortChangeType.DOWN); - controller.notifyPortChanged(sw, p5, PortChangeType.OTHER_UPDATE); - sendMessageToHandlerNoControllerReset( - Collections.<OFMessage>singletonList(ps)); - verify(sw); - verify(controller); - } - } - - /** - * Test re-assert MASTER - * - */ - @Test - public void testReassertMaster() throws Exception { - testInitialMoveToMasterWithRole(); - - OFError err = (OFError) - BasicFactory.getInstance().getMessage(OFType.ERROR); - err.setXid(42); - err.setErrorType(OFErrorType.OFPET_BAD_REQUEST); - err.setErrorCode(OFBadRequestCode.OFPBRC_EPERM); - - reset(controller); - controller.reassertRole(handler, Role.MASTER); - expectLastCall().once(); - controller.handleMessage(sw, err, null); - expectLastCall().once(); - - sendMessageToHandlerNoControllerReset( - Collections.<OFMessage>singletonList(err)); - - verify(sw); - verify(controller); - } - - -} diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFStatisticsFutureTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFStatisticsFutureTest.java deleted file mode 100644 index 15dc9f401052962dde4f1df3ce3111599f87d1e4..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/internal/OFStatisticsFutureTest.java +++ /dev/null @@ -1,149 +0,0 @@ -package net.floodlightcontroller.core.internal; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.test.MockThreadPoolService; - -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.*; -import org.openflow.protocol.OFStatisticsReply; -import org.openflow.protocol.statistics.OFFlowStatisticsReply; -import org.openflow.protocol.statistics.OFStatistics; -import org.openflow.protocol.statistics.OFStatisticsType; - -import static org.easymock.EasyMock.*; - -public class OFStatisticsFutureTest { - private MockThreadPoolService tp; - - @Before - public void setUp() { - tp = new MockThreadPoolService(); - } - - private OFStatisticsReply getStatisticsReply(int transactionId, - int count, boolean moreReplies) { - OFStatisticsReply sr = new OFStatisticsReply(); - sr.setXid(transactionId); - sr.setStatisticType(OFStatisticsType.FLOW); - List<OFStatistics> statistics = new ArrayList<OFStatistics>(); - for (int i = 0; i < count; ++i) { - statistics.add(new OFFlowStatisticsReply()); - } - sr.setStatistics(statistics); - if (moreReplies) - sr.setFlags((short) 1); - return sr; - } - - public class FutureFetcher<E> implements Runnable { - public E value; - public Future<E> future; - - public FutureFetcher(Future<E> future) { - this.future = future; - } - - @Override - public void run() { - try { - value = future.get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * @return the value - */ - public E getValue() { - return value; - } - - /** - * @return the future - */ - public Future<E> getFuture() { - return future; - } - } - - /** - * - * @throws Exception - */ - @Test - public void testOFStatisticsFuture() throws Exception { - // Test for a single stats reply - IOFSwitch sw = createMock(IOFSwitch.class); - sw.cancelStatisticsReply(1); - OFStatisticsFuture sf = new OFStatisticsFuture(tp, sw, 1); - - replay(sw); - List<OFStatistics> stats; - FutureFetcher<List<OFStatistics>> ff = new FutureFetcher<List<OFStatistics>>(sf); - Thread t = new Thread(ff); - t.start(); - sf.deliverFuture(sw, getStatisticsReply(1, 10, false)); - - t.join(); - stats = ff.getValue(); - verify(sw); - assertEquals(10, stats.size()); - - // Test multiple stats replies - reset(sw); - sw.cancelStatisticsReply(1); - - sf = new OFStatisticsFuture(tp, sw, 1); - - replay(sw); - ff = new FutureFetcher<List<OFStatistics>>(sf); - t = new Thread(ff); - t.start(); - sf.deliverFuture(sw, getStatisticsReply(1, 10, true)); - sf.deliverFuture(sw, getStatisticsReply(1, 5, false)); - t.join(); - - stats = sf.get(); - verify(sw); - assertEquals(15, stats.size()); - - // Test cancellation - reset(sw); - sw.cancelStatisticsReply(1); - sf = new OFStatisticsFuture(tp, sw, 1); - - replay(sw); - ff = new FutureFetcher<List<OFStatistics>>(sf); - t = new Thread(ff); - t.start(); - sf.cancel(true); - t.join(); - - stats = sf.get(); - verify(sw); - assertEquals(0, stats.size()); - - // Test self timeout - reset(sw); - sw.cancelStatisticsReply(1); - sf = new OFStatisticsFuture(tp, sw, 1, 75, TimeUnit.MILLISECONDS); - - replay(sw); - ff = new FutureFetcher<List<OFStatistics>>(sf); - t = new Thread(ff); - t.start(); - t.join(2000); - - stats = sf.get(); - verify(sw); - assertEquals(0, stats.size()); - } - -} diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java deleted file mode 100644 index 2899d44400ad49663c009ede80e5141cebff077e..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java +++ /dev/null @@ -1,1518 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.internal; - -import static org.easymock.EasyMock.*; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted; -import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted; -import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted; -import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent; -import net.floodlightcontroller.core.IOFSwitch.PortChangeType; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.OFSwitchBase; -import net.floodlightcontroller.debugcounter.DebugCounter; -import net.floodlightcontroller.debugcounter.IDebugCounterService; -import net.floodlightcontroller.packet.ARP; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; - -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPortStatus; -import org.openflow.protocol.OFType; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFPhysicalPort.OFPortConfig; -import org.openflow.protocol.OFPhysicalPort.OFPortFeatures; -import org.openflow.protocol.OFPortStatus.OFPortReason; -import org.openflow.protocol.factory.BasicFactory; -import org.openflow.protocol.statistics.OFDescriptionStatistics; -import org.openflow.util.HexString; - -public class OFSwitchBaseTest { - private static final String srcMac = "00:44:33:22:11:00"; - IFloodlightProviderService floodlightProvider; - Map<Long, IOFSwitch> switches; - private OFMessage blockMessage; - private OFPacketIn pi; - private IPacket testPacket; - private byte[] testPacketSerialized; - - private class OFSwitchTest extends OFSwitchBase { - public OFSwitchTest(IFloodlightProviderService fp) { - super(); - stringId = "whatever"; - datapathId = 1L; - floodlightProvider = fp; - } - - @Override - public void setSwitchProperties(OFDescriptionStatistics description) { - // TODO Auto-generated method stub - } - - @Override - public OFPortType getPortType(short port_num) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isFastPort(short port_num) { - // TODO Auto-generated method stub - return false; - } - - @Override - public void write(OFMessage msg, FloodlightContext cntx) { - blockMessage = msg; - } - - public void setThresholds(int high, int low, int host, int port) { - sw.setInputThrottleThresholds(high, low, host, port); - } - - public boolean inputThrottleEnabled() { - return packetInThrottleEnabled; - } - - @Override - public String toString() { - return "OFSwitchTest"; - } - } - private OFSwitchTest sw; - private ImmutablePort p1a; - private ImmutablePort p1b; - private ImmutablePort p2a; - private ImmutablePort p2b; - private ImmutablePort p3; - private final ImmutablePort portFoo1 = ImmutablePort.create("foo", (short)11); - private final ImmutablePort portFoo2 = ImmutablePort.create("foo", (short)12); - private final ImmutablePort portBar1 = ImmutablePort.create("bar", (short)11); - private final ImmutablePort portBar2 = ImmutablePort.create("bar", (short)12); - private final PortChangeEvent portFoo1Add = - new PortChangeEvent(portFoo1, PortChangeType.ADD); - private final PortChangeEvent portFoo2Add = - new PortChangeEvent(portFoo2, PortChangeType.ADD); - private final PortChangeEvent portBar1Add = - new PortChangeEvent(portBar1, PortChangeType.ADD); - private final PortChangeEvent portBar2Add = - new PortChangeEvent(portBar2, PortChangeType.ADD); - private final PortChangeEvent portFoo1Del = - new PortChangeEvent(portFoo1, PortChangeType.DELETE); - private final PortChangeEvent portFoo2Del = - new PortChangeEvent(portFoo2, PortChangeType.DELETE); - private final PortChangeEvent portBar1Del = - new PortChangeEvent(portBar1, PortChangeType.DELETE); - private final PortChangeEvent portBar2Del = - new PortChangeEvent(portBar2, PortChangeType.DELETE); - - @Before - public void setUp() throws Exception { - blockMessage = null; - // Build our test packet - testPacket = new Ethernet() - .setSourceMACAddress(srcMac) - .setDestinationMACAddress("00:11:22:33:44:55") - .setEtherType(Ethernet.TYPE_ARP) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REPLY) - .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) - .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) - .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) - .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); - testPacketSerialized = testPacket.serialize(); - - pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(testPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) testPacketSerialized.length); - floodlightProvider = createMock(IFloodlightProviderService.class); - sw = new OFSwitchTest(floodlightProvider); - IDebugCounterService debugCounter = new DebugCounter(); - sw.setDebugCounterService(debugCounter); - switches = new ConcurrentHashMap<Long, IOFSwitch>(); - switches.put(sw.getId(), sw); - expect(floodlightProvider.getSwitch(sw.getId())).andReturn(sw).anyTimes(); - expect(floodlightProvider.getOFMessageFactory()) - .andReturn(BasicFactory.getInstance()).anyTimes(); - } - - @Before - public void setUpPorts() { - ImmutablePort.Builder bld = new ImmutablePort.Builder(); - // p1a is disabled - p1a = bld.setName("port1") - .setPortNumber((short)1) - .setPortStateLinkDown(true) - .build(); - assertFalse("Sanity check portEnabled", p1a.isEnabled()); - - // p1b is enabled - // p1b has different feature from p1a - p1b = bld.addCurrentFeature(OFPortFeatures.OFPPF_1GB_FD) - .setPortStateLinkDown(false) - .build(); - assertTrue("Sanity check portEnabled", p1b.isEnabled()); - - // p2 is disabled - // p2 has mixed case - bld = new ImmutablePort.Builder(); - p2a = bld.setName("Port2") - .setPortNumber((short)2) - .setPortStateLinkDown(false) - .addConfig(OFPortConfig.OFPPC_PORT_DOWN) - .build(); - // p2b only differs in PortFeatures - p2b = bld.addCurrentFeature(OFPortFeatures.OFPPF_100MB_HD) - .build(); - assertFalse("Sanity check portEnabled", p2a.isEnabled()); - // p3 is enabled - // p3 has mixed case - bld = new ImmutablePort.Builder(); - p3 = bld.setName("porT3") - .setPortNumber((short)3) - .setPortStateLinkDown(false) - .build(); - assertTrue("Sanity check portEnabled", p3.isEnabled()); - - } - - /** - * By default, high threshold is infinite - */ - @Test - public void testNoPacketInThrottle() { - replay(floodlightProvider); - /* disable input throttle */ - sw.setThresholds(Integer.MAX_VALUE, 1, 0, 0); - for (int i = 0; i < 200; i++) { - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(blockMessage == null); - assertFalse(sw.inputThrottleEnabled()); - } - - /** - * The test sends packet in at infinite rate (< 1ms), - * so throttling should be enabled on 100th packet, when the first - * rate measurement is done. - */ - @Test - public void testPacketInStartThrottle() { - floodlightProvider.addSwitchEvent(anyLong(), - (String)anyObject(), anyBoolean()); - replay(floodlightProvider); - - int high = 500; - sw.setThresholds(high, 10, 50, 200); - // We measure time lapse every 1000 packets - for (int i = 0; i < 1000; i++) { - assertFalse(sw.inputThrottleEnabled()); - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(sw.inputThrottleEnabled()); - assertTrue(sw.inputThrottled(pi)); - assertTrue(sw.inputThrottled(pi)); - assertTrue(blockMessage == null); - } - - /** - * With throttling enabled, raise the low water mark threshold, - * verify throttling stops. - * @throws InterruptedException - */ - @Test - public void testPacketInStopThrottle() throws InterruptedException { - floodlightProvider.addSwitchEvent(anyLong(), - (String)anyObject(), anyBoolean()); - expectLastCall().times(2); - replay(floodlightProvider); - - sw.setThresholds(100, 10, 50, 200); - // First, enable throttling - for (int i = 0; i < 1000; i++) { - assertFalse(sw.inputThrottleEnabled()); - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(sw.inputThrottleEnabled()); - - sw.setThresholds(Integer.MAX_VALUE, 100000, 50, 200); - for (int i = 0; i < 999; i++) { - assertTrue(sw.inputThrottled(pi)); - assertTrue(sw.inputThrottleEnabled()); - } - // Sleep for 2 msec, next packet should disable throttling - Thread.sleep(2); - assertFalse(sw.inputThrottled(pi)); - assertFalse(sw.inputThrottleEnabled()); - } - - /** - * With throttling enabled, if rate of unique flows from a host - * exceeds set threshold, a flow mod should be emitted to block host - */ - @Test - public void testPacketInBlockHost() { - floodlightProvider.addSwitchEvent(anyLong(), - (String)anyObject(), anyBoolean()); - expectLastCall().times(2); - replay(floodlightProvider); - - int high = 500; - int perMac = 50; - sw.setThresholds(high, 10, perMac, 200); - // First, enable throttling - for (int i = 0; i < 1000; i++) { - assertFalse(sw.inputThrottleEnabled()); - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(sw.inputThrottleEnabled()); - assertTrue(blockMessage == null); - - // Build unique flows with the same source mac - for (int j = 0; j < perMac - 1; j++) { - testPacketSerialized[5]++; - pi.setPacketData(testPacketSerialized); - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(blockMessage == null); - testPacketSerialized[5]++; - pi.setPacketData(testPacketSerialized); - assertFalse(sw.inputThrottled(pi)); - - // Verify the message is a flowmod with a hard timeout and srcMac - assertTrue(blockMessage != null); - assertTrue(blockMessage instanceof OFFlowMod); - OFFlowMod fm = (OFFlowMod) blockMessage; - assertTrue(fm.getHardTimeout() == 5); - OFMatch match = fm.getMatch(); - assertTrue((match.getWildcards() & OFMatch.OFPFW_DL_SRC) == 0); - assertTrue(Arrays.equals(match.getDataLayerSource(), - HexString.fromHexString(srcMac))); - - // Verify non-unique OFMatches are throttled - assertTrue(sw.inputThrottled(pi)); - } - - /** - * With throttling enabled, if rate of unique flows from a port - * exceeds set threshold, a flow mod should be emitted to block port - */ - @Test - public void testPacketInBlockPort() { - floodlightProvider.addSwitchEvent(anyLong(), - (String)anyObject(), anyBoolean()); - expectLastCall().times(2); - replay(floodlightProvider); - - int high = 500; - int perPort = 200; - sw.setThresholds(high, 10, 50, perPort); - // First, enable throttling - for (int i = 0; i < 1000; i++) { - assertFalse(sw.inputThrottleEnabled()); - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(sw.inputThrottleEnabled()); - assertTrue(blockMessage == null); - - // Build unique flows with different source mac - for (int j = 0; j < perPort - 1; j++) { - testPacketSerialized[11]++; - pi.setPacketData(testPacketSerialized); - assertFalse(sw.inputThrottled(pi)); - } - assertTrue(blockMessage == null); - testPacketSerialized[11]++; - pi.setPacketData(testPacketSerialized); - assertFalse(sw.inputThrottled(pi)); - - // Verify the message is a flowmod with a hard timeout and per port - assertTrue(blockMessage != null); - assertTrue(blockMessage instanceof OFFlowMod); - OFFlowMod fm = (OFFlowMod) blockMessage; - assertTrue(fm.getHardTimeout() == 5); - OFMatch match = fm.getMatch(); - assertTrue((match.getWildcards() & OFMatch.OFPFW_DL_SRC) != 0); - assertTrue((match.getWildcards() & OFMatch.OFPFW_IN_PORT) == 0); - assertTrue(match.getInputPort() == 1); - - // Verify non-unique OFMatches are throttled - assertTrue(sw.inputThrottled(pi)); - } - - /** - * Test whether two collections contains the same elements, regardless - * of the order in which the elements appear in the collections - * @param expected - * @param actual - */ - private static <T> void assertCollectionEqualsNoOrder(Collection<T> expected, - Collection<T> actual) { - String msg = String.format("expected=%s, actual=%s", - expected, actual); - assertEquals(msg, expected.size(), actual.size()); - for(T e: expected) { - if (!actual.contains(e)) { - msg = String.format("Expected element %s not found in " + - "actual. expected=%s, actual=%s", - e, expected, actual); - fail(msg); - } - } - } - - - /** - * Test "normal" setPorts() and comparePorts() methods. No name<->number - * conflicts or exception testing. - */ - @Test - public void testBasicSetPortOperations() { - Collection<ImmutablePort> oldPorts = Collections.emptyList(); - Collection<ImmutablePort> oldEnabledPorts = Collections.emptyList(); - Collection<Short> oldEnabledPortNumbers = Collections.emptyList(); - List<ImmutablePort> ports = new ArrayList<ImmutablePort>(); - - - Collection<PortChangeEvent> expectedChanges = - new ArrayList<IOFSwitch.PortChangeEvent>(); - - Collection<PortChangeEvent> actualChanges = sw.comparePorts(ports); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertEquals(0, sw.getPorts().size()); - assertEquals(0, sw.getEnabledPorts().size()); - assertEquals(0, sw.getEnabledPortNumbers().size()); - - actualChanges = sw.setPorts(ports); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertEquals(0, sw.getPorts().size()); - assertEquals(0, sw.getEnabledPorts().size()); - assertEquals(0, sw.getEnabledPortNumbers().size()); - - //--------------------------------------------- - // Add port p1a and p2a - ports.add(p1a); - ports.add(p2a); - - PortChangeEvent evP1aAdded = - new PortChangeEvent(p1a, PortChangeType.ADD); - PortChangeEvent evP2aAdded = - new PortChangeEvent(p2a, PortChangeType.ADD); - - expectedChanges.clear(); - expectedChanges.add(evP1aAdded); - expectedChanges.add(evP2aAdded); - - actualChanges = sw.comparePorts(ports); - assertEquals(0, sw.getPorts().size()); - assertEquals(0, sw.getEnabledPorts().size()); - assertEquals(0, sw.getEnabledPortNumbers().size()); - assertEquals(2, actualChanges.size()); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - - actualChanges = sw.setPorts(ports); - assertEquals(2, actualChanges.size()); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - assertTrue("enabled ports should be empty", - sw.getEnabledPortNumbers().isEmpty()); - assertTrue("enabled ports should be empty", - sw.getEnabledPorts().isEmpty()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(null, sw.getPort((short)3)); - assertEquals(null, sw.getPort("port3")); - assertEquals(null, sw.getPort("PoRt3")); // case insensitive get - - - //---------------------------------------------------- - // Set the same ports again. No changes - oldPorts = sw.getPorts(); - oldEnabledPorts = sw.getEnabledPorts(); - oldEnabledPortNumbers = sw.getEnabledPortNumbers(); - - expectedChanges.clear(); - - actualChanges = sw.comparePorts(ports); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertEquals(oldPorts, sw.getPorts()); - assertEquals(oldEnabledPorts, sw.getEnabledPorts()); - assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers()); - - actualChanges = sw.setPorts(ports); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertEquals(oldPorts, sw.getPorts()); - assertEquals(oldEnabledPorts, sw.getEnabledPorts()); - assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers()); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - assertTrue("enabled ports should be empty", - sw.getEnabledPortNumbers().isEmpty()); - assertTrue("enabled ports should be empty", - sw.getEnabledPorts().isEmpty()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(null, sw.getPort((short)3)); - assertEquals(null, sw.getPort("port3")); - assertEquals(null, sw.getPort("PoRt3")); // case insensitive get - - //---------------------------------------------------- - // Remove p1a, add p1b. Should receive a port up - oldPorts = sw.getPorts(); - oldEnabledPorts = sw.getEnabledPorts(); - oldEnabledPortNumbers = sw.getEnabledPortNumbers(); - ports.clear(); - ports.add(p2a); - ports.add(p1b); - - // comparePorts - PortChangeEvent evP1bUp = new PortChangeEvent(p1b, PortChangeType.UP); - actualChanges = sw.comparePorts(ports); - assertEquals(oldPorts, sw.getPorts()); - assertEquals(oldEnabledPorts, sw.getEnabledPorts()); - assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers()); - assertEquals(1, actualChanges.size()); - assertTrue("No UP event for port1", actualChanges.contains(evP1bUp)); - - // setPorts - actualChanges = sw.setPorts(ports); - assertEquals(1, actualChanges.size()); - assertTrue("No UP event for port1", actualChanges.contains(evP1bUp)); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - List<ImmutablePort> enabledPorts = new ArrayList<ImmutablePort>(); - enabledPorts.add(p1b); - List<Short> enabledPortNumbers = new ArrayList<Short>(); - enabledPortNumbers.add((short)1); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1b, sw.getPort((short)1)); - assertEquals(p1b, sw.getPort("port1")); - assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(null, sw.getPort((short)3)); - assertEquals(null, sw.getPort("port3")); - assertEquals(null, sw.getPort("PoRt3")); // case insensitive get - - //---------------------------------------------------- - // Remove p2a, add p2b. Should receive a port modify - oldPorts = sw.getPorts(); - oldEnabledPorts = sw.getEnabledPorts(); - oldEnabledPortNumbers = sw.getEnabledPortNumbers(); - ports.clear(); - ports.add(p2b); - ports.add(p1b); - - PortChangeEvent evP2bModified = - new PortChangeEvent(p2b, PortChangeType.OTHER_UPDATE); - - // comparePorts - actualChanges = sw.comparePorts(ports); - assertEquals(oldPorts, sw.getPorts()); - assertEquals(oldEnabledPorts, sw.getEnabledPorts()); - assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers()); - assertEquals(1, actualChanges.size()); - assertTrue("No OTHER_CHANGE event for port2", - actualChanges.contains(evP2bModified)); - - // setPorts - actualChanges = sw.setPorts(ports); - assertEquals(1, actualChanges.size()); - assertTrue("No OTHER_CHANGE event for port2", - actualChanges.contains(evP2bModified)); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts = new ArrayList<ImmutablePort>(); - enabledPorts.add(p1b); - enabledPortNumbers = new ArrayList<Short>(); - enabledPortNumbers.add((short)1); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1b, sw.getPort((short)1)); - assertEquals(p1b, sw.getPort("port1")); - assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2b, sw.getPort((short)2)); - assertEquals(p2b, sw.getPort("port2")); - assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(null, sw.getPort((short)3)); - assertEquals(null, sw.getPort("port3")); - assertEquals(null, sw.getPort("PoRt3")); // case insensitive get - - - //---------------------------------------------------- - // Remove p1b, add p1a. Should receive a port DOWN - // Remove p2b, add p2a. Should receive a port modify - // Add p3, should receive an add - oldPorts = sw.getPorts(); - oldEnabledPorts = sw.getEnabledPorts(); - oldEnabledPortNumbers = sw.getEnabledPortNumbers(); - ports.clear(); - ports.add(p2a); - ports.add(p1a); - ports.add(p3); - - PortChangeEvent evP1aDown = - new PortChangeEvent(p1a, PortChangeType.DOWN); - PortChangeEvent evP2aModified = - new PortChangeEvent(p2a, PortChangeType.OTHER_UPDATE); - PortChangeEvent evP3Add = - new PortChangeEvent(p3, PortChangeType.ADD); - expectedChanges.clear(); - expectedChanges.add(evP1aDown); - expectedChanges.add(evP2aModified); - expectedChanges.add(evP3Add); - - // comparePorts - actualChanges = sw.comparePorts(ports); - assertEquals(oldPorts, sw.getPorts()); - assertEquals(oldEnabledPorts, sw.getEnabledPorts()); - assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers()); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - - // setPorts - actualChanges = sw.setPorts(ports); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPorts.add(p3); - enabledPortNumbers.clear(); - enabledPortNumbers.add((short)3); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(p3, sw.getPort((short)3)); - assertEquals(p3, sw.getPort("port3")); - assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get - - - //---------------------------------------------------- - // Remove p1b Should receive a port DELETE - // Remove p2b Should receive a port DELETE - oldPorts = sw.getPorts(); - oldEnabledPorts = sw.getEnabledPorts(); - oldEnabledPortNumbers = sw.getEnabledPortNumbers(); - ports.clear(); - ports.add(p3); - - PortChangeEvent evP1aDel = - new PortChangeEvent(p1a, PortChangeType.DELETE); - PortChangeEvent evP2aDel = - new PortChangeEvent(p2a, PortChangeType.DELETE); - expectedChanges.clear(); - expectedChanges.add(evP1aDel); - expectedChanges.add(evP2aDel); - - // comparePorts - actualChanges = sw.comparePorts(ports); - assertEquals(oldPorts, sw.getPorts()); - assertEquals(oldEnabledPorts, sw.getEnabledPorts()); - assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers()); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - - // setPorts - actualChanges = sw.setPorts(ports); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPorts.add(p3); - enabledPortNumbers.clear(); - enabledPortNumbers.add((short)3); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - - assertEquals(p3, sw.getPort((short)3)); - assertEquals(p3, sw.getPort("port3")); - assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get - } - - - /** - * Test "normal" OFPortStatus handling. No name<->number - * conflicts or exception testing. - */ - @Test - public void testBasicPortStatusOperation() { - OFPortStatus ps = (OFPortStatus) - BasicFactory.getInstance().getMessage(OFType.PORT_STATUS); - List<ImmutablePort> ports = new ArrayList<ImmutablePort>(); - ports.add(p1a); - ports.add(p2a); - - - // Set p1a and p2a as baseline - PortChangeEvent evP1aAdded = - new PortChangeEvent(p1a, PortChangeType.ADD); - PortChangeEvent evP2aAdded = - new PortChangeEvent(p2a, PortChangeType.ADD); - - Collection<PortChangeEvent> expectedChanges = - new ArrayList<IOFSwitch.PortChangeEvent>(); - expectedChanges.add(evP1aAdded); - expectedChanges.add(evP2aAdded); - - Collection<PortChangeEvent> actualChanges = sw.comparePorts(ports); - assertEquals(0, sw.getPorts().size()); - assertEquals(0, sw.getEnabledPorts().size()); - assertEquals(0, sw.getEnabledPortNumbers().size()); - assertEquals(2, actualChanges.size()); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - - actualChanges = sw.setPorts(ports); - assertEquals(2, actualChanges.size()); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - assertTrue("enabled ports should be empty", - sw.getEnabledPortNumbers().isEmpty()); - assertTrue("enabled ports should be empty", - sw.getEnabledPorts().isEmpty()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - //---------------------------------------------------- - // P1a -> p1b. Should receive a port up - ports.clear(); - ports.add(p2a); - ports.add(p1b); - - ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode()); - ps.setDesc(p1b.toOFPhysicalPort()); - - PortChangeEvent evP1bUp = new PortChangeEvent(p1b, PortChangeType.UP); - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - expectedChanges.add(evP1bUp); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - List<ImmutablePort> enabledPorts = new ArrayList<ImmutablePort>(); - enabledPorts.add(p1b); - List<Short> enabledPortNumbers = new ArrayList<Short>(); - enabledPortNumbers.add((short)1); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1b, sw.getPort((short)1)); - assertEquals(p1b, sw.getPort("port1")); - assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - //---------------------------------------------------- - // p2a -> p2b. Should receive a port modify - ports.clear(); - ports.add(p2b); - ports.add(p1b); - - PortChangeEvent evP2bModified = - new PortChangeEvent(p2b, PortChangeType.OTHER_UPDATE); - - ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode()); - ps.setDesc(p2b.toOFPhysicalPort()); - - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - expectedChanges.add(evP2bModified); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts = new ArrayList<ImmutablePort>(); - enabledPorts.add(p1b); - enabledPortNumbers = new ArrayList<Short>(); - enabledPortNumbers.add((short)1); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1b, sw.getPort((short)1)); - assertEquals(p1b, sw.getPort("port1")); - assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2b, sw.getPort((short)2)); - assertEquals(p2b, sw.getPort("port2")); - assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(null, sw.getPort((short)3)); - assertEquals(null, sw.getPort("port3")); - assertEquals(null, sw.getPort("PoRt3")); // case insensitive get - - - //---------------------------------------------------- - // p1b -> p1a. Via an OFPPR_ADD, Should receive a port DOWN - ports.clear(); - ports.add(p2b); - ports.add(p1a); - - // we use an ADD here. We treat ADD and MODIFY the same way - ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode()); - ps.setDesc(p1a.toOFPhysicalPort()); - - PortChangeEvent evP1aDown = - new PortChangeEvent(p1a, PortChangeType.DOWN); - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - expectedChanges.add(evP1aDown); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPortNumbers.clear(); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2b, sw.getPort((short)2)); - assertEquals(p2b, sw.getPort("port2")); - assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get - - - //---------------------------------------------------- - // p2b -> p2a. Via an OFPPR_ADD, Should receive a port MODIFY - ports.clear(); - ports.add(p2a); - ports.add(p1a); - - // we use an ADD here. We treat ADD and MODIFY the same way - ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode()); - ps.setDesc(p2a.toOFPhysicalPort()); - - PortChangeEvent evP2aModify = - new PortChangeEvent(p2a, PortChangeType.OTHER_UPDATE); - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - expectedChanges.add(evP2aModify); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPortNumbers.clear(); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(p2a, sw.getPort((short)2)); - assertEquals(p2a, sw.getPort("port2")); - assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get - - - //---------------------------------------------------- - // Remove p2a - ports.clear(); - ports.add(p1a); - - ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode()); - ps.setDesc(p2a.toOFPhysicalPort()); - - PortChangeEvent evP2aDel = - new PortChangeEvent(p2a, PortChangeType.DELETE); - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - expectedChanges.add(evP2aDel); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPortNumbers.clear(); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(null, sw.getPort((short)2)); - assertEquals(null, sw.getPort("port2")); - assertEquals(null, sw.getPort("PoRt2")); // case insensitive get - - //---------------------------------------------------- - // Remove p2a again. Nothing should happen. - ports.clear(); - ports.add(p1a); - - ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode()); - ps.setDesc(p2a.toOFPhysicalPort()); - - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPortNumbers.clear(); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1a, sw.getPort((short)1)); - assertEquals(p1a, sw.getPort("port1")); - assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(null, sw.getPort((short)2)); - assertEquals(null, sw.getPort("port2")); - assertEquals(null, sw.getPort("PoRt2")); // case insensitive get - - - //---------------------------------------------------- - // Remove p1a - ports.clear(); - - ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode()); - ps.setDesc(p1a.toOFPhysicalPort()); - - PortChangeEvent evP1aDel = - new PortChangeEvent(p1a, PortChangeType.DELETE); - actualChanges = sw.processOFPortStatus(ps); - expectedChanges.clear(); - expectedChanges.add(evP1aDel); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPortNumbers.clear(); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(null, sw.getPort((short)1)); - assertEquals(null, sw.getPort("port1")); - assertEquals(null, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(null, sw.getPort((short)2)); - assertEquals(null, sw.getPort("port2")); - assertEquals(null, sw.getPort("PoRt2")); // case insensitive get - - - //---------------------------------------------------- - // Add p3, should receive an add - ports.clear(); - ports.add(p3); - - PortChangeEvent evP3Add = - new PortChangeEvent(p3, PortChangeType.ADD); - expectedChanges.clear(); - expectedChanges.add(evP3Add); - - ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode()); - ps.setDesc(p3.toOFPhysicalPort()); - - actualChanges = sw.processOFPortStatus(ps); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPorts.add(p3); - enabledPortNumbers.clear(); - enabledPortNumbers.add((short)3); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(null, sw.getPort((short)1)); - assertEquals(null, sw.getPort("port1")); - assertEquals(null, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(null, sw.getPort((short)2)); - assertEquals(null, sw.getPort("port2")); - assertEquals(null, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(p3, sw.getPort((short)3)); - assertEquals(p3, sw.getPort("port3")); - assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get - - //---------------------------------------------------- - // Add p1b, back should receive an add - ports.clear(); - ports.add(p1b); - ports.add(p3); - - PortChangeEvent evP1bAdd = - new PortChangeEvent(p1b, PortChangeType.ADD); - expectedChanges.clear(); - expectedChanges.add(evP1bAdd); - - // use a modify to add the port - ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode()); - ps.setDesc(p1b.toOFPhysicalPort()); - - actualChanges = sw.processOFPortStatus(ps); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPorts.add(p3); - enabledPorts.add(p1b); - enabledPortNumbers.clear(); - enabledPortNumbers.add((short)3); - enabledPortNumbers.add((short)1); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1b, sw.getPort((short)1)); - assertEquals(p1b, sw.getPort("port1")); - assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(null, sw.getPort((short)2)); - assertEquals(null, sw.getPort("port2")); - assertEquals(null, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(p3, sw.getPort((short)3)); - assertEquals(p3, sw.getPort("port3")); - assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get - - //---------------------------------------------------- - // Modify, but nothing really changed - ports.clear(); - ports.add(p1b); - ports.add(p3); - - expectedChanges.clear(); - - // use a modify to add the port - ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode()); - ps.setDesc(p1b.toOFPhysicalPort()); - - actualChanges = sw.processOFPortStatus(ps); - assertCollectionEqualsNoOrder(expectedChanges, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - enabledPorts.clear(); - enabledPorts.add(p3); - enabledPorts.add(p1b); - enabledPortNumbers.clear(); - enabledPortNumbers.add((short)3); - enabledPortNumbers.add((short)1); - assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts()); - assertCollectionEqualsNoOrder(enabledPortNumbers, - sw.getEnabledPortNumbers()); - assertEquals(p1b, sw.getPort((short)1)); - assertEquals(p1b, sw.getPort("port1")); - assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get - - assertEquals(null, sw.getPort((short)2)); - assertEquals(null, sw.getPort("port2")); - assertEquals(null, sw.getPort("PoRt2")); // case insensitive get - - assertEquals(p3, sw.getPort((short)3)); - assertEquals(p3, sw.getPort("port3")); - assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get - } - - - /** - * Test exception handling for setPorts() and comparePorts() - */ - @Test - public void testSetPortExceptions() { - try { - sw.setPorts(null); - fail("Excpeted exception not thrown"); - } catch (NullPointerException e) { }; - - // two ports with same name - List<ImmutablePort> ports = new ArrayList<ImmutablePort>(); - ports.add(ImmutablePort.create("port1", (short)1)); - ports.add(ImmutablePort.create("port1", (short)2)); - try { - sw.setPorts(ports); - fail("Excpeted exception not thrown"); - } catch (IllegalArgumentException e) { }; - - // two ports with same number - ports.clear(); - ports.add(ImmutablePort.create("port1", (short)1)); - ports.add(ImmutablePort.create("port2", (short)1)); - try { - sw.setPorts(ports); - fail("Excpeted exception not thrown"); - } catch (IllegalArgumentException e) { }; - - // null port in list - ports.clear(); - ports.add(ImmutablePort.create("port1", (short)1)); - ports.add(null); - try { - sw.setPorts(ports); - fail("Excpeted exception not thrown"); - } catch (NullPointerException e) { }; - - // try getPort(null) - try { - sw.getPort(null); - fail("Excpeted exception not thrown"); - } catch (NullPointerException e) { }; - - //-------------------------- - // comparePorts() - try { - sw.comparePorts(null); - fail("Excpeted exception not thrown"); - } catch (NullPointerException e) { }; - - // two ports with same name - ports = new ArrayList<ImmutablePort>(); - ports.add(ImmutablePort.create("port1", (short)1)); - ports.add(ImmutablePort.create("port1", (short)2)); - try { - sw.comparePorts(ports); - fail("Excpeted exception not thrown"); - } catch (IllegalArgumentException e) { }; - - // two ports with same number - ports.clear(); - ports.add(ImmutablePort.create("port1", (short)1)); - ports.add(ImmutablePort.create("port2", (short)1)); - try { - sw.comparePorts(ports); - fail("Excpeted exception not thrown"); - } catch (IllegalArgumentException e) { }; - - // null port in list - ports.clear(); - ports.add(ImmutablePort.create("port1", (short)1)); - ports.add(null); - try { - sw.comparePorts(ports); - fail("Excpeted exception not thrown"); - } catch (NullPointerException e) { }; - - // try getPort(null) - try { - sw.getPort(null); - fail("Excpeted exception not thrown"); - } catch (NullPointerException e) { }; - - } - - @Test - public void testPortStatusExceptions() { - OFPortStatus ps = (OFPortStatus) - BasicFactory.getInstance().getMessage(OFType.PORT_STATUS); - - try { - sw.processOFPortStatus(null); - fail("Expected exception not thrown"); - } catch (NullPointerException e) { } - - // illegal reason code - ps.setReason((byte)0x42); - ps.setDesc(ImmutablePort.create("p1", (short)1).toOFPhysicalPort()); - try { - sw.processOFPortStatus(ps); - fail("Expected exception not thrown"); - } catch (IllegalArgumentException e) { } - - // null port - ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode()); - ps.setDesc(null); - try { - sw.processOFPortStatus(ps); - fail("Expected exception not thrown"); - } catch (NullPointerException e) { } - } - - /** - * Assert that the expected PortChangeEvents have been recevied, asserting - * the expected ordering. - * - * All events in earlyEvents have to appear in actualEvents before any - * event in lateEvent appears. Events in anytimeEvents can appear at any - * given time. earlyEvents, lateEvents, and anytimeEvents must be mutually - * exclusive (their intersection must be none) and their union must - * contain all elements from actualEvents - * @param earlyEvents - * @param lateEvents - * @param anytimeEvents - * @param actualEvents - */ - private static void assertChangeEvents(Collection<PortChangeEvent> earlyEvents, - Collection<PortChangeEvent> lateEvents, - Collection<PortChangeEvent> anytimeEvents, - Collection<PortChangeEvent> actualEvents) { - String inputDesc = String.format("earlyEvents=%s, lateEvents=%s, " + - "anytimeEvents=%s, actualEvents=%s", - earlyEvents, lateEvents, anytimeEvents, actualEvents); - // Make copies of expected lists, so we can modify them - Collection<PortChangeEvent> early = - new ArrayList<PortChangeEvent>(earlyEvents); - Collection<PortChangeEvent> late = - new ArrayList<PortChangeEvent>(lateEvents); - Collection<PortChangeEvent> any = - new ArrayList<PortChangeEvent>(anytimeEvents); - - // Sanity check: no overlap between early, late, and anytime events - for (PortChangeEvent ev: early) { - assertFalse("Test setup error. Early and late overlap", - late.contains(ev)); - assertFalse("Test setup error. Early and anytime overlap", - any.contains(ev)); - } - for (PortChangeEvent ev: late) { - assertFalse("Test setup error. Late and early overlap", - early.contains(ev)); - assertFalse("Test setup error. Late and any overlap", - any.contains(ev)); - } - for (PortChangeEvent ev: any) { - assertFalse("Test setup error. Anytime and early overlap", - early.contains(ev)); - assertFalse("Test setup error. Anytime and late overlap", - late.contains(ev)); - } - - for (PortChangeEvent a: actualEvents) { - if (early.remove(a)) { - continue; - } - if (any.remove(a)) { - continue; - } - if (late.remove(a)) { - if (!early.isEmpty()) { - fail(a + " is in late list, but haven't seen all required " + - "early events. " + inputDesc); - } else { - continue; - } - } - fail(a + " was not expected. " + inputDesc); - } - if (!early.isEmpty()) - fail("Elements left in early: " + early + ". " + inputDesc); - if (!late.isEmpty()) - fail("Elements left in late: " + late + ". " + inputDesc); - if (!any.isEmpty()) - fail("Elements left in any: " + any + ". " + inputDesc); - } - - /** - * Test setPort() with changing name / number mappings - * We don't test comparePorts() here. We assume setPorts() and - * comparePorts() use the same underlying implementation - */ - @Test - public void testSetPortNameNumberMappingChange() { - - List<ImmutablePort> ports = new ArrayList<ImmutablePort>(); - Collection<PortChangeEvent> early = new ArrayList<PortChangeEvent>(); - Collection<PortChangeEvent> late = new ArrayList<PortChangeEvent>(); - Collection<PortChangeEvent> anytime = new ArrayList<PortChangeEvent>(); - Collection<PortChangeEvent> actualChanges = null; - - ports.add(portFoo1); - ports.add(p1a); - sw.setPorts(ports); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Add portFoo2: name collision - ports.clear(); - ports.add(portFoo2); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.setPorts(ports); - early.add(portFoo1Del); - late.add(portFoo2Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Add portBar2: number collision - ports.clear(); - ports.add(portBar2); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.setPorts(ports); - early.add(portFoo2Del); - late.add(portBar2Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Set to portFoo1, portBar2. No collisions in this step - ports.clear(); - ports.add(portFoo1); - ports.add(portBar2); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.setPorts(ports); - anytime.add(portFoo1Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Add portFoo2: name and number collision - ports.clear(); - ports.add(portFoo2); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.setPorts(ports); - early.add(portFoo1Del); - early.add(portBar2Del); - late.add(portFoo2Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Set to portFoo2, portBar1. No collisions in this step - ports.clear(); - ports.add(portFoo2); - ports.add(portBar1); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.setPorts(ports); - anytime.add(portBar1Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Add portFoo1, portBar2 name and number collision - // Also change p1a -> p1b: expect modify for it - // Also add p3: expect add for it - PortChangeEvent p1bUp = new PortChangeEvent(p1b, PortChangeType.UP); - PortChangeEvent p3Add = new PortChangeEvent(p3, PortChangeType.ADD); - ports.clear(); - ports.add(portFoo1); - ports.add(portBar2); - ports.add(p1b); - ports.add(p3); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.setPorts(ports); - early.add(portFoo2Del); - early.add(portBar1Del); - late.add(portFoo1Add); - late.add(portBar2Add); - anytime.add(p1bUp); - anytime.add(p3Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - } - - - @Test - public void testPortStatusNameNumberMappingChange() { - List<ImmutablePort> ports = new ArrayList<ImmutablePort>(); - Collection<PortChangeEvent> early = new ArrayList<PortChangeEvent>(); - Collection<PortChangeEvent> late = new ArrayList<PortChangeEvent>(); - Collection<PortChangeEvent> anytime = new ArrayList<PortChangeEvent>(); - Collection<PortChangeEvent> actualChanges = null; - - // init: add portFoo1, p1a - ports.add(portFoo1); - ports.add(p1a); - sw.setPorts(ports); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - OFPortStatus ps = (OFPortStatus) - BasicFactory.getInstance().getMessage(OFType.PORT_STATUS); - - // portFoo1 -> portFoo2 via MODIFY : name collision - ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode()); - ps.setDesc(portFoo2.toOFPhysicalPort()); - ports.clear(); - ports.add(portFoo2); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.processOFPortStatus(ps); - early.add(portFoo1Del); - late.add(portFoo2Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // portFoo2 -> portBar2 via ADD number collision - ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode()); - ps.setDesc(portBar2.toOFPhysicalPort()); - ports.clear(); - ports.add(portBar2); - ports.add(p1a); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.processOFPortStatus(ps); - early.add(portFoo2Del); - late.add(portBar2Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Set to portFoo1, portBar2 - ports.clear(); - ports.add(portFoo1); - ports.add(portBar2); - sw.setPorts(ports); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // portFoo1 + portBar2 -> portFoo2: name and number collision - ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode()); - ps.setDesc(portFoo2.toOFPhysicalPort()); - ports.clear(); - ports.add(portFoo2); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.processOFPortStatus(ps); - early.add(portFoo1Del); - early.add(portBar2Del); - late.add(portFoo2Add); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - //---------------------- - // Test DELETEs - - // del portFoo1: name exists (portFoo2), but number doesn't. - ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode()); - ps.setDesc(portFoo1.toOFPhysicalPort()); - ports.clear(); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.processOFPortStatus(ps); - anytime.add(portFoo2Del); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // Set to portFoo1 - ports.clear(); - ports.add(portFoo1); - sw.setPorts(ports); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // del portBar1: number exists (portFoo1), but name doesn't. - ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode()); - ps.setDesc(portBar1.toOFPhysicalPort()); - ports.clear(); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.processOFPortStatus(ps); - anytime.add(portFoo1Del); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - - // Set to portFoo1, portBar2 - ports.clear(); - ports.add(portFoo1); - ports.add(portBar2); - sw.setPorts(ports); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - - // del portFoo2: name and number exists - ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode()); - ps.setDesc(portFoo2.toOFPhysicalPort()); - ports.clear(); - early.clear(); - late.clear(); - anytime.clear(); - actualChanges = sw.processOFPortStatus(ps); - anytime.add(portFoo1Del); - anytime.add(portBar2Del); - assertChangeEvents(early, late, anytime, actualChanges); - assertCollectionEqualsNoOrder(ports, sw.getPorts()); - } - - @Test - public void testSubHandshake() { - OFMessage m = BasicFactory.getInstance().getMessage(OFType.VENDOR); - // test execptions before handshake is started - try { - sw.processDriverHandshakeMessage(m); - fail("expected exception not thrown"); - } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ } - try { - sw.isDriverHandshakeComplete(); - fail("expected exception not thrown"); - } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ } - - // start the handshake -- it should immediately complete - sw.startDriverHandshake(); - assertTrue("Handshake should be complete", - sw.isDriverHandshakeComplete()); - - // test exceptions after handshake is completed - try { - sw.processDriverHandshakeMessage(m); - fail("expected exception not thrown"); - } catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ } - try { - sw.startDriverHandshake(); - fail("Expected exception not thrown"); - } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ } - } - -} diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java deleted file mode 100644 index e59a9d060899e856b6564d48cbf8527c90316a8c..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.internal; - -import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted; -import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted; -import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; - -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFType; -import org.openflow.protocol.factory.BasicFactory; - -import static org.junit.Assert.*; - -public class OFSwitchImplTest { - protected OFSwitchImpl sw; - - - @Before - public void setUp() throws Exception { - sw = new OFSwitchImpl(); - } - - @Test - public void testSetHARoleReply() { - - sw.setHARole(Role.MASTER); - assertEquals(Role.MASTER, sw.getHARole()); - - sw.setHARole(Role.EQUAL); - assertEquals(Role.EQUAL, sw.getHARole()); - - sw.setHARole(Role.SLAVE); - assertEquals(Role.SLAVE, sw.getHARole()); - } - - @Test - public void testSubHandshake() { - OFMessage m = BasicFactory.getInstance().getMessage(OFType.VENDOR); - // test execptions before handshake is started - try { - sw.processDriverHandshakeMessage(m); - fail("expected exception not thrown"); - } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ } - try { - sw.isDriverHandshakeComplete(); - fail("expected exception not thrown"); - } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ } - - // start the handshake -- it should immediately complete - sw.startDriverHandshake(); - assertTrue("Handshake should be complete", - sw.isDriverHandshakeComplete()); - - // test exceptions after handshake is completed - try { - sw.processDriverHandshakeMessage(m); - fail("expected exception not thrown"); - } catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ } - try { - sw.startDriverHandshake(); - fail("Expected exception not thrown"); - } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ } - } -} diff --git a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java b/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java deleted file mode 100644 index b40715a66ea3e418b534cc8f5d91eff70d68d7b5..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.module; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; - -import org.sdnplatform.sync.test.MockSyncService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.module.FloodlightModuleLoader; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.test.MockFloodlightProvider; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.counter.NullCounterStore; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.devicemanager.test.MockDeviceManager; -import net.floodlightcontroller.perfmon.NullPktInProcessingTime; -import net.floodlightcontroller.storage.memory.MemoryStorageSource; -import net.floodlightcontroller.topology.TopologyManager; - -public class FloodlightTestModuleLoader extends FloodlightModuleLoader { - protected static Logger log = LoggerFactory.getLogger(FloodlightTestModuleLoader.class); - - // List of default modules to use unless specified otherwise - public static final Class<? extends IFloodlightModule> DEFAULT_STORAGE_SOURCE = - MemoryStorageSource.class; - public static final Class<? extends IFloodlightModule> DEFAULT_FLOODLIGHT_PRPOVIDER = - MockFloodlightProvider.class; - public static final Class<? extends IFloodlightModule> DEFAULT_TOPOLOGY_PROVIDER = - TopologyManager.class; - public static final Class<? extends IFloodlightModule> DEFAULT_DEVICE_SERVICE = - MockDeviceManager.class; - public static final Class<? extends IFloodlightModule> DEFAULT_COUNTER_STORE = - NullCounterStore.class; - public static final Class<? extends IFloodlightModule> DEFAULT_THREADPOOL = - MockThreadPoolService.class; - public static final Class<? extends IFloodlightModule> DEFAULT_ENTITY_CLASSIFIER = - DefaultEntityClassifier.class; - public static final Class<? extends IFloodlightModule> DEFAULT_PERFMON = - NullPktInProcessingTime.class; - public static final Class<? extends IFloodlightModule> DEFAULT_SYNC_SERVICE = - MockSyncService.class; - - protected static final Collection<Class<? extends IFloodlightModule>> DEFAULT_MODULE_LIST; - - static { - DEFAULT_MODULE_LIST = new ArrayList<Class<? extends IFloodlightModule>>(); - DEFAULT_MODULE_LIST.add(DEFAULT_DEVICE_SERVICE); - DEFAULT_MODULE_LIST.add(DEFAULT_FLOODLIGHT_PRPOVIDER); - DEFAULT_MODULE_LIST.add(DEFAULT_STORAGE_SOURCE); - DEFAULT_MODULE_LIST.add(DEFAULT_TOPOLOGY_PROVIDER); - DEFAULT_MODULE_LIST.add(DEFAULT_COUNTER_STORE); - DEFAULT_MODULE_LIST.add(DEFAULT_THREADPOOL); - DEFAULT_MODULE_LIST.add(DEFAULT_ENTITY_CLASSIFIER); - DEFAULT_MODULE_LIST.add(DEFAULT_PERFMON); - DEFAULT_MODULE_LIST.add(DEFAULT_SYNC_SERVICE); - } - - protected IFloodlightModuleContext fmc; - - /** - * Adds default modules to the list of modules to load. This is done - * in order to avoid the module loader throwing errors about duplicate - * modules and neither one is specified by the user. - * @param userModules The list of user specified modules to add to. - */ - protected void addDefaultModules(Collection<Class<? extends IFloodlightModule>> userModules) { - Collection<Class<? extends IFloodlightModule>> defaultModules = - new ArrayList<Class<? extends IFloodlightModule>>(DEFAULT_MODULE_LIST.size()); - defaultModules.addAll(DEFAULT_MODULE_LIST); - - Iterator<Class<? extends IFloodlightModule>> modIter = userModules.iterator(); - while (modIter.hasNext()) { - Class<? extends IFloodlightModule> userMod = modIter.next(); - Iterator<Class<? extends IFloodlightModule>> dmIter = defaultModules.iterator(); - while (dmIter.hasNext()) { - Class<? extends IFloodlightModule> dmMod = dmIter.next(); - Collection<Class<? extends IFloodlightService>> userModServs; - Collection<Class<? extends IFloodlightService>> dmModServs; - try { - dmModServs = dmMod.newInstance().getModuleServices(); - userModServs = userMod.newInstance().getModuleServices(); - } catch (InstantiationException e) { - log.error(e.getMessage()); - break; - } catch (IllegalAccessException e) { - log.error(e.getMessage()); - break; - } - - // If either of these are null continue as they have no services - if (dmModServs == null || userModServs == null) continue; - - // If the user supplied modules has a service - // that is in the default module list we remove - // the default module from the list. - boolean shouldBreak = false; - Iterator<Class<? extends IFloodlightService>> userModServsIter - = userModServs.iterator(); - while (userModServsIter.hasNext()) { - Class<? extends IFloodlightService> userModServIntf = userModServsIter.next(); - Iterator<Class<? extends IFloodlightService>> dmModsServsIter - = dmModServs.iterator(); - while (dmModsServsIter.hasNext()) { - Class<? extends IFloodlightService> dmModServIntf - = dmModsServsIter.next(); - - if (dmModServIntf.getCanonicalName().equals( - userModServIntf.getCanonicalName())) { - logger.debug("Removing default module {} because it was " + - "overriden by an explicitly specified module", - dmModServIntf.getCanonicalName()); - dmIter.remove(); - shouldBreak = true; - break; - } - } - if (shouldBreak) break; - } - if (shouldBreak) break; - } - } - - // Append the remaining default modules to the user specified ones. - // This avoids the module loader throwing duplicate module errors. - userModules.addAll(defaultModules); - log.debug("Using module set " + userModules.toString()); - } - - /** - * Sets up all modules and their dependencies. - * @param modules The list of modules that the user wants to load. - * @param mockedServices The list of services that will be mocked. Any - * module that provides this service will not be loaded. - */ - public void setupModules(Collection<Class<? extends IFloodlightModule>> modules, - Collection<IFloodlightService> mockedServices) throws FloodlightModuleException { - addDefaultModules(modules); - Collection<String> modulesAsString = new ArrayList<String>(); - for (Class<? extends IFloodlightModule> m : modules) { - modulesAsString.add(m.getCanonicalName()); - } - - fmc = loadModulesFromList(modulesAsString, null, mockedServices); - } - - /** - * Gets the inited/started instance of a module from the context. - * @param ifl The name if the module to get, i.e. "LearningSwitch.class". - * @return The inited/started instance of the module. - */ - public IFloodlightModule getModuleByName(Class<? extends IFloodlightModule> ifl) { - Collection<IFloodlightModule> modules = fmc.getAllModules(); - for (IFloodlightModule m : modules) { - if (ifl.getCanonicalName().equals(m.getClass().getCanonicalName())) { - return m; - } - } - return null; - } - - /** - * Gets an inited/started instance of a service from the context. - * @param ifs The name of the service to get, i.e. "ITopologyService.class". - * @return The inited/started instance of the service from teh context. - */ - public IFloodlightService getModuleByService(Class<? extends IFloodlightService> ifs) { - Collection<IFloodlightModule> modules = fmc.getAllModules(); - for (IFloodlightModule m : modules) { - Collection<Class<? extends IFloodlightService>> mServs = m.getModuleServices(); - if (mServs == null) continue; - for (Class<? extends IFloodlightService> mServClass : mServs) { - if (mServClass.getCanonicalName().equals(ifs.getCanonicalName())) { - assert(m instanceof IFloodlightService); - return (IFloodlightService)m; - } - } - } - return null; - } -} diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java index 92e082b740c276bee6de2e19c3288783a76e387d..f5f89350abb048234cd368bc773f45187ff98f05 100644 --- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java +++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java @@ -17,45 +17,51 @@ package net.floodlightcontroller.core.test; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; +import static org.junit.Assert.fail; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Set; -import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.jboss.netty.util.Timer; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.HAListenerTypeMarker; +import net.floodlightcontroller.core.HARole; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IHAListener; import net.floodlightcontroller.core.IInfoProvider; +import net.floodlightcontroller.core.IListener.Command; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IOFSwitchDriver; -import net.floodlightcontroller.core.IOFSwitchListener; -import net.floodlightcontroller.core.IListener.Command; -import net.floodlightcontroller.core.IReadyForReconcileListener; import net.floodlightcontroller.core.RoleInfo; +import net.floodlightcontroller.core.internal.Controller.IUpdate; +import net.floodlightcontroller.core.internal.Controller.ModuleLoaderState; +import net.floodlightcontroller.core.internal.RoleManager; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.ListenerDispatcher; + +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFPacketIn; +import org.projectfloodlight.openflow.protocol.OFType; + import net.floodlightcontroller.packet.Ethernet; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFType; -import org.openflow.protocol.factory.BasicFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,26 +70,31 @@ import org.slf4j.LoggerFactory; * @author David Erickson (daviderickson@cs.stanford.edu) */ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightProviderService { - protected static Logger log = LoggerFactory.getLogger(MockFloodlightProvider.class); + private final static Logger log = LoggerFactory.getLogger(MockFloodlightProvider.class); protected ConcurrentMap<OFType, ListenerDispatcher<OFType,IOFMessageListener>> listeners; - protected List<IOFSwitchListener> switchListeners; protected ListenerDispatcher<HAListenerTypeMarker, IHAListener> haListeners; - protected Map<Long, IOFSwitch> switches; - protected BasicFactory factory; - private Role role; + private HARole role; + private final String openFlowHostname = "127.0.0.1"; + private final int openFlowPort = 6653; + private final boolean useAsyncUpdates; + private volatile ExecutorService executorService; + private volatile Future<?> mostRecentUpdateFuture; /** * */ - public MockFloodlightProvider() { + public MockFloodlightProvider(boolean useAsyncUpdates) { listeners = new ConcurrentHashMap<OFType, ListenerDispatcher<OFType, IOFMessageListener>>(); - switches = new ConcurrentHashMap<Long, IOFSwitch>(); - switchListeners = new CopyOnWriteArrayList<IOFSwitchListener>(); haListeners = new ListenerDispatcher<HAListenerTypeMarker, IHAListener>(); - factory = BasicFactory.getInstance(); + role = null; + this.useAsyncUpdates = useAsyncUpdates; + } + + public MockFloodlightProvider() { + this(false); } @Override @@ -115,48 +126,17 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro public Map<OFType, List<IOFMessageListener>> getListeners() { Map<OFType, List<IOFMessageListener>> lers = new HashMap<OFType, List<IOFMessageListener>>(); - for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e : - listeners.entrySet()) { - lers.put(e.getKey(), e.getValue().getOrderedListeners()); - } - return Collections.unmodifiableMap(lers); + for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e : + listeners.entrySet()) { + lers.put(e.getKey(), e.getValue().getOrderedListeners()); + } + return Collections.unmodifiableMap(lers); } public void clearListeners() { this.listeners.clear(); } - @Override - public Map<Long,IOFSwitch> getAllSwitchMap() { - return Collections.unmodifiableMap(this.switches); - } - - @Override - public Set<Long> getAllSwitchDpids() { - // the contract for getAllSwitchDpids says the caller will own the - // returned set - return new HashSet<Long>(this.switches.keySet()); - } - - @Override - public IOFSwitch getSwitch(long dpid) { - return this.switches.get(dpid); - } - - public void setSwitches(Map<Long, IOFSwitch> switches) { - this.switches = switches; - } - - @Override - public void addOFSwitchListener(IOFSwitchListener listener) { - switchListeners.add(listener); - } - - @Override - public void removeOFSwitchListener(IOFSwitchListener listener) { - switchListeners.remove(listener); - } - public void dispatchMessage(IOFSwitch sw, OFMessage msg) { dispatchMessage(sw, msg, new FloodlightContext()); } @@ -169,7 +149,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro if (OFType.PACKET_IN.equals(msg.getType())) { OFPacketIn pi = (OFPacketIn)msg; Ethernet eth = new Ethernet(); - eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); + eth.deserialize(pi.getData(), 0, pi.getData().length); IFloodlightProviderService.bcStore.put(bc, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, eth); @@ -181,7 +161,8 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } @Override - public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc) { + public void handleOutgoingMessage(IOFSwitch sw, OFMessage m) { + FloodlightContext bc = new FloodlightContext(); List<IOFMessageListener> msgListeners = null; if (listeners.containsKey(m.getType())) { msgListeners = listeners.get(m.getType()).getOrderedListeners(); @@ -198,42 +179,23 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro public void handleOutgoingMessages(IOFSwitch sw, List<OFMessage> msglist, FloodlightContext bc) { for (OFMessage m:msglist) { - handleOutgoingMessage(sw, m, bc); + handleOutgoingMessage(sw, m); } } - /** - * @return the switchListeners - */ - public List<IOFSwitchListener> getSwitchListeners() { - return switchListeners; - } - - @Override - public void terminate() { - } - - @Override - public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) { - dispatchMessage(sw, msg); - return true; - } - - @Override - public boolean injectOfMessage(IOFSwitch sw, OFMessage msg, - FloodlightContext bContext) { - dispatchMessage(sw, msg, bContext); - return true; - } - - @Override - public BasicFactory getOFMessageFactory() { - return factory; - } - @Override public void run() { logListeners(); + if (useAsyncUpdates) + executorService = Executors.newSingleThreadExecutor(); + } + + public void shutdown() { + if (executorService != null) { + executorService.shutdownNow(); + executorService = null; + mostRecentUpdateFuture = null; + } } @Override @@ -262,34 +224,62 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - // TODO Auto-generated method stub - + public void init(FloodlightModuleContext context) throws FloodlightModuleException { + // do nothing. } @Override public void startUp(FloodlightModuleContext context) { - // TODO Auto-generated method stub - + // do nothing. } @Override public void addInfoProvider(String type, IInfoProvider provider) { - // TODO Auto-generated method stub - + // do nothing. } @Override public void removeInfoProvider(String type, IInfoProvider provider) { - // TODO Auto-generated method stub - + // do nothing. } @Override public Map<String, Object> getControllerInfo(String type) { - // TODO Auto-generated method stub - return null; + // mock up something + Map<String, Object> summary = new HashMap<String, Object>(); + summary.put("test-summary-1", 2); + summary.put("test-summary-2", 5); + return summary; + } + + @Override + public void addUpdateToQueue(final IUpdate update) { + if (useAsyncUpdates) { + mostRecentUpdateFuture = executorService.submit(new Runnable() { + @Override + public void run() { + update.dispatch(); + } + }); + } else { + update.dispatch(); + } + } + + public void waitForUpdates(long timeout, TimeUnit unit) throws InterruptedException { + + long timeoutNanos = unit.toNanos(timeout); + long start = System.nanoTime(); + for (;;) { + Future<?> future = mostRecentUpdateFuture; + if ((future == null) || future.isDone()) + break; + Thread.sleep(100); + long now = System.nanoTime(); + if (now > start + timeoutNanos) { + fail("Timeout waiting for update tasks to complete"); + } + } } @Override @@ -303,7 +293,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } @Override - public Role getRole() { + public HARole getRole() { /* DISABLE THIS CHECK FOR NOW. OTHER UNIT TESTS NEED TO BE UPDATED * FIRST if (this.role == null) @@ -315,7 +305,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } @Override - public void setRole(Role role, String roleChangeDescription) { + public void setRole(HARole role, String roleChangeDescription) { this.role = role; } @@ -324,22 +314,25 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro * @param oldRole * @param newRole */ - public void transitionToMaster() { - for (IHAListener rl : haListeners.getOrderedListeners()) { - rl.transitionToMaster(); - } + public void transitionToActive() { + IUpdate update = new IUpdate() { + @Override + public void dispatch() { + for (IHAListener rl : haListeners.getOrderedListeners()) { + rl.transitionToActive(); + } + } + }; + addUpdateToQueue(update); } - @Override public Map<String, String> getControllerNodeIPs() { - // TODO Auto-generated method stub return null; } @Override public long getSystemStartTime() { - // TODO Auto-generated method stub return 0; } @@ -366,51 +359,67 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } @Override - public void setAlwaysClearFlowsOnSwActivate(boolean value) { + public RoleInfo getRoleInfo() { // TODO Auto-generated method stub + return null; + } + + @Override + public Map<String, Long> getMemory() { + Map<String, Long> m = new HashMap<String, Long>(); + m.put("total", 1000000000L); + m.put("free", 20000000L); + return m; + } + @Override + public Long getUptime() { + return 1000000L; } @Override - public void addOFSwitchDriver(String desc, IOFSwitchDriver driver) { - // TODO Auto-generated method stub + public String getOFHostname() { + return openFlowHostname; + } + @Override + public int getOFPort() { + return openFlowPort; } @Override - public RoleInfo getRoleInfo() { - // TODO Auto-generated method stub - return null; + public void handleMessage(IOFSwitch sw, OFMessage m, + FloodlightContext bContext) { + // do nothing } @Override - public Map<String, Long> getMemory() { - Map<String, Long> m = new HashMap<String, Long>(); - Runtime runtime = Runtime.getRuntime(); - m.put("total", runtime.totalMemory()); - m.put("free", runtime.freeMemory()); - return m; + public Timer getTimer() { + return null; } @Override - public Long getUptime() { - RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); - return rb.getUptime(); + public RoleManager getRoleManager() { + return null; } @Override - public void addReadyForReconcileListener(IReadyForReconcileListener l) { - // do nothing. + public ModuleLoaderState getModuleLoaderState() { + return null; } @Override - public void addSwitchEvent(long switchDPID, String reason, boolean flushNow) { - // TODO Auto-generated method stub + public String getControllerId() { + return null; } @Override public Set<String> getUplinkPortPrefixSet() { - // TODO Auto-generated method stub return null; } + + @Override + public int getWorkerThreads() { + return 0; + } } diff --git a/src/test/java/net/floodlightcontroller/core/test/MockScheduledExecutor.java b/src/test/java/net/floodlightcontroller/core/test/MockScheduledExecutor.java deleted file mode 100644 index 733ff1ab93bf4038724a746fbed06d549896f106..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/test/MockScheduledExecutor.java +++ /dev/null @@ -1,252 +0,0 @@ -/** -* 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.core.test; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -public class MockScheduledExecutor implements ScheduledExecutorService { - ScheduledExecutorService ses = null; - - public static class MockFuture<T> implements Future<T>,ScheduledFuture<T>{ - T result; - ExecutionException e; - - /** - * @param result - */ - public MockFuture(T result) { - super(); - this.result = result; - } - - /** - * @param result - */ - public MockFuture(ExecutionException e) { - super(); - this.e = e; - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - @Override - public T get() throws InterruptedException, ExecutionException { - if (e != null) throw e; - return result; - } - - @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, - ExecutionException, TimeoutException { - if (e != null) throw e; - return result; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return true; - } - - @Override - public long getDelay(TimeUnit arg0) { - return 0; - } - - @Override - public int compareTo(Delayed arg0) { - return 0; - } - } - - @Override - public boolean awaitTermination(long arg0, TimeUnit arg1) - throws InterruptedException { - return false; - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> arg0) - throws InterruptedException { - List<Future<T>> rlist = new ArrayList<Future<T>>(); - for (Callable<T> arg : arg0) { - try { - rlist.add(new MockFuture<T>(arg.call())); - } catch (Exception e) { - rlist.add(new MockFuture<T>(new ExecutionException(e))); - } - } - return rlist; - } - - @Override - public <T> List<Future<T>> invokeAll( - Collection<? extends Callable<T>> arg0, long arg1, TimeUnit arg2) - throws InterruptedException { - return this.invokeAll(arg0); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> arg0) - throws InterruptedException, ExecutionException { - for (Callable<T> arg : arg0) { - try { - return arg.call(); - } catch (Exception e) { - - } - } - throw new ExecutionException(new Exception("no task completed successfully")); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> arg0, long arg1, - TimeUnit arg2) throws InterruptedException, ExecutionException, - TimeoutException { - return invokeAny(arg0); - } - - @Override - public boolean isShutdown() { - if (ses != null) - return ses.isShutdown(); - - return false; - } - - @Override - public boolean isTerminated() { - if (ses != null) - return ses.isTerminated(); - - return false; - } - - @Override - public void shutdown() { - if (ses != null) - ses.shutdown(); - } - - @Override - public List<Runnable> shutdownNow() { - if (ses != null) - return ses.shutdownNow(); - return null; - } - - @Override - public <T> Future<T> submit(Callable<T> arg0) { - try { - return new MockFuture<T>(arg0.call()); - } catch (Exception e) { - return new MockFuture<T>(new ExecutionException(e)); - } - } - - @Override - public Future<?> submit(Runnable arg0) { - try { - arg0.run(); - return new MockFuture<Object>(null); - } catch (Exception e) { - return new MockFuture<Object>(new ExecutionException(e)); - } - } - - @Override - public <T> Future<T> submit(Runnable arg0, T arg1) { - try { - arg0.run(); - return new MockFuture<T>((T)null); - } catch (Exception e) { - return new MockFuture<T>(new ExecutionException(e)); - } - } - - @Override - public void execute(Runnable arg0) { - arg0.run(); - } - - @Override - public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { - if (ses == null) - ses = Executors.newScheduledThreadPool(1); - try { - return ses.schedule(command, delay, unit); - } catch (Exception e) { - return new MockFuture<Object>(new ExecutionException(e)); - } - } - - @Override - public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, - TimeUnit unit) { - if (ses == null) - ses = Executors.newScheduledThreadPool(1); - try { - return ses.schedule(callable, delay, unit); - } catch (Exception e) { - return new MockFuture<V>(new ExecutionException(e)); - } - } - - @Override - public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, - long period, TimeUnit unit) { - if (ses == null) - ses = Executors.newScheduledThreadPool(1); - try { - return ses.scheduleAtFixedRate(command, initialDelay, period, unit); - } catch (Exception e) { - return new MockFuture<Object>(new ExecutionException(e)); - } - } - - @Override - public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, - long delay, TimeUnit unit) { - if (ses == null) - ses = Executors.newScheduledThreadPool(1); - try { - return ses.scheduleWithFixedDelay(command, initialDelay, delay, unit); - } catch (Exception e) { - return new MockFuture<Object>(new ExecutionException(e)); - } - } - -} diff --git a/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java b/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java deleted file mode 100644 index 2e59ba4c8f7706db536a985caa3577b7e7ab6908..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.test; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.module.IFloodlightService; -import net.floodlightcontroller.threadpool.IThreadPoolService; - -public class MockThreadPoolService implements IFloodlightModule, IThreadPoolService { - - protected ScheduledExecutorService mockExecutor = new MockScheduledExecutor(); - - /** - * Return a mock executor that will simply execute each task - * synchronously once. - */ - @Override - public ScheduledExecutorService getScheduledExecutor() { - return mockExecutor; - } - - // IFloodlightModule - - @Override - public Collection<Class<? extends IFloodlightService>> getModuleServices() { - Collection<Class<? extends IFloodlightService>> l = - new ArrayList<Class<? extends IFloodlightService>>(); - l.add(IThreadPoolService.class); - return l; - } - - @Override - public Map<Class<? extends IFloodlightService>, IFloodlightService> - getServiceImpls() { - Map<Class<? extends IFloodlightService>, - IFloodlightService> m = - new HashMap<Class<? extends IFloodlightService>, - IFloodlightService>(); - m.put(IThreadPoolService.class, this); - // We are the class that implements the service - return m; - } - - @Override - public Collection<Class<? extends IFloodlightService>> - getModuleDependencies() { - // No dependencies - return null; - } - - @Override - public void init(FloodlightModuleContext context) - throws FloodlightModuleException { - } - - @Override - public void startUp(FloodlightModuleContext context) { - // no-op - } - -} diff --git a/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java b/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java deleted file mode 100644 index 07f8c3dd5295233dde8e5405816df12cc17bc031..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.test; - -import java.util.ArrayList; -import java.util.List; - -import net.floodlightcontroller.packet.DHCP; -import net.floodlightcontroller.packet.DHCPOption; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.util.MACAddress; - -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFType; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.factory.BasicFactory; - -/** - * A class to that creates many types of L2/L3/L4 or OpenFlow packets. - * This is used in testing. - * @author alexreimers - * - */ -public class PacketFactory { - public static String broadcastMac = "ff:ff:ff:ff:ff:ff"; - public static String broadcastIp = "255.255.255.255"; - protected static BasicFactory OFMessageFactory = BasicFactory.getInstance(); - - /** - * Generates a DHCP request OFPacketIn. - * @param hostMac The host MAC address of for the request. - * @return An OFPacketIn that contains a DHCP request packet. - */ - public static OFPacketIn DhcpDiscoveryRequestOFPacketIn(MACAddress hostMac) { - byte[] serializedPacket = DhcpDiscoveryRequestEthernet(hostMac).serialize(); - return (((OFPacketIn)OFMessageFactory - .getMessage(OFType.PACKET_IN)) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setInPort((short) 1) - .setPacketData(serializedPacket) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short)serializedPacket.length)); - } - - /** - * Generates a DHCP request Ethernet frame. - * @param hostMac The host MAC address of for the request. - * @returnAn An Ethernet frame that contains a DHCP request packet. - */ - public static Ethernet DhcpDiscoveryRequestEthernet(MACAddress hostMac) { - List<DHCPOption> optionList = new ArrayList<DHCPOption>(); - - byte[] requestValue = new byte[4]; - requestValue[0] = requestValue[1] = requestValue[2] = requestValue[3] = 0; - DHCPOption requestOption = - new DHCPOption() - .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP. - getValue()) - .setLength((byte)4) - .setData(requestValue); - - byte[] msgTypeValue = new byte[1]; - msgTypeValue[0] = 1; // DHCP request - DHCPOption msgTypeOption = - new DHCPOption() - .setCode(DHCP.DHCPOptionCode.OptionCode_MessageType. - getValue()) - .setLength((byte)1) - .setData(msgTypeValue); - - byte[] reqParamValue = new byte[4]; - reqParamValue[0] = 1; // subnet mask - reqParamValue[1] = 3; // Router - reqParamValue[2] = 6; // Domain Name Server - reqParamValue[3] = 42; // NTP Server - DHCPOption reqParamOption = - new DHCPOption() - .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedParameters. - getValue()) - .setLength((byte)4) - .setData(reqParamValue); - - byte[] clientIdValue = new byte[7]; - clientIdValue[0] = 1; // Ethernet - System.arraycopy(hostMac.toBytes(), 0, - clientIdValue, 1, 6); - DHCPOption clientIdOption = - new DHCPOption() - .setCode(DHCP.DHCPOptionCode.OptionCode_ClientID. - getValue()) - .setLength((byte)7) - .setData(clientIdValue); - - DHCPOption endOption = - new DHCPOption() - .setCode(DHCP.DHCPOptionCode.OptionCode_END. - getValue()) - .setLength((byte)0) - .setData(null); - - optionList.add(requestOption); - optionList.add(msgTypeOption); - optionList.add(reqParamOption); - optionList.add(clientIdOption); - optionList.add(endOption); - - Ethernet requestPacket = new Ethernet(); - requestPacket.setSourceMACAddress(hostMac.toBytes()) - .setDestinationMACAddress(broadcastMac) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setVersion((byte)4) - .setDiffServ((byte)0) - .setIdentification((short)100) - .setFlags((byte)0) - .setFragmentOffset((short)0) - .setTtl((byte)250) - .setProtocol(IPv4.PROTOCOL_UDP) - .setChecksum((short)0) - .setSourceAddress(0) - .setDestinationAddress(broadcastIp) - .setPayload( - new UDP() - .setSourcePort(UDP.DHCP_CLIENT_PORT) - .setDestinationPort(UDP.DHCP_SERVER_PORT) - .setChecksum((short)0) - .setPayload( - new DHCP() - .setOpCode(DHCP.OPCODE_REQUEST) - .setHardwareType(DHCP.HWTYPE_ETHERNET) - .setHardwareAddressLength((byte)6) - .setHops((byte)0) - .setTransactionId(0x00003d1d) - .setSeconds((short)0) - .setFlags((short)0) - .setClientIPAddress(0) - .setYourIPAddress(0) - .setServerIPAddress(0) - .setGatewayIPAddress(0) - .setClientHardwareAddress(hostMac.toBytes()) - .setOptions(optionList)))); - - return requestPacket; - } -} diff --git a/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java b/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java deleted file mode 100644 index 23c15a44e8b4517ea71269d786aaefde2471fd4a..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/** -* 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.core.util; - -import static org.junit.Assert.*; - -import org.junit.Test; - - -public class AppCookieTest { - /* Unfortunately the AppCookie registry is static. So we need to pick - * app ids that are not otherwise used for testing. - * NOTE: MSB bit is set for appId and cleared or appId2 ==> allows - * testing for sign handling - * - */ - private static int appId = 0xF42; - private static int appId2 = 0x743; - private static int invalidAppId1 = 0x1000; - private static int invalidAppId2 = -1; - - @Test - public void testAppCookie(){ - int user = 0xF123F123; // MSB set - int user2 = 0x42; // MSB cleared - long expectedCookie11 = 0xF4200000F123F123L; // app1, user1 - long expectedCookie21 = 0x74300000F123F123L; // app2, user1 - long expectedCookie12 = 0xF420000000000042L; // app1, user2 - long expectedCookie22 = 0x7430000000000042L; // app2, user2 - String name = "FooBar"; - String name2 = "FooFooFoo"; - - - // try get a cookie or an unregistered appId - try { - AppCookie.makeCookie(appId, user); - fail("Expected exception not thrown"); - } catch(AppIDNotRegisteredException e) { /* expected */ } - - AppCookie.registerApp(appId, name); - - long cookie = AppCookie.makeCookie(appId, user); - assertEquals(expectedCookie11, cookie); - assertEquals(appId, AppCookie.extractApp(cookie)); - assertEquals(user, AppCookie.extractUser(cookie)); - - cookie = AppCookie.makeCookie(appId, user2); - assertEquals(expectedCookie12, cookie); - assertEquals(appId, AppCookie.extractApp(cookie)); - assertEquals(user2, AppCookie.extractUser(cookie)); - - // Register again with the same name - AppCookie.registerApp(appId, name); - - // Register again with different name ==> exception - try { - AppCookie.registerApp(appId, name + "XXXXX"); - fail("Expected exception not thrown"); - } catch (AppIDInUseException e) { /* expected */ } - - // try get a cookie or an unregistered appId - try { - AppCookie.makeCookie(appId2, user); - fail("Expected exception not thrown"); - } catch(AppIDNotRegisteredException e) { /* expected */ } - - AppCookie.registerApp(appId2, name2); - - cookie = AppCookie.makeCookie(appId2, user); - assertEquals(expectedCookie21, cookie); - assertEquals(appId2, AppCookie.extractApp(cookie)); - assertEquals(user, AppCookie.extractUser(cookie)); - - cookie = AppCookie.makeCookie(appId2, user2); - assertEquals(expectedCookie22, cookie); - assertEquals(appId2, AppCookie.extractApp(cookie)); - assertEquals(user2, AppCookie.extractUser(cookie)); - - // Register invalid app ids - try { - AppCookie.registerApp(invalidAppId1, "invalid"); - fail("Expected exception not thrown"); - } catch (InvalidAppIDValueException e) { /* expected */ } - - try { - AppCookie.registerApp(invalidAppId2, "also invalid"); - fail("Expected exception not thrown"); - } catch (InvalidAppIDValueException e) { /* expected */ } - - - } -} diff --git a/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java b/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java deleted file mode 100644 index 0829aa447f4d211b0e207c45a0527b7a825906b9..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/** -* 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.core.util; - -import static org.easymock.EasyMock.createNiceMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import org.junit.Test; -import org.openflow.protocol.OFType; - -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.test.FloodlightTestCase; - -public class MessageDispatcherTest extends FloodlightTestCase { - - IOFMessageListener createLMock(String name) { - IOFMessageListener mock = createNiceMock(IOFMessageListener.class); - expect(mock.getName()).andReturn(name).anyTimes(); - return mock; - } - - void addPrereqs(IOFMessageListener mock, String... deps) { - for (String dep : deps) { - expect(mock.isCallbackOrderingPrereq(OFType.PACKET_IN, dep)).andReturn(true).anyTimes(); - } - } - - void testOrdering(ArrayList<IOFMessageListener> inputListeners) { - ListenerDispatcher<OFType, IOFMessageListener> ld = - new ListenerDispatcher<OFType, IOFMessageListener>(); - - for (IOFMessageListener l : inputListeners) { - ld.addListener(OFType.PACKET_IN, l); - } - for (IOFMessageListener l : inputListeners) { - verify(l); - } - - List<IOFMessageListener> result = ld.getOrderedListeners(); - System.out.print("Ordering: "); - for (IOFMessageListener l : result) { - System.out.print(l.getName()); - System.out.print(","); - } - System.out.print("\n"); - - for (int ind_i = 0; ind_i < result.size(); ind_i++) { - IOFMessageListener i = result.get(ind_i); - for (int ind_j = ind_i+1; ind_j < result.size(); ind_j++) { - IOFMessageListener j = result.get(ind_j); - - boolean orderwrong = - (i.isCallbackOrderingPrereq(OFType.PACKET_IN, j.getName()) || - j.isCallbackOrderingPostreq(OFType.PACKET_IN, i.getName())); - assertFalse("Invalid order: " + - ind_i + " (" + i.getName() + ") " + - ind_j + " (" + j.getName() + ") ", orderwrong); - } - } - } - - void randomTestOrdering(ArrayList<IOFMessageListener> mocks) { - Random rand = new Random(0); - ArrayList<IOFMessageListener> random = - new ArrayList<IOFMessageListener>(); - random.addAll(mocks); - for (int i = 0; i < 20; i++) { - for (int j = 0; j < random.size(); j++) { - int ind = rand.nextInt(mocks.size()-1); - IOFMessageListener tmp = random.get(j); - random.set(j, random.get(ind)); - random.set(ind, tmp); - } - testOrdering(random); - } - } - - @Test - public void testCallbackOrderingSimple() throws Exception { - ArrayList<IOFMessageListener> mocks = - new ArrayList<IOFMessageListener>(); - for (int i = 0; i < 10; i++) { - mocks.add(createLMock(""+i)); - } - for (int i = 1; i < 10; i++) { - addPrereqs(mocks.get(i), ""+(i-1)); - } - for (IOFMessageListener l : mocks) { - replay(l); - } - randomTestOrdering(mocks); - } - - @Test - public void testCallbackOrderingPartial() throws Exception { - ArrayList<IOFMessageListener> mocks = - new ArrayList<IOFMessageListener>(); - for (int i = 0; i < 10; i++) { - mocks.add(createLMock(""+i)); - } - for (int i = 1; i < 5; i++) { - addPrereqs(mocks.get(i), ""+(i-1)); - } - for (int i = 6; i < 10; i++) { - addPrereqs(mocks.get(i), ""+(i-1)); - } - for (IOFMessageListener l : mocks) { - replay(l); - } - randomTestOrdering(mocks); - } - - - @Test - public void testCallbackOrderingPartial2() throws Exception { - ArrayList<IOFMessageListener> mocks = - new ArrayList<IOFMessageListener>(); - for (int i = 0; i < 10; i++) { - mocks.add(createLMock(""+i)); - } - for (int i = 2; i < 5; i++) { - addPrereqs(mocks.get(i), ""+(i-1)); - } - for (int i = 6; i < 9; i++) { - addPrereqs(mocks.get(i), ""+(i-1)); - } - for (IOFMessageListener l : mocks) { - replay(l); - } - randomTestOrdering(mocks); - } -} diff --git a/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java b/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java deleted file mode 100644 index fa04b741496d801dfb7c3fe417a61083acab3f93..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java +++ /dev/null @@ -1,291 +0,0 @@ -/** -* 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.core.util; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; - -import net.floodlightcontroller.test.FloodlightTestCase; - -public class SingletonTaskTest extends FloodlightTestCase { - - public int ran = 0; - public int finished = 0; - public long time = 0; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - ran = 0; - finished = 0; - time = 0; - } - - @Test - public void testBasic() throws InterruptedException { - ScheduledExecutorService ses = - Executors.newSingleThreadScheduledExecutor(); - - SingletonTask st1 = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - ran += 1; - } - }); - st1.reschedule(0, null); - ses.shutdown(); - ses.awaitTermination(5, TimeUnit.SECONDS); - - assertEquals("Check that task ran", 1, ran); - } - - @Test - public void testDelay() throws InterruptedException { - ScheduledExecutorService ses = - Executors.newSingleThreadScheduledExecutor(); - - SingletonTask st1 = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - ran += 1; - time = System.nanoTime(); - } - }); - long start = System.nanoTime(); - st1.reschedule(10, TimeUnit.MILLISECONDS); - assertFalse("Check that task hasn't run yet", ran > 0); - - ses.shutdown(); - ses.awaitTermination(5, TimeUnit.SECONDS); - - assertEquals("Check that task ran", 1, ran); - assertTrue("Check that time passed appropriately", - (time - start) >= TimeUnit.NANOSECONDS.convert(10, TimeUnit.MILLISECONDS)); - } - - @Test - public void testReschedule() throws InterruptedException { - ScheduledExecutorService ses = - Executors.newSingleThreadScheduledExecutor(); - - final Object tc = this; - SingletonTask st1 = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - synchronized (tc) { - ran += 1; - } - time = System.nanoTime(); - } - }); - long start = System.nanoTime(); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - st1.reschedule(20, TimeUnit.MILLISECONDS); - Thread.sleep(5); - assertFalse("Check that task hasn't run yet", ran > 0); - - ses.shutdown(); - ses.awaitTermination(5, TimeUnit.SECONDS); - - assertEquals("Check that task ran only once", 1, ran); - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) >= TimeUnit.NANOSECONDS.convert(55, TimeUnit.MILLISECONDS)); - } - - @Test - public void testConcurrentAddDelay() throws InterruptedException { - ScheduledExecutorService ses = - Executors.newSingleThreadScheduledExecutor(); - - final Object tc = this; - SingletonTask st1 = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - synchronized (tc) { - ran += 1; - } - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - synchronized (tc) { - finished += 1; - time = System.nanoTime(); - } - } - }); - - long start = System.nanoTime(); - st1.reschedule(5, TimeUnit.MILLISECONDS); - Thread.sleep(20); - assertEquals("Check that task started", 1, ran); - assertEquals("Check that task not finished", 0, finished); - st1.reschedule(75, TimeUnit.MILLISECONDS); - assertTrue("Check task running state true", st1.context.taskRunning); - assertTrue("Check task should run state true", st1.context.taskShouldRun); - assertEquals("Check that task started", 1, ran); - assertEquals("Check that task not finished", 0, finished); - - Thread.sleep(150); - - assertTrue("Check task running state false", !st1.context.taskRunning); - assertTrue("Check task should run state false", !st1.context.taskShouldRun); - assertEquals("Check that task ran exactly twice", 2, ran); - assertEquals("Check that task finished exactly twice", 2, finished); - - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) >= TimeUnit.NANOSECONDS.convert(130, TimeUnit.MILLISECONDS)); - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) <= TimeUnit.NANOSECONDS.convert(160, TimeUnit.MILLISECONDS)); - - ses.shutdown(); - ses.awaitTermination(5, TimeUnit.SECONDS); - } - - @Test - public void testConcurrentAddDelay2() throws InterruptedException { - ScheduledExecutorService ses = - Executors.newSingleThreadScheduledExecutor(); - - final Object tc = this; - SingletonTask st1 = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - synchronized (tc) { - ran += 1; - } - try { - Thread.sleep(50); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - synchronized (tc) { - finished += 1; - time = System.nanoTime(); - } - } - }); - - long start = System.nanoTime(); - st1.reschedule(5, TimeUnit.MILLISECONDS); - Thread.sleep(20); - assertEquals("Check that task started", 1, ran); - assertEquals("Check that task not finished", 0, finished); - st1.reschedule(25, TimeUnit.MILLISECONDS); - assertTrue("Check task running state true", st1.context.taskRunning); - assertTrue("Check task should run state true", st1.context.taskShouldRun); - assertEquals("Check that task started", 1, ran); - assertEquals("Check that task not finished", 0, finished); - - Thread.sleep(150); - - assertTrue("Check task running state false", !st1.context.taskRunning); - assertTrue("Check task should run state false", !st1.context.taskShouldRun); - assertEquals("Check that task ran exactly twice", 2, ran); - assertEquals("Check that task finished exactly twice", 2, finished); - - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) >= TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS)); - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) <= TimeUnit.NANOSECONDS.convert(125, TimeUnit.MILLISECONDS)); - - ses.shutdown(); - ses.awaitTermination(5, TimeUnit.SECONDS); - } - - - @Test - public void testConcurrentAddNoDelay() throws InterruptedException { - ScheduledExecutorService ses = - Executors.newSingleThreadScheduledExecutor(); - - final Object tc = this; - SingletonTask st1 = new SingletonTask(ses, new Runnable() { - @Override - public void run() { - synchronized (tc) { - ran += 1; - } - try { - Thread.sleep(50); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - synchronized (tc) { - finished += 1; - time = System.nanoTime(); - } - } - }); - - long start = System.nanoTime(); - st1.reschedule(0, null); - Thread.sleep(20); - assertEquals("Check that task started", 1, ran); - assertEquals("Check that task not finished", 0, finished); - st1.reschedule(0, null); - assertTrue("Check task running state true", st1.context.taskRunning); - assertTrue("Check task should run state true", st1.context.taskShouldRun); - assertEquals("Check that task started", 1, ran); - assertEquals("Check that task not finished", 0, finished); - - Thread.sleep(150); - - assertTrue("Check task running state false", !st1.context.taskRunning); - assertTrue("Check task should run state false", !st1.context.taskShouldRun); - assertEquals("Check that task ran exactly twice", 2, ran); - assertEquals("Check that task finished exactly twice", 2, finished); - - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) >= TimeUnit.NANOSECONDS.convert(90, TimeUnit.MILLISECONDS)); - assertTrue("Check that time passed appropriately: " + (time - start), - (time - start) <= TimeUnit.NANOSECONDS.convert(130, TimeUnit.MILLISECONDS)); - - ses.shutdown(); - ses.awaitTermination(5, TimeUnit.SECONDS); - } -} diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java deleted file mode 100644 index ecd145f969176aafb8e7a0ede3dcbc87bd5fb731..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ /dev/null @@ -1,3039 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by David Erickson, Stanford University - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - **/ - -package net.floodlightcontroller.devicemanager.internal; - - -import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.anyShort; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.createNiceMock; -import static org.easymock.EasyMock.eq; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.isA; -import static org.easymock.EasyMock.or; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.reset; -import static org.easymock.EasyMock.verify; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IListener.Command; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceListener; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IEntityClassifierService; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus; -import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl.ClassState; -import net.floodlightcontroller.devicemanager.internal.DeviceSyncRepresentation.SyncEntity; -import net.floodlightcontroller.devicemanager.test.MockEntityClassifier; -import net.floodlightcontroller.devicemanager.test.MockEntityClassifierMac; -import net.floodlightcontroller.devicemanager.test.MockFlexEntityClassifier; -import net.floodlightcontroller.flowcache.FlowReconcileManager; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.packet.ARP; -import net.floodlightcontroller.packet.Data; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestApiServer; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.memory.MemoryStorageSource; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyService; - -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.util.HexString; -import org.sdnplatform.sync.IClosableIterator; -import org.sdnplatform.sync.IStoreClient; -import org.sdnplatform.sync.ISyncService; -import org.sdnplatform.sync.Versioned; -import org.sdnplatform.sync.test.MockSyncService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DeviceManagerImplTest extends FloodlightTestCase { - - protected static Logger logger = - LoggerFactory.getLogger(DeviceManagerImplTest.class); - - protected OFPacketIn testARPReplyPacketIn_1, testARPReplyPacketIn_2; - protected OFPacketIn testUDPPacketIn; - protected IPacket testARPReplyPacket_1, testARPReplyPacket_2; - protected Ethernet testUDPPacket; - protected byte[] testARPReplyPacket_1_Srld, testARPReplyPacket_2_Srld; - protected byte[] testUDPPacketSrld; - private MockSyncService syncService; - private IStoreClient<String, DeviceSyncRepresentation> storeClient; - - DeviceManagerImpl deviceManager; - MemoryStorageSource storageSource; - FlowReconcileManager flowReconcileMgr; - - private IOFSwitch makeSwitchMock(long id) { - IOFSwitch mockSwitch = createMock(IOFSwitch.class); - ImmutablePort port = ImmutablePort.create("p1", (short)1); - expect(mockSwitch.getId()).andReturn(id).anyTimes(); - expect(mockSwitch.getStringId()) - .andReturn(HexString.toHexString(id, 6)).anyTimes(); - expect(mockSwitch.getPort(anyShort())) - .andReturn(port).anyTimes(); - return mockSwitch; - } - - /* - * return an EasyMock ITopologyService that's setup so that it will - * answer all questions a device or device manager will ask - * (isAttachmentPointPort, etc.) in a way so that every port is a - * non-BD, attachment point port. - * The returned mock is still in record mode - */ - private ITopologyService makeMockTopologyAllPortsAp() { - ITopologyService mockTopology = createMock(ITopologyService.class); - mockTopology.isAttachmentPointPort(anyLong(), anyShort()); - expectLastCall().andReturn(true).anyTimes(); - mockTopology.getL2DomainId(anyLong()); - expectLastCall().andReturn(1L).anyTimes(); - mockTopology.isBroadcastDomainPort(anyLong(), anyShort()); - expectLastCall().andReturn(false).anyTimes(); - mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort()); - expectLastCall().andReturn(false).anyTimes(); - mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort()); - expectLastCall().andReturn(false).anyTimes(); - return mockTopology; - } - - @Override - @Before - public void setUp() throws Exception { - doSetUp(Role.MASTER); - } - - public void doSetUp(Role initialRole) throws Exception { - super.setUp(); - - this.syncService = new MockSyncService(); - - FloodlightModuleContext fmc = new FloodlightModuleContext(); - RestApiServer restApi = new RestApiServer(); - MockThreadPoolService tp = new MockThreadPoolService(); - ITopologyService topology = createMock(ITopologyService.class); - fmc.addService(IThreadPoolService.class, tp); - mockFloodlightProvider = getMockFloodlightProvider(); - mockFloodlightProvider.setRole(initialRole, ""); - - deviceManager = new DeviceManagerImpl(); - flowReconcileMgr = new FlowReconcileManager(); - DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); - fmc.addService(IDeviceService.class, deviceManager); - storageSource = new MemoryStorageSource(); - fmc.addService(IStorageSourceService.class, storageSource); - fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); - fmc.addService(IRestApiService.class, restApi); - fmc.addService(IFlowReconcileService.class, flowReconcileMgr); - fmc.addService(IEntityClassifierService.class, entityClassifier); - fmc.addService(ITopologyService.class, topology); - fmc.addService(ISyncService.class, syncService); - tp.init(fmc); - restApi.init(fmc); - storageSource.init(fmc); - deviceManager.init(fmc); - flowReconcileMgr.init(fmc); - entityClassifier.init(fmc); - syncService.init(fmc); - storageSource.startUp(fmc); - deviceManager.startUp(fmc); - flowReconcileMgr.startUp(fmc); - tp.startUp(fmc); - entityClassifier.startUp(fmc); - syncService.startUp(fmc); - - this.storeClient = - this.syncService.getStoreClient(DeviceManagerImpl.DEVICE_SYNC_STORE_NAME, - String.class, DeviceSyncRepresentation.class); - - reset(topology); - topology.addListener(deviceManager); - expectLastCall().anyTimes(); - replay(topology); - - IOFSwitch mockSwitch1 = makeSwitchMock(1L); - IOFSwitch mockSwitch10 = makeSwitchMock(10L); - IOFSwitch mockSwitch5 = makeSwitchMock(5L); - IOFSwitch mockSwitch50 = makeSwitchMock(50L); - Map<Long, IOFSwitch> switches = new HashMap<Long,IOFSwitch>(); - switches.put(1L, mockSwitch1); - switches.put(10L, mockSwitch10); - switches.put(5L, mockSwitch5); - switches.put(50L, mockSwitch50); - mockFloodlightProvider.setSwitches(switches); - - replay(mockSwitch1, mockSwitch5, mockSwitch10, mockSwitch50); - - // Build our test packet - this.testARPReplyPacket_1 = new Ethernet() - .setSourceMACAddress("00:44:33:22:11:01") - .setDestinationMACAddress("00:11:22:33:44:55") - .setEtherType(Ethernet.TYPE_ARP) - .setVlanID((short)5) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REPLY) - .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) - .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) - .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) - .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); - this.testARPReplyPacket_1_Srld = testARPReplyPacket_1.serialize(); - - // Another test packet with the same ARP payload as packet 1 but with - // a different source MAC. (i.e., sender MAC and source MAC differ) - this.testARPReplyPacket_2 = new Ethernet() - .setSourceMACAddress("00:99:88:77:66:55") - .setDestinationMACAddress("00:11:22:33:44:55") - .setEtherType(Ethernet.TYPE_ARP) - .setVlanID((short)5) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REPLY) - .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01")) - .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")) - .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) - .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))); - this.testARPReplyPacket_2_Srld = testARPReplyPacket_2.serialize(); - - // This packet reverses the MACs and IP from testARPReplyPacket_1 - this.testUDPPacket = (Ethernet) new Ethernet() - .setSourceMACAddress("00:11:22:33:44:55") - .setDestinationMACAddress("00:44:33:22:11:01") - .setEtherType(Ethernet.TYPE_IPv4) - .setVlanID((short)5) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.2") - .setDestinationAddress("192.168.1.1") - .setPayload(new UDP() - .setSourcePort((short) 5000) - .setDestinationPort((short) 5001) - .setPayload(new Data(new byte[] {0x01})))); - updateUDPPacketIn(); - - // Build the PacketIn - this.testARPReplyPacketIn_1 = ((OFPacketIn) mockFloodlightProvider. - getOFMessageFactory().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(this.testARPReplyPacket_1_Srld) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) this.testARPReplyPacket_1_Srld.length); - - // Build the PacketIn - this.testARPReplyPacketIn_2 = ((OFPacketIn) mockFloodlightProvider. - getOFMessageFactory().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(this.testARPReplyPacket_2_Srld) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) this.testARPReplyPacket_2_Srld.length); - - - } - - /** - * Updates testUDPPacketIn and testUDPPacketSrld from testUDPPacket - * To be called after testUDPPacket has been mangled. - */ - private void updateUDPPacketIn() { - this.testUDPPacketSrld = this.testUDPPacket.serialize(); - // Build the PacketIn - this.testUDPPacketIn = ((OFPacketIn) mockFloodlightProvider. - getOFMessageFactory().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 3) - .setPacketData(this.testUDPPacketSrld) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) this.testUDPPacketSrld.length); - } - - @Test - public void testLastSeen() throws Exception { - Calendar c = Calendar.getInstance(); - Date d1 = c.getTime(); - Entity entity1 = new Entity(1L, null, null, null, null, d1); - c.add(Calendar.SECOND, 1); - Entity entity2 = new Entity(1L, null, 1, null, null, c.getTime()); - - IDevice d = deviceManager.learnDeviceByEntity(entity2); - assertEquals(c.getTime(), d.getLastSeen()); - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(c.getTime(), d.getLastSeen()); - - deviceManager.startUp(null); - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(d1, d.getLastSeen()); - d = deviceManager.learnDeviceByEntity(entity2); - assertEquals(c.getTime(), d.getLastSeen()); - } - - - @Test - public void testEntityLearning() throws Exception { - IDeviceListener mockListener = - 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(anyLong())). - andReturn(1L).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). - andReturn(false).anyTimes(); - - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())).andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(10L, (short)1, 10L, (short)1)). - andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)1)). - andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(50L, (short)3, 50L, (short)3)). - andReturn(true).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - deviceManager.topology = mockTopology; - - Entity entity1 = new Entity(1L, null, null, 1L, 1, new Date()); - Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date()); - Entity entity3 = new Entity(1L, null, 1, 10L, 1, new Date()); - Entity entity4 = new Entity(1L, null, 1, 1L, 1, new Date()); - Entity entity5 = new Entity(2L, (short)4, 1, 5L, 2, new Date()); - Entity entity6 = new Entity(2L, (short)4, 1, 50L, 3, new Date()); - Entity entity7 = new Entity(2L, (short)4, 2, 50L, 3, new Date()); - - mockListener.deviceAdded(isA(IDevice.class)); - replay(mockListener, mockTopology); - - Device d1 = deviceManager.learnDeviceByEntity(entity1); - assertSame(d1, deviceManager.learnDeviceByEntity(entity1)); - assertSame(d1, deviceManager.findDeviceByEntity(entity1)); - assertEquals(DefaultEntityClassifier.entityClass , - d1.getEntityClass()); - assertArrayEquals(new Short[] { -1 }, d1.getVlanId()); - assertArrayEquals(new Integer[] { }, d1.getIPv4Addresses()); - - assertEquals(1, deviceManager.getAllDevices().size()); - verify(mockListener); - - reset(mockListener); - mockListener.deviceAdded(isA(IDevice.class)); - replay(mockListener); - - Device d2 = deviceManager.learnDeviceByEntity(entity2); - assertFalse(d1.equals(d2)); - assertNotSame(d1, d2); - assertNotSame(d1.getDeviceKey(), d2.getDeviceKey()); - assertEquals(MockEntityClassifier.testEC, d2.getEntityClass()); - assertArrayEquals(new Short[] { -1 }, d2.getVlanId()); - assertArrayEquals(new Integer[] { }, d2.getIPv4Addresses()); - - assertEquals(2, deviceManager.getAllDevices().size()); - verify(mockListener); - - reset(mockListener); - mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); - replay(mockListener); - - Device d3 = deviceManager.learnDeviceByEntity(entity3); - assertNotSame(d2, d3); - assertEquals(d2.getDeviceKey(), d3.getDeviceKey()); - assertEquals(MockEntityClassifier.testEC, d3.getEntityClass()); - assertArrayEquals(new Integer[] { 1 }, - d3.getIPv4Addresses()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) }, - d3.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) }, - d3.getAttachmentPoints(true)); - assertArrayEquals(new Short[] { -1 }, - d3.getVlanId()); - - assertEquals(2, deviceManager.getAllDevices().size()); - verify(mockListener); - - reset(mockListener); - mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); - replay(mockListener); - - Device d4 = deviceManager.learnDeviceByEntity(entity4); - assertNotSame(d1, d4); - assertEquals(d1.getDeviceKey(), d4.getDeviceKey()); - assertEquals(DefaultEntityClassifier.entityClass, d4.getEntityClass()); - assertArrayEquals(new Integer[] { 1 }, - d4.getIPv4Addresses()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, - d4.getAttachmentPoints()); - assertArrayEquals(new Short[] { -1 }, - d4.getVlanId()); - - assertEquals(2, deviceManager.getAllDevices().size()); - verify(mockListener); - - reset(mockListener); - mockListener.deviceAdded((isA(IDevice.class))); - replay(mockListener); - - Device d5 = deviceManager.learnDeviceByEntity(entity5); - assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 2) }, - d5.getAttachmentPoints()); - assertArrayEquals(new Short[] { (short) 4 }, - d5.getVlanId()); - assertEquals(2L, d5.getMACAddress()); - assertEquals("00:00:00:00:00:02", d5.getMACAddressString()); - verify(mockListener); - - reset(mockListener); - mockListener.deviceAdded(isA(IDevice.class)); - replay(mockListener); - - Device d6 = deviceManager.learnDeviceByEntity(entity6); - assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) }, - d6.getAttachmentPoints()); - assertArrayEquals(new Short[] { (short) 4 }, - d6.getVlanId()); - - assertEquals(4, deviceManager.getAllDevices().size()); - verify(mockListener); - - reset(mockListener); - mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); - replay(mockListener); - - Device d7 = deviceManager.learnDeviceByEntity(entity7); - assertNotSame(d6, d7); - assertEquals(d6.getDeviceKey(), d7.getDeviceKey()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(50L, 3) }, - d7.getAttachmentPoints()); - assertArrayEquals(new Short[] { (short) 4 }, - d7.getVlanId()); - - assertEquals(4, deviceManager.getAllDevices().size()); - verify(mockListener); - - - reset(mockListener); - replay(mockListener); - - reset(deviceManager.topology); - deviceManager.topology.addListener(deviceManager); - expectLastCall().times(1); - replay(deviceManager.topology); - - deviceManager.entityClassifier = new MockEntityClassifierMac(); - deviceManager.startUp(null); - Entity entityNoClass = new Entity(5L, (short)1, 5, -1L, 1, new Date()); - assertEquals(null, deviceManager.learnDeviceByEntity(entityNoClass)); - - verify(mockListener); - } - - - private void doTestEntityOrdering(boolean computeInsertionPoint) throws Exception { - Entity e = new Entity(10L, null, null, null, null, null); - IEntityClass ec = createNiceMock(IEntityClass.class); - Device d = new Device(deviceManager, 1L, e, ec); - - int expectedLength = 1; - Long[] macs = new Long[] { 5L, // new first element - 15L, // new last element - 7L, // insert in middle - 12L, // insert in middle - 6L, // insert at idx 1 - 14L, // insert at idx length-2 - 1L, - 20L - }; - - for (Long mac: macs) { - e = new Entity(mac, null, null, null, null, null); - int insertionPoint; - if (computeInsertionPoint) { - insertionPoint = -(Arrays.binarySearch(d.entities, e)+1); - } else { - insertionPoint = -1; - } - d = deviceManager.allocateDevice(d, e, insertionPoint); - expectedLength++; - assertEquals(expectedLength, d.entities.length); - for (int i = 0; i < d.entities.length-1; i++) - assertEquals(-1, d.entities[i].compareTo(d.entities[i+1])); - } - } - - @Test - public void testEntityOrderingExternal() throws Exception { - doTestEntityOrdering(true); - } - - @Test - public void testEntityOrderingInternal() throws Exception { - doTestEntityOrdering(false); - } - - @Test - public void testAttachmentPointLearning() throws Exception { - IDeviceListener mockListener = - createMock(IDeviceListener.class); - expect(mockListener.getName()).andReturn("mockListener").atLeastOnce(); - expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - - replay(mockListener); - deviceManager.addListener(mockListener); - verify(mockListener); - reset(mockListener); - - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getL2DomainId(1L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(5L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(10L)). - andReturn(10L).anyTimes(); - expect(mockTopology.getL2DomainId(50L)). - andReturn(10L).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). - andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort())).andReturn(false).anyTimes(); - - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())).andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(5L, (short)1, 10L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(10L, (short)1, 50L, (short)1)). - andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - - deviceManager.topology = mockTopology; - - Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); - Entity entity0 = new Entity(1L, null, null, null, null, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity4 = new Entity(1L, null, null, 50L, 1, c.getTime()); - - IDevice d; - SwitchPort[] aps; - Integer[] ips; - - mockListener.deviceAdded(isA(IDevice.class)); - replay(mockListener); - - deviceManager.learnDeviceByEntity(entity1); - d = deviceManager.learnDeviceByEntity(entity0); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - mockListener.deviceMoved((isA(IDevice.class))); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity2); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - - assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - mockListener.deviceMoved((isA(IDevice.class))); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity3); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] {new SwitchPort(5L, 1), new SwitchPort(10L, 1)}, aps); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - mockListener.deviceMoved((isA(IDevice.class))); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity4); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1), - new SwitchPort(50L, 1) }, aps); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - } - - /** - * 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(1L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(5L)). - andReturn(1L).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). - andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort())) - .andReturn(false).anyTimes(); - - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())).andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). - andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - - deviceManager.topology = mockTopology; - - Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity3 = new Entity(1L, null, null, 1L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity4 = new Entity(1L, null, null, 5L, 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(1L, 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(5L, 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(1L, 1), - new SwitchPort(5L, 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(1L, 1), - new SwitchPort(5L, 1, ErrorStatus.DUPLICATE_DEVICE)}, - d.getAttachmentPoints(true)); - verify(mockListener); - } - - private void verifyEntityArray(Entity[] expected, Device d) { - Arrays.sort(expected); - assertArrayEquals(expected, d.entities); - } - - @Test - public void testNoLearningOnInternalPorts() throws Exception { - IDeviceListener mockListener = - createMock(IDeviceListener.class); - - expect(mockListener.getName()).andReturn("mockListener").anyTimes(); - expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - - replay(mockListener); - deviceManager.addListener(mockListener); - verify(mockListener); - reset(mockListener); - - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getL2DomainId(1L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(2L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(3L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(4L)). - andReturn(1L).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())) - .andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort())) - .andReturn(false).anyTimes(); - - expect(mockTopology.isAttachmentPointPort(or(eq(1L), eq(3L)), anyShort())) - .andReturn(true).anyTimes(); - // Switches 2 and 4 have only internal ports - expect(mockTopology.isAttachmentPointPort(or(eq(2L), eq(4L)), anyShort())) - .andReturn(false).anyTimes(); - - expect(mockTopology.isConsistent(1L, (short)1, 3L, (short)1)) - .andReturn(false).once(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - - deviceManager.topology = mockTopology; - - Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity2 = new Entity(1L, null, 2, 2L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity3 = new Entity(1L, null, 3, 3L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity4 = new Entity(1L, null, 4, 4L, 1, c.getTime()); - - IDevice d; - SwitchPort[] aps; - Integer[] ips; - - mockListener.deviceAdded(isA(IDevice.class)); - expectLastCall().once(); - replay(mockListener); - - // cannot learn device internal ports - d = deviceManager.learnDeviceByEntity(entity2); - assertNull(d); - d = deviceManager.learnDeviceByEntity(entity4); - assertNull(d); - - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); - verifyEntityArray(new Entity[] { entity1 } , (Device)d); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - replay(mockListener); - - // don't learn - d = deviceManager.learnDeviceByEntity(entity2); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); - verifyEntityArray(new Entity[] { entity1 } , (Device)d); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - mockListener.deviceMoved(isA(IDevice.class)); - mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); - replay(mockListener); - - // learn - d = deviceManager.learnDeviceByEntity(entity3); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(3L, 1) }, aps); - verifyEntityArray(new Entity[] { entity1, entity3 } , (Device)d); - ips = d.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 1, 3 }, ips); - verify(mockListener); - - reset(mockListener); - replay(mockListener); - - // don't learn - d = deviceManager.learnDeviceByEntity(entity4); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(3L, 1) }, aps); - verifyEntityArray(new Entity[] { entity1, entity3 } , (Device)d); - ips = d.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 1, 3 }, ips); - verify(mockListener); - } - - @Test - public void testAttachmentPointSuppression() throws Exception { - IDeviceListener mockListener = - createMock(IDeviceListener.class); - - expect(mockListener.getName()).andReturn("mockListener").anyTimes(); - expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - - replay(mockListener); - deviceManager.addListener(mockListener); - verify(mockListener); - reset(mockListener); - - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getL2DomainId(1L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(5L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(10L)). - andReturn(10L).anyTimes(); - expect(mockTopology.getL2DomainId(50L)). - andReturn(10L).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())) - .andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort())) - .andReturn(false).anyTimes(); - - expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())) - .andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(5L, (short)1, 50L, (short)1)) - .andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - - deviceManager.topology = mockTopology; - // suppress (1L, 1) and (10L, 1) - deviceManager.addSuppressAPs(1L, (short)1); - deviceManager.addSuppressAPs(10L, (short)1); - - Calendar c = Calendar.getInstance(); - Entity entity0 = new Entity(1L, null, null, null, null, c.getTime()); - // No attachment point should be learnt on 1L, 1 - Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity2 = new Entity(1L, null, 1, 5L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime()); - c.add(Calendar.SECOND, 1); - Entity entity4 = new Entity(1L, null, null, 50L, 1, c.getTime()); - - IDevice d; - SwitchPort[] aps; - Integer[] ips; - - mockListener.deviceAdded(isA(IDevice.class)); - 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); - - deviceManager.learnDeviceByEntity(entity0); - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertEquals(aps.length, 0); - verifyEntityArray(new Entity[] { entity0, entity1} , (Device)d); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 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()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps); - verifyEntityArray(new Entity[] { entity0, entity1, entity2 } , (Device)d); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity3); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps); - verifyEntityArray(new Entity[] { entity0, entity1, entity2, entity3 } , (Device)d); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - - reset(mockListener); - mockListener.deviceMoved((isA(IDevice.class))); - replay(mockListener); - - d = deviceManager.learnDeviceByEntity(entity4); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1), - new SwitchPort(50L, 1) }, aps); - verifyEntityArray(new Entity[] { entity0, entity1, entity2, entity3, entity4} , (Device)d); - ips = d.getIPv4Addresses(); - assertArrayEquals(new Integer[] { 1 }, ips); - verify(mockListener); - } - - @Test - public void testBDAttachmentPointLearning() throws Exception { - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getL2DomainId(anyLong())). - andReturn(1L).anyTimes(); - expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(1L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(1L, (short)2)). - andReturn(true).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(1L, (short)1, - 1L, (short)2)).andReturn(true).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(1L, (short)2, - 1L, (short)1)).andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - - deviceManager.topology = mockTopology; - - Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); - c.add(Calendar.MILLISECOND, - (int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT/ 2); - Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime()); - c.add(Calendar.MILLISECOND, - (int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT / 2 + 1); - Entity entity3 = new Entity(1L, null, null, 1L, 2, c.getTime()); - - IDevice d; - SwitchPort[] aps; - - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); - - // this timestamp is too soon; don't switch - d = deviceManager.learnDeviceByEntity(entity2); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); - - // it should switch when we learn with a timestamp after the - // timeout - d = deviceManager.learnDeviceByEntity(entity3); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2) }, aps); - } - - /** - * This test verifies that the learning behavior on OFPP_LOCAL ports. - * Once a host is learned on OFPP_LOCAL, it is allowed to move only from - * one OFPP_LOCAL to another OFPP_LOCAL port. - * @throws Exception - */ - @Test - public void testLOCALAttachmentPointLearning() throws Exception { - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getL2DomainId(anyLong())). - andReturn(1L).anyTimes(); - expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(1L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(1L, OFPort.OFPP_LOCAL.getValue())). - andReturn(false).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(1L, (short)2)). - andReturn(true).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(1L, (short)1, - 1L, OFPort.OFPP_LOCAL.getValue())).andReturn(true).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(1L, OFPort.OFPP_LOCAL.getValue(), - 1L, (short)2)).andReturn(true).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(1L, (short)2, - 1L, OFPort.OFPP_LOCAL.getValue())).andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - - deviceManager.topology = mockTopology; - - Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); - c.add(Calendar.MILLISECOND, - (int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT/ 2); - Entity entity2 = new Entity(1L, null, null, 1L, (int)OFPort.OFPP_LOCAL.getValue(), c.getTime()); - c.add(Calendar.MILLISECOND, - (int)AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT + 1); - Entity entity3 = new Entity(1L, null, null, 1L, 2, c.getTime()); - - IDevice d; - SwitchPort[] aps; - - d = deviceManager.learnDeviceByEntity(entity1); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps); - - // Ensure that the attachment point changes to OFPP_LOCAL - d = deviceManager.learnDeviceByEntity(entity2); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, OFPort.OFPP_LOCAL.getValue()) }, aps); - - // Even though the new attachment point is consistent with old - // and the time has elapsed, OFPP_LOCAL attachment point should - // be maintained. - d = deviceManager.learnDeviceByEntity(entity3); - assertEquals(1, deviceManager.getAllDevices().size()); - aps = d.getAttachmentPoints(); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, OFPort.OFPP_LOCAL.getValue()) }, aps); - } - - private static void - mockTopologyForPacketInTests(ITopologyService mockTopology) { - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true). - anyTimes(); - expect(mockTopology.isConsistent(EasyMock.anyLong(), - EasyMock.anyShort(), - EasyMock.anyLong(), - EasyMock.anyShort())).andReturn(false). - anyTimes(); - expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), - EasyMock.anyShort())) - .andReturn(false) - .anyTimes(); - expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), - anyShort(), - anyLong(), - anyShort())) - .andReturn(false).anyTimes(); - - } - - private Command dispatchPacketIn(long swId, OFPacketIn pi, - FloodlightContext cntx) { - IOFSwitch sw = mockFloodlightProvider.getSwitch(swId); - Ethernet eth = new Ethernet(); - eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - eth); - return deviceManager.receive(sw, pi, cntx); - } - - /** - * Verify that the given device exactly matches the given fields. E.g., - * if ip is not null we expect the device to have exactly one IP address. - * swId and port are the attachment point port. - * Vlan and ip are optional all other fields must be specified. - * @return - */ - private static void verifyDevice(IDevice d, long mac, Short vlan, Integer ip, - long swId, int port) { - assertNotNull(d); - assertEquals(mac, d.getMACAddress()); - if (vlan == null) - assertArrayEquals(new Short[0], d.getVlanId()); - else - assertArrayEquals(new Short[] { vlan }, d.getVlanId()); - - if (ip == null) - assertArrayEquals(new Integer[0], d.getIPv4Addresses()); - else - assertArrayEquals(new Integer[] { ip }, d.getIPv4Addresses()); - - SwitchPort expectedAp = new SwitchPort(swId, port); - assertArrayEquals(new SwitchPort[] { expectedAp }, - d.getAttachmentPoints()); - } - - - @Test - public void testPacketInBasic() throws Exception { - byte[] deviceMac = - ((Ethernet)this.testARPReplyPacket_1).getSourceMACAddress(); - OFPacketIn packetIn = testARPReplyPacketIn_1; - Integer ipaddr = IPv4.toIPv4Address("192.168.1.1"); - - // Mock up our expected behavior - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - mockTopologyForPacketInTests(mockTopology); - replay(mockTopology); - - FloodlightContext cntx = new FloodlightContext(); - Command cmd = dispatchPacketIn(1L, packetIn, cntx); - verify(mockTopology); - assertEquals(Command.CONTINUE, cmd); - // Verify the device - Device rdevice = (Device) - deviceManager.findDevice(Ethernet.toLong(deviceMac), - (short)5, null, null, null); - verifyDevice(rdevice, Ethernet.toLong(deviceMac), - (short)5, ipaddr, 1L, 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(null, null, ipaddr, - null, null); - 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.setInPort((short)2); - cmd = dispatchPacketIn(5L, packetIn, cntx); - verify(mockTopology); - // Verify the replay matched our expectations - assertEquals(Command.CONTINUE, cmd); - - // Verify the device - rdevice = (Device) - deviceManager.findDevice(Ethernet.toLong(deviceMac), - (short)5, null, null, null); - verifyDevice(rdevice, Ethernet.toLong(deviceMac), - (short)5, ipaddr, 5L, 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 - long srcMac = Ethernet.toLong(testUDPPacket.getSourceMACAddress()); - long dstMac = Ethernet.toLong(deviceMac); - reset(mockTopology); - mockTopologyForPacketInTests(mockTopology); - replay(mockTopology); - // trigger the packet in - cntx = new FloodlightContext(); - cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - verify(mockTopology); - - assertEquals(Command.CONTINUE, cmd); - IDevice srcDev = - deviceManager.findDevice(srcMac, (short)5, null, null, null); - verifyDevice(srcDev, srcMac, (short)5, null, - 1L, testUDPPacketIn.getInPort()); - - IDevice dstDev = - deviceManager.findDevice(dstMac, (short)5, null, null, null); - verifyDevice(dstDev, dstMac, (short)5, ipaddr, 5L, 2); - - cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - assertEquals(srcDev, cntxSrcDev); - - cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertEquals(dstDev, cntxDstDev); - - assertEquals(2, deviceManager.getAllDevices().size()); - } - - /** - * This test ensures the device manager learns the source device - * corresponding to the senderHardwareAddress and senderProtocolAddress - * in an ARP response whenever the senderHardwareAddress is different - * from the source MAC address of the Ethernet frame. - * - * @throws Exception - */ - @Test - public void testDeviceLearningFromArpResponseData() throws Exception { - ARP arp = (ARP)((Ethernet)this.testARPReplyPacket_2).getPayload(); - long senderMac = Ethernet.toLong(arp.getSenderHardwareAddress()); - long sourceMac = - Ethernet.toLong(((Ethernet)this.testARPReplyPacket_2) - .getSourceMACAddress()); - Integer ipaddr = IPv4.toIPv4Address("192.168.1.1"); - OFPacketIn packetIn = testARPReplyPacketIn_2; - - // Mock up our expected behavior - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - mockTopologyForPacketInTests(mockTopology); - replay(mockTopology); - - - FloodlightContext cntx = new FloodlightContext(); - Command cmd = dispatchPacketIn(1L, packetIn, cntx); - verify(mockTopology); - assertEquals(Command.CONTINUE, cmd); - // Verify the device for the sender HW address - Device senderDev = (Device) - deviceManager.findDevice(senderMac, (short)5, null, null, null); - verifyDevice(senderDev, senderMac, (short)5, ipaddr, 1L, 1); - - Device result = null; - Iterator<? extends IDevice> dstiter = - deviceManager.queryDevices(null, null, ipaddr, - null, null); - if (dstiter.hasNext()) { - result = (Device)dstiter.next(); - } - assertFalse("There shouldn't be more than 1 device", dstiter.hasNext()); - assertEquals(senderDev, result); - - - - // Verify the device for the source MAC - Device srcDev = (Device) - deviceManager.findDevice(sourceMac, (short)5, null, null, null); - // must NOT learn IP on this device - verifyDevice(srcDev, sourceMac, (short)5, null, 1L, 1); - assertFalse("Device must differ", srcDev.equals(senderDev)); - // Context is annotated with this device, not the device associated - // with ARP sender address - IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - assertEquals(srcDev, cntxSrcDev); - - assertEquals(2, deviceManager.getAllDevices().size()); - } - - - @Test - public void testPacketInInvalidSrcMac() throws Exception { - // Mock up our expected behavior - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - mockTopologyForPacketInTests(mockTopology); - replay(mockTopology); - FloodlightContext cntx = new FloodlightContext(); - - testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(0L)); - updateUDPPacketIn(); - Command cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.STOP, cmd); - IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - assertNull(cntxSrcDev); - IDevice cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertNull(cntxDstDev); - - testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(-1L)); - updateUDPPacketIn(); - cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.STOP, cmd); - cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - assertNull(cntxSrcDev); - cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertNull(cntxDstDev); - - // MAC with only the multicast bit set - testUDPPacket.setSourceMACAddress(new byte[] { 1, 0, 0, 0, 0, 0 }); - updateUDPPacketIn(); - cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.STOP, cmd); - cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - assertNull(cntxSrcDev); - cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertNull(cntxDstDev); - - // Now use a real MAC. We should get a src device - testUDPPacket.setSourceMACAddress(Ethernet.toByteArray(1L)); - updateUDPPacketIn(); - cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.CONTINUE, cmd); - cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - verifyDevice(cntxSrcDev, 1L, (short)5, null, - 1L, testUDPPacketIn.getInPort()); - - cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertNull(cntxDstDev); - verify(mockTopology); - } - - - @Test - public void testPacketInInvalidDstMac() throws Exception { - // Mock up our expected behavior - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - mockTopologyForPacketInTests(mockTopology); - replay(mockTopology); - FloodlightContext cntx = new FloodlightContext(); - - long srcMac = Ethernet.toLong(testUDPPacket.getSourceMACAddress()); - long dstMac = Ethernet.toLong(testUDPPacket.getDestinationMACAddress()); - - // Prime device manager with the source device - Command cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.CONTINUE, cmd); - IDevice cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - verifyDevice(cntxSrcDev, srcMac, (short)5, null, - 1L, testUDPPacketIn.getInPort()); - IDevice cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertNull(cntxDstDev); - IDevice expectedSrcDev = cntxSrcDev; - - // Create a device for the destination. We can use testARPPacketIn_1 - // for that. - cntx = new FloodlightContext(); - // Prime device manager with the source device - cmd = dispatchPacketIn(1L, testARPReplyPacketIn_1, cntx); - assertEquals(Command.CONTINUE, cmd); - cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - // yes: we check that cntxSrcDev matched dstMAC because we are - // just adding the dest device - int ip = IPv4.toIPv4Address("192.168.1.1"); - verifyDevice(cntxSrcDev, dstMac, (short)5, ip, - 1L, testARPReplyPacketIn_1.getInPort()); - // yes: we set the expected dst device to the current srcDev - IDevice expectedDstDev = cntxSrcDev; - - //------------------------------- - // Let the real tests begin - - cntx = new FloodlightContext(); - testUDPPacket.setDestinationMACAddress(Ethernet.toByteArray(0L)); - updateUDPPacketIn(); - cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.STOP, cmd); - cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertNull(cntxDstDev); - - // use a real dest mac - cntx = new FloodlightContext(); - testUDPPacket.setDestinationMACAddress(Ethernet.toByteArray(dstMac)); - updateUDPPacketIn(); - cmd = dispatchPacketIn(1L, testUDPPacketIn, cntx); - assertEquals(Command.CONTINUE, cmd); - cntxSrcDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_SRC_DEVICE); - assertEquals(expectedSrcDev, cntxSrcDev); - cntxDstDev = IDeviceService.fcStore.get(cntx, - IDeviceService.CONTEXT_DST_DEVICE); - assertEquals(expectedDstDev, cntxDstDev); - - verify(mockTopology); - } - - /** - * Note: Entity expiration does not result in device moved notification. - * @throws Exception - */ - public void doTestEntityExpiration() throws Exception { - IDeviceListener mockListener = - createMock(IDeviceListener.class); - expect(mockListener.getName()).andReturn("mockListener").anyTimes(); - expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - - expect(mockTopology.isBroadcastDomainPort(1L, (short)1)).andReturn(false).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(5L, (short)1)).andReturn(false).anyTimes(); - expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(5L)).andReturn(5L).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). - andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - deviceManager.topology = mockTopology; - - Calendar c = Calendar.getInstance(); - Entity entity1 = new Entity(1L, null, 2, 1L, 1, c.getTime()); - c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); - Entity entity2 = new Entity(1L, null, 1, 5L, 1, c.getTime()); - - deviceManager.learnDeviceByEntity(entity1); - IDevice d = deviceManager.learnDeviceByEntity(entity2); - assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 1)}, - d.getAttachmentPoints()); - Iterator<? extends IDevice> diter = - deviceManager.queryClassDevices(d.getEntityClass(), - null, null, 1, null, null); - assertTrue(diter.hasNext()); - assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); - diter = deviceManager.queryClassDevices(d.getEntityClass(), - null, null, 2, null, null); - assertTrue(diter.hasNext()); - assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); - - replay(mockListener); - deviceManager.addListener(mockListener); - verify(mockListener); - reset(mockListener); - - mockListener.deviceIPV4AddrChanged(isA(IDevice.class)); - replay(mockListener); - deviceManager.entityCleanupTask.reschedule(0, null); - - d = deviceManager.getDevice(d.getDeviceKey()); - assertArrayEquals(new Integer[] { 2 }, d.getIPv4Addresses()); - - // Attachment points are not removed, previous ones are still valid. - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 1) }, - d.getAttachmentPoints()); - diter = deviceManager.queryClassDevices(d.getEntityClass(), - null, null, 2, null, null); - assertTrue(diter.hasNext()); - assertEquals(d.getDeviceKey(), diter.next().getDeviceKey()); - diter = deviceManager.queryClassDevices(d.getEntityClass(), - null, null, 1, null, null); - assertFalse(diter.hasNext()); - - d = deviceManager.findDevice(1L, null, null, null, null); - assertArrayEquals(new Integer[] { 2 }, d.getIPv4Addresses()); - - // Attachment points are not removed, previous ones are still valid. - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 1) }, - d.getAttachmentPoints()); - - verify(mockListener); - } - - public void doTestDeviceExpiration() throws Exception { - IDeviceListener mockListener = - createMock(IDeviceListener.class); - expect(mockListener.getName()).andReturn("mockListener").anyTimes(); - expect(mockListener.isCallbackOrderingPostreq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - expect(mockListener.isCallbackOrderingPrereq((String)anyObject(), (String)anyObject())) - .andReturn(false).atLeastOnce(); - - Calendar c = Calendar.getInstance(); - c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1); - Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime()); - Entity entity2 = new Entity(1L, null, 2, 5L, 1, c.getTime()); - - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - - expect(mockTopology.isAttachmentPointPort(EasyMock.anyLong(), - EasyMock.anyShort())). - andReturn(true). - anyTimes(); - expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes(); - expect(mockTopology.isConsistent(EasyMock.anyLong(), - EasyMock.anyShort(), - EasyMock.anyLong(), - EasyMock.anyShort())).andReturn(false). - anyTimes(); - expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), - EasyMock.anyShort())). - andReturn(false).anyTimes(); - replay(mockTopology); - - IDevice d = deviceManager.learnDeviceByEntity(entity2); - d = deviceManager.learnDeviceByEntity(entity1); - assertArrayEquals(new Integer[] { 1, 2 }, d.getIPv4Addresses()); - - replay(mockListener); - deviceManager.addListener(mockListener); - verify(mockListener); - reset(mockListener); - - mockListener.deviceRemoved(isA(IDevice.class)); - replay(mockListener); - deviceManager.entityCleanupTask.reschedule(0, null); - - IDevice r = deviceManager.getDevice(d.getDeviceKey()); - assertNull(r); - Iterator<? extends IDevice> diter = - deviceManager.queryClassDevices(d.getEntityClass(), - null, null, 1, null, null); - assertFalse(diter.hasNext()); - - r = deviceManager.findDevice(1L, null, null, null, null); - assertNull(r); - - verify(mockListener); - } - - /* - * A ConcurrentHashMap for devices (deviceMap) that can be used to test - * code that specially handles concurrent modification situations. In - * particular, we overwrite values() and will replace / remove all the - * elements returned by values. - * - * The remove flag in the constructor specifies if devices returned by - * values() should be removed or replaced. - */ - protected static class ConcurrentlyModifiedDeviceMap - extends ConcurrentHashMap<Long, Device> { - private static final long serialVersionUID = 7784938535441180562L; - protected boolean remove; - public ConcurrentlyModifiedDeviceMap(boolean remove) { - super(); - this.remove = remove; - } - - @Override - public Collection<Device> values() { - // Get the values from the real map and copy them since - // the collection returned by values can reflect changed - Collection<Device> devs = new ArrayList<Device>(super.values()); - for (Device d: devs) { - if (remove) { - // We remove the device from the underlying map - super.remove(d.getDeviceKey()); - } else { - super.remove(d.getDeviceKey()); - // We add a different Device instance with the same - // key to the map. We'll do some hackery so the device - // is different enough to compare differently in equals - // but otherwise looks the same. - // It's ugly but it works. - // clone entities - Device newDevice = d; - for (Entity e: d.getEntities()) { - Entity newEntity = new Entity (e.macAddress, - e.vlan, - e.ipv4Address, - e.switchDPID, - e.switchPort, - e.lastSeenTimestamp); - if (e.vlan == null) - newEntity.vlan = (short)1; - else - newEntity.vlan = (short)((e.vlan + 1 % 4095)+1); - newDevice = new Device(newDevice, newEntity, -1); - } - assertEquals(false, newDevice.equals(d)); - super.put(newDevice.getDeviceKey(), newDevice); - } - } - return devs; - } - } - - @Test - public void testEntityExpiration() throws Exception { - doTestEntityExpiration(); - } - - @Test - public void testDeviceExpiration() throws Exception { - doTestDeviceExpiration(); - } - - /* Test correct entity cleanup behavior when a concurrent modification - * occurs. - */ - @Test - public void testEntityExpirationConcurrentModification() throws Exception { - deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false); - doTestEntityExpiration(); - } - - /* Test correct entity cleanup behavior when a concurrent remove - * occurs. - */ - @Test - public void testDeviceExpirationConcurrentRemove() throws Exception { - deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(true); - doTestDeviceExpiration(); - } - - /* Test correct entity cleanup behavior when a concurrent modification - * occurs. - */ - @Test - public void testDeviceExpirationConcurrentModification() throws Exception { - deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false); - doTestDeviceExpiration(); - } - - - @Test - public void testAttachmentPointFlapping() throws Exception { - Calendar c = Calendar.getInstance(); - - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())).andReturn(true).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), - anyShort())). - andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort())).andReturn(false).anyTimes(); - expect(mockTopology.getL2DomainId(anyLong())). - andReturn(1L).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)1)). - andReturn(true).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 10L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(5L, (short)1, 10L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(10L, (short)1, 1L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(5L, (short)1, 1L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(10L, (short)1, 5L, (short)1)). - andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - - replay(mockTopology); - deviceManager.topology = mockTopology; - - Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime()); - Entity entity1a = new Entity(1L, null, 1, 1L, 1, c.getTime()); - Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime()); - Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime()); - entity1.setLastSeenTimestamp(c.getTime()); - c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2); - entity1a.setLastSeenTimestamp(c.getTime()); - c.add(Calendar.MILLISECOND, 1); - entity2.setLastSeenTimestamp(c.getTime()); - c.add(Calendar.MILLISECOND, 1); - entity3.setLastSeenTimestamp(c.getTime()); - - - - IDevice d; - d = deviceManager.learnDeviceByEntity(entity1); - d = deviceManager.learnDeviceByEntity(entity1a); - d = deviceManager.learnDeviceByEntity(entity2); - d = deviceManager.learnDeviceByEntity(entity3); - - // all entities are active, so entity3 should win - assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1) }, - d.getAttachmentPoints()); - - assertArrayEquals(new SwitchPort[] { new SwitchPort(10L, 1),}, - d.getAttachmentPoints(true)); - - c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/4); - entity1.setLastSeenTimestamp(c.getTime()); - d = deviceManager.learnDeviceByEntity(entity1); - - // all are still active; entity3 should still win - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, - d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 1, - ErrorStatus.DUPLICATE_DEVICE), - new SwitchPort(10L, 1, - ErrorStatus.DUPLICATE_DEVICE) }, - d.getAttachmentPoints(true)); - - c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+2000); - entity1.setLastSeenTimestamp(c.getTime()); - d = deviceManager.learnDeviceByEntity(entity1); - - assertEquals(entity1.getActiveSince(), entity1.getLastSeenTimestamp()); - // entity1 should now be the only active entity - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, - d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, - d.getAttachmentPoints(true)); - } - - - @Test - public void testAttachmentPointFlappingTwoCluster() throws Exception { - Calendar c = Calendar.getInstance(); - - ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())).andReturn(true).anyTimes(); - expect(mockTopology.isBroadcastDomainPort(anyLong(), - anyShort())). - andReturn(false).anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), - anyLong(), anyShort())).andReturn(false).anyTimes(); - expect(mockTopology.getL2DomainId(1L)). - andReturn(1L).anyTimes(); - expect(mockTopology.getL2DomainId(5L)). - andReturn(5L).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 1L, (short)2)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)2, 5L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(5L, (short)1, 5L, (short)2)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)2, 1L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)1)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(1L, (short)1, 5L, (short)2)). - andReturn(false).anyTimes(); - expect(mockTopology.isConsistent(5L, (short)2, 5L, (short)1)). - andReturn(false).anyTimes(); - - Date topologyUpdateTime = new Date(); - expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime). - anyTimes(); - - replay(mockTopology); - deviceManager.topology = mockTopology; - - Entity entity1 = new Entity(1L, null, null, 1L, 1, c.getTime()); - Entity entity2 = new Entity(1L, null, null, 1L, 2, c.getTime()); - Entity entity3 = new Entity(1L, null, null, 5L, 1, c.getTime()); - Entity entity4 = new Entity(1L, null, null, 5L, 2, c.getTime()); - entity1.setLastSeenTimestamp(c.getTime()); - c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT/2); - c.add(Calendar.MILLISECOND, 1); - entity2.setLastSeenTimestamp(c.getTime()); - c.add(Calendar.MILLISECOND, 1); - entity3.setLastSeenTimestamp(c.getTime()); - c.add(Calendar.MILLISECOND, 1); - entity4.setLastSeenTimestamp(c.getTime()); - - deviceManager.learnDeviceByEntity(entity1); - deviceManager.learnDeviceByEntity(entity2); - deviceManager.learnDeviceByEntity(entity3); - IDevice d = deviceManager.learnDeviceByEntity(entity4); - - // all entities are active, so entities 2,4 should win - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2), - new SwitchPort(5L, 2) }, - d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 2), - new SwitchPort(5L, 2)}, - d.getAttachmentPoints(true)); - - c.add(Calendar.MILLISECOND, 1); - entity1.setLastSeenTimestamp(c.getTime()); - d = deviceManager.learnDeviceByEntity(entity1); - - // all entities are active, so entities 2,4 should win - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 2) }, - d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 2), - new SwitchPort(1L, 2, ErrorStatus.DUPLICATE_DEVICE)}, - d.getAttachmentPoints(true)); - - c.add(Calendar.MILLISECOND, Entity.ACTIVITY_TIMEOUT+1); - entity1.setLastSeenTimestamp(c.getTime()); - d = deviceManager.learnDeviceByEntity(entity1); - - // entities 3,4 are still in conflict, but 1 should be resolved - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 2) }, - d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 2)}, - d.getAttachmentPoints(true)); - - entity3.setLastSeenTimestamp(c.getTime()); - d = deviceManager.learnDeviceByEntity(entity3); - - // no conflicts, 1 and 3 will win - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 1) }, - d.getAttachmentPoints()); - assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1), - new SwitchPort(5L, 1) }, - d.getAttachmentPoints(true)); - - } - - protected void doTestDeviceQuery() throws Exception { - Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); - Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date()); - Entity entity3 = new Entity(3L, (short)3, 3, 5L, 1, new Date()); - Entity entity4 = new Entity(4L, (short)4, 3, 5L, 2, new Date()); - Entity entity5 = new Entity(1L, (short)4, 3, 5L, 2, new Date()); - - Device d1 = deviceManager.learnDeviceByEntity(entity1); - deviceManager.learnDeviceByEntity(entity2); - Device d3 = deviceManager.learnDeviceByEntity(entity3); - Device d4 = deviceManager.learnDeviceByEntity(entity4); - - IDevice d; - - Iterator<? extends IDevice> iter = - deviceManager.queryDevices(null, (short)1, 1, null, null); - int count = 0; - while (iter.hasNext()) { - count += 1; - d = iter.next(); - assertEquals(d1.getDeviceKey(), d.getDeviceKey()); - } - assertEquals(1, count); - - iter = deviceManager.queryDevices(null, (short)3, 3, null, null); - count = 0; - while (iter.hasNext()) { - count += 1; - d = iter.next(); - assertEquals(d3.getDeviceKey(), d.getDeviceKey()); - } - assertEquals(1, count); - - iter = deviceManager.queryDevices(null, (short)1, 3, null, null); - count = 0; - while (iter.hasNext()) { - count += 1; - iter.next(); - } - assertEquals(0, count); - - Device d5 = deviceManager.learnDeviceByEntity(entity5); - iter = deviceManager.queryDevices(null, (short)4, 3, null, null); - count = 0; - Set<Long> deviceKeysFromIterator = new HashSet<Long>(); - while (iter.hasNext()) { - count += 1; - d = iter.next(); - deviceKeysFromIterator.add(d.getDeviceKey()); - } - Set<Long> expectedDeviceKeys = new HashSet<Long>(); - expectedDeviceKeys.add(d4.getDeviceKey()); - expectedDeviceKeys.add(d5.getDeviceKey()); - assertEquals(expectedDeviceKeys, deviceKeysFromIterator); - assertEquals(2, count); - - - iter = deviceManager.queryDevices(1L, null, null, null, null); - count = 0; - deviceKeysFromIterator = new HashSet<Long>(); - while (iter.hasNext()) { - count += 1; - d = iter.next(); - deviceKeysFromIterator.add(d.getDeviceKey()); - } - expectedDeviceKeys = new HashSet<Long>(); - expectedDeviceKeys.add(d1.getDeviceKey()); - expectedDeviceKeys.add(d5.getDeviceKey()); - assertEquals(expectedDeviceKeys, deviceKeysFromIterator); - assertEquals(2, count); - } - - @Test - public void testDeviceIndex() throws Exception { - EnumSet<IDeviceService.DeviceField> indexFields = - EnumSet.noneOf(IDeviceService.DeviceField.class); - indexFields.add(IDeviceService.DeviceField.IPV4); - indexFields.add(IDeviceService.DeviceField.VLAN); - deviceManager.addIndex(false, indexFields); - - indexFields = EnumSet.noneOf(IDeviceService.DeviceField.class); - deviceManager.addIndex(false, indexFields); - - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); - replay(mockTopology); - doTestDeviceQuery(); - } - - @Test - public void testDeviceQuery() throws Exception { - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); - replay(mockTopology); - - doTestDeviceQuery(); - } - - protected void doTestDeviceClassQuery() throws Exception { - Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); - Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date()); - Entity entity3 = new Entity(3L, (short)3, 3, 5L, 1, new Date()); - Entity entity4 = new Entity(4L, (short)4, 3, 5L, 2, new Date()); - Entity entity5 = new Entity(1L, (short)4, 3, 5L, 2, new Date()); - - IDevice d1 = deviceManager.learnDeviceByEntity(entity1); - IDevice d2 = deviceManager.learnDeviceByEntity(entity2); - IDevice d3 = deviceManager.learnDeviceByEntity(entity3); - IDevice d4 = deviceManager.learnDeviceByEntity(entity4); - assertEquals(d1.getEntityClass(), d2.getEntityClass()); - assertEquals(d1.getEntityClass(), d3.getEntityClass()); - assertEquals(d1.getEntityClass(), d4.getEntityClass()); - - IDevice d; - - Iterator<? extends IDevice> iter = - deviceManager.queryClassDevices(d1.getEntityClass(), null, - (short)1, 1, null, null); - int count = 0; - while (iter.hasNext()) { - count += 1; - d = iter.next(); - assertEquals(d1.getDeviceKey(), d.getDeviceKey()); - } - assertEquals(1, count); - - iter = deviceManager.queryClassDevices(d1.getEntityClass(), null, - (short)3, 3, null, null); - count = 0; - while (iter.hasNext()) { - count += 1; - d = iter.next(); - assertEquals(d3.getDeviceKey(), d.getDeviceKey()); - - } - assertEquals(1, count); - - iter = deviceManager.queryClassDevices(d1.getEntityClass(), null, - (short)1, 3, null, null); - count = 0; - while (iter.hasNext()) { - count += 1; - iter.next(); - } - assertEquals(0, count); - - IDevice d5 = deviceManager.learnDeviceByEntity(entity5); - assertEquals(d1.getEntityClass(), d5.getEntityClass()); - iter = deviceManager.queryClassDevices(d1.getEntityClass(), null, - (short)4, 3, null, null); - count = 0; - Set<Long> deviceKeysFromIterator = new HashSet<Long>(); - while (iter.hasNext()) { - count += 1; - d = iter.next(); - deviceKeysFromIterator.add(d.getDeviceKey()); - } - Set<Long> expectedDeviceKeys = new HashSet<Long>(); - expectedDeviceKeys.add(d4.getDeviceKey()); - expectedDeviceKeys.add(d5.getDeviceKey()); - assertEquals(expectedDeviceKeys, deviceKeysFromIterator); - assertEquals(2, count); - } - - @Test - public void testDeviceClassIndex() throws Exception { - EnumSet<IDeviceService.DeviceField> indexFields = - EnumSet.noneOf(IDeviceService.DeviceField.class); - indexFields.add(IDeviceService.DeviceField.IPV4); - indexFields.add(IDeviceService.DeviceField.VLAN); - deviceManager.addIndex(true, indexFields); - - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); - replay(mockTopology); - - doTestDeviceClassQuery(); - } - - @Test - public void testDeviceClassQuery() throws Exception { - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); - replay(mockTopology); - - doTestDeviceClassQuery(); - } - - @Test - public void testFindDevice() throws FloodlightModuleException { - boolean exceptionCaught; - deviceManager.entityClassifier= new MockEntityClassifierMac(); - deviceManager.startUp(null); - - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); - replay(mockTopology); - - Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); - Entity entity2 = new Entity(2L, (short)2, 2, 1L, 2, new Date()); - Entity entity2b = new Entity(22L, (short)2, 2, 1L, 2, new Date()); - - Entity entity3 = new Entity(3L, (short)1, 3, 2L, 1, new Date()); - Entity entity4 = new Entity(4L, (short)2, 4, 2L, 2, new Date()); - - Entity entity5 = new Entity(5L, (short)1, 5, 3L, 1, new Date()); - - - IDevice d1 = deviceManager.learnDeviceByEntity(entity1); - IDevice d2 = deviceManager.learnDeviceByEntity(entity2); - IDevice d3 = deviceManager.learnDeviceByEntity(entity3); - IDevice d4 = deviceManager.learnDeviceByEntity(entity4); - IDevice d5 = deviceManager.learnDeviceByEntity(entity5); - - // Make sure the entity classifier worked as expected - assertEquals(MockEntityClassifierMac.testECMac1, d1.getEntityClass()); - assertEquals(MockEntityClassifierMac.testECMac1, d2.getEntityClass()); - assertEquals(MockEntityClassifierMac.testECMac2, d3.getEntityClass()); - assertEquals(MockEntityClassifierMac.testECMac2, d4.getEntityClass()); - assertEquals(DefaultEntityClassifier.entityClass, - d5.getEntityClass()); - - // Look up the device using findDevice() which uses only the primary - // index - assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(), - entity1.getVlan(), - entity1.getIpv4Address(), - entity1.getSwitchDPID(), - entity1.getSwitchPort())); - // port changed. Device will be found through class index - assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(), - entity1.getVlan(), - entity1.getIpv4Address(), - entity1.getSwitchDPID(), - entity1.getSwitchPort()+1)); - // VLAN changed. No device matches - assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(), - (short)42, - entity1.getIpv4Address(), - entity1.getSwitchDPID(), - entity1.getSwitchPort())); - assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(), - null, - entity1.getIpv4Address(), - entity1.getSwitchDPID(), - entity1.getSwitchPort())); - assertEquals(d2, deviceManager.findDeviceByEntity(entity2)); - assertEquals(null, deviceManager.findDeviceByEntity(entity2b)); - assertEquals(d3, deviceManager.findDevice(entity3.getMacAddress(), - entity3.getVlan(), - entity3.getIpv4Address(), - entity3.getSwitchDPID(), - entity3.getSwitchPort())); - // switch and port not set. throws exception - exceptionCaught = false; - try { - assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(), - entity3.getVlan(), - entity3.getIpv4Address(), - null, - null)); - } - catch (IllegalArgumentException e) { - exceptionCaught = true; - } - if (!exceptionCaught) - fail("findDevice() did not throw IllegalArgumentException"); - assertEquals(d4, deviceManager.findDeviceByEntity(entity4)); - assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), - entity5.getVlan(), - entity5.getIpv4Address(), - entity5.getSwitchDPID(), - entity5.getSwitchPort())); - // switch and port not set. throws exception (swith/port are key - // fields of IEntityClassifier but not d5.entityClass - exceptionCaught = false; - try { - assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), - entity5.getVlan(), - entity5.getIpv4Address(), - null, - null)); - } - catch (IllegalArgumentException e) { - exceptionCaught = true; - } - if (!exceptionCaught) - fail("findDevice() did not throw IllegalArgumentException"); - - - Entity entityNoClass = new Entity(5L, (short)1, 5, -1L, 1, new Date()); - assertEquals(null, deviceManager.findDeviceByEntity(entityNoClass)); - - - // Now look up destination devices - assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), - entity1.getMacAddress(), - entity1.getVlan(), - entity1.getIpv4Address())); - assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), - entity1.getMacAddress(), - entity1.getVlan(), - null)); - assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(), - entity1.getMacAddress(), - (short) -1, - 0)); - } - - - - @Test - public void testGetIPv4Addresses() { - // Looks like Date is only 1s granularity - - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes(); - expect(mockTopology.isConsistent(EasyMock.anyLong(), - EasyMock.anyShort(), - EasyMock.anyLong(), - EasyMock.anyShort())) - .andReturn(false) - .anyTimes(); - expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), - EasyMock.anyShort())) - .andReturn(false) - .anyTimes(); - expect(mockTopology.isInSameBroadcastDomain(EasyMock.anyLong(), - EasyMock.anyShort(), - EasyMock.anyLong(), - EasyMock.anyShort())). - andReturn(false).anyTimes(); - replay(mockTopology); - - Entity e1 = new Entity(1L, (short)1, null, null, null, new Date(2000)); - Device d1 = deviceManager.learnDeviceByEntity(e1); - assertArrayEquals(new Integer[0], d1.getIPv4Addresses()); - - - Entity e2 = new Entity(2L, (short)2, 2, null, null, new Date(2000)); - Device d2 = deviceManager.learnDeviceByEntity(e2); - d2 = deviceManager.learnDeviceByEntity(e2); - assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); - // More than one entity - Entity e2b = new Entity(2L, (short)2, null, 2L, 2, new Date(3000)); - d2 = deviceManager.learnDeviceByEntity(e2b); - assertEquals(2, d2.entities.length); - assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); - // and now add an entity with an IP - Entity e2c = new Entity(2L, (short)2, 2, 2L, 3, new Date(3000)); - d2 = deviceManager.learnDeviceByEntity(e2c); - assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); - assertEquals(3, d2.entities.length); - - // Other devices with different IPs shouldn't interfere - Entity e3 = new Entity(3L, (short)3, 3, null, null, new Date(4000)); - Entity e3b = new Entity(3L, (short)3, 3, 3L, 3, new Date(4400)); - Device d3 = deviceManager.learnDeviceByEntity(e3); - d3 = deviceManager.learnDeviceByEntity(e3b); - assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); - assertArrayEquals(new Integer[] { 3 }, d3.getIPv4Addresses()); - - // Add another IP to d3 - Entity e3c = new Entity(3L, (short)3, 33, 3L, 3, new Date(4400)); - d3 = deviceManager.learnDeviceByEntity(e3c); - Integer[] ips = d3.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 3, 33 }, ips); - - // Add another device that also claims IP2 but is older than e2 - Entity e4 = new Entity(4L, (short)4, 2, null, null, new Date(1000)); - Entity e4b = new Entity(4L, (short)4, null, 4L, 4, new Date(1000)); - Device d4 = deviceManager.learnDeviceByEntity(e4); - assertArrayEquals(new Integer[] { 2 }, d2.getIPv4Addresses()); - assertArrayEquals(new Integer[0], d4.getIPv4Addresses()); - // add another entity to d4 - d4 = deviceManager.learnDeviceByEntity(e4b); - assertArrayEquals(new Integer[0], d4.getIPv4Addresses()); - - // Make e4 and e4a newer - Entity e4c = new Entity(4L, (short)4, 2, null, null, new Date(5000)); - Entity e4d = new Entity(4L, (short)4, null, 4L, 5, new Date(5000)); - d4 = deviceManager.learnDeviceByEntity(e4c); - d4 = deviceManager.learnDeviceByEntity(e4d); - assertArrayEquals(new Integer[0], d2.getIPv4Addresses()); - // FIXME: d4 should not return IP4 - assertArrayEquals(new Integer[] { 2 }, d4.getIPv4Addresses()); - - // Add another newer entity to d2 but with different IP - Entity e2d = new Entity(2L, (short)2, 22, 4L, 6, new Date(6000)); - d2 = deviceManager.learnDeviceByEntity(e2d); - assertArrayEquals(new Integer[] { 22 }, d2.getIPv4Addresses()); - assertArrayEquals(new Integer[] { 2 }, d4.getIPv4Addresses()); - - // new IP for d2,d4 but with same timestamp. Both devices get the IP - Entity e2e = new Entity(2L, (short)2, 42, 2L, 4, new Date(7000)); - d2 = deviceManager.learnDeviceByEntity(e2e); - ips= d2.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 22, 42 }, ips); - Entity e4e = new Entity(4L, (short)4, 42, 4L, 7, new Date(7000)); - d4 = deviceManager.learnDeviceByEntity(e4e); - ips= d4.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 2, 42 }, ips); - - // add a couple more IPs - Entity e2f = new Entity(2L, (short)2, 4242, 2L, 5, new Date(8000)); - d2 = deviceManager.learnDeviceByEntity(e2f); - ips= d2.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 22, 42, 4242 }, ips); - Entity e4f = new Entity(4L, (short)4, 4242, 4L, 8, new Date(9000)); - d4 = deviceManager.learnDeviceByEntity(e4f); - ips= d4.getIPv4Addresses(); - Arrays.sort(ips); - assertArrayEquals(new Integer[] { 2, 42, 4242 }, ips); - } - - // TODO: this test should really go into a separate class that collects - // unit tests for Device - @Test - public void testGetSwitchPortVlanId() { - Entity entity1 = new Entity(1L, (short)1, null, 10L, 1, new Date()); - Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date()); - Entity entity3 = new Entity(1L, (short)3, null, 1L, 1, new Date()); - Entity entity4 = new Entity(1L, (short)42, null, 1L, 1, new Date()); - Entity[] entities = new Entity[] { entity1, entity2, - entity3, entity4 - }; - Device d = new Device(null,1L, null, null, null, - Arrays.asList(entities), null); - SwitchPort swp1x1 = new SwitchPort(1L, 1); - SwitchPort swp1x2 = new SwitchPort(1L, 2); - SwitchPort swp2x1 = new SwitchPort(2L, 1); - SwitchPort swp10x1 = new SwitchPort(10L, 1); - assertArrayEquals(new Short[] { -1, 1}, - d.getSwitchPortVlanIds(swp10x1)); - assertArrayEquals(new Short[] { 3, 42}, - d.getSwitchPortVlanIds(swp1x1)); - assertArrayEquals(new Short[0], - d.getSwitchPortVlanIds(swp1x2)); - assertArrayEquals(new Short[0], - d.getSwitchPortVlanIds(swp2x1)); - } - - @Test - public void testReclassifyDevice() throws FloodlightModuleException { - MockFlexEntityClassifier flexClassifier = - new MockFlexEntityClassifier(); - deviceManager.entityClassifier= flexClassifier; - deviceManager.startUp(null); - - ITopologyService mockTopology = createMock(ITopologyService.class); - deviceManager.topology = mockTopology; - expect(mockTopology.isAttachmentPointPort(anyLong(), - anyShort())). - andReturn(true).anyTimes(); - expect(mockTopology.getL2DomainId(anyLong())).andReturn(1L).anyTimes(); - expect(mockTopology.isConsistent(EasyMock.anyLong(), - EasyMock.anyShort(), - EasyMock.anyLong(), - EasyMock.anyShort())) - .andReturn(false) - .anyTimes(); - expect(mockTopology.isBroadcastDomainPort(EasyMock.anyLong(), - EasyMock.anyShort())) - .andReturn(false) - .anyTimes(); - replay(mockTopology); - - //flexClassifier.createTestEntityClass("Class1"); - - Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); - Entity entity1b = new Entity(1L, (short)2, 1, 1L, 1, new Date()); - Entity entity2 = new Entity(2L, (short)1, 2, 2L, 2, new Date()); - Entity entity2b = new Entity(2L, (short)2, 2, 2L, 2, new Date()); - - - Device d1 = deviceManager.learnDeviceByEntity(entity1); - Device d2 = deviceManager.learnDeviceByEntity(entity2); - Device d1b = deviceManager.learnDeviceByEntity(entity1b); - Device d2b = deviceManager.learnDeviceByEntity(entity2b); - - d1 = deviceManager.getDeviceIteratorForQuery(entity1.getMacAddress(), - entity1.getVlan(), entity1.getIpv4Address(), - entity1.getSwitchDPID(), entity1.getSwitchPort()) - .next(); - d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(), - entity1b.getVlan(), entity1b.getIpv4Address(), - entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next(); - - assertEquals(d1, d1b); - - d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(), - entity2.getVlan(), entity2.getIpv4Address(), - entity2.getSwitchDPID(), entity2.getSwitchPort()).next(); - d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(), - entity2b.getVlan(), entity2b.getIpv4Address(), - entity2b.getSwitchDPID(), entity2b.getSwitchPort()).next(); - assertEquals(d2, d2b); - - IEntityClass eC1 = flexClassifier.createTestEntityClass("C1"); - IEntityClass eC2 = flexClassifier.createTestEntityClass("C2"); - - flexClassifier.addVlanEntities((short)1, eC1); - flexClassifier.addVlanEntities((short)2, eC1); - - deviceManager.reclassifyDevice(d1); - deviceManager.reclassifyDevice(d2); - - d1 = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity1)); - d1b = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity1b)); - - assertEquals(d1, d1b); - - d2 = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity2)); - d2b = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity2b)); - - assertEquals(d2, d2b); - - flexClassifier.addVlanEntities((short)1, eC2); - - deviceManager.reclassifyDevice(d1); - deviceManager.reclassifyDevice(d2); - d1 = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity1)); - d1b = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity1b)); - d2 = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity2)); - d2b = deviceManager.deviceMap.get( - deviceManager.primaryIndex.findByEntity(entity2b)); - - assertNotSame(d1, d1b); - - assertNotSame(d2, d2b); - - flexClassifier.addVlanEntities((short)1, eC1); - deviceManager.reclassifyDevice(d1); - deviceManager.reclassifyDevice(d2); - ClassState classState = deviceManager.classStateMap.get(eC1.getName()); - - Long deviceKey1 = null; - Long deviceKey1b = null; - Long deviceKey2 = null; - Long deviceKey2b = null; - - deviceKey1 = - classState.classIndex.findByEntity(entity1); - deviceKey1b = - classState.classIndex.findByEntity(entity1b); - deviceKey2 = - classState.classIndex.findByEntity(entity2); - deviceKey2b = - classState.classIndex.findByEntity(entity2b); - - assertEquals(deviceKey1, deviceKey1b); - - assertEquals(deviceKey2, deviceKey2b); - } - - @Test - public void testSyncEntity() { - Date d1 = new Date(); - Date d2 = new Date(0); - Entity e1 = new Entity(1L, (short)2, 3, 4L, 5, d1); - e1.setActiveSince(d2); - SyncEntity se1 = new SyncEntity(e1); - assertEntityEquals(e1, se1); - assertEquals(1L, se1.macAddress); - assertEquals(Short.valueOf((short)2), se1.vlan); - assertEquals(Integer.valueOf(3), se1.ipv4Address); - assertEquals(Long.valueOf(4L), se1.switchDPID); - assertEquals(Integer.valueOf(5), se1.switchPort); - assertEquals(d1, se1.lastSeenTimestamp); - assertEquals(d2, se1.activeSince); - assertNotSame(d1, se1.lastSeenTimestamp); - assertNotSame(d2, se1.activeSince); - - Entity e2 = new Entity(42L, null, null, null, null, null); - SyncEntity se2 = new SyncEntity(e2); - assertEntityEquals(e2, se2); - - SyncEntity se3 = new SyncEntity(); - SyncEntity se4 = new SyncEntity(); - se3.lastSeenTimestamp = new Date(1000); - se4.lastSeenTimestamp = new Date(2000); - assertTrue("", se3.compareTo(se4) < 0); - assertTrue("", se4.compareTo(se3) > 0); - se4.lastSeenTimestamp = new Date(1000); - assertTrue("", se3.compareTo(se4) == 0); - assertTrue("", se4.compareTo(se3) == 0); - se4.lastSeenTimestamp = new Date(500); - assertTrue("", se3.compareTo(se4) > 0); - assertTrue("", se4.compareTo(se3) < 0); - } - - /* Test basic DeviceSyncRepresentation behavior */ - @Test - public void testDeviceSyncRepresentationBasics() { - DeviceSyncRepresentation dsr = new DeviceSyncRepresentation(); - assertNull(dsr.getKey()); - assertNull(dsr.getEntities()); - dsr.setKey("MyKey"); - assertEquals("MyKey", dsr.getKey()); - assertEquals("MyKey", dsr.toString()); - - List<SyncEntity> entities = new ArrayList<SyncEntity>(); - Entity e1a = new Entity(1L, (short)2, 3, 4L, 5, new Date(1000)); - Entity e1b = new Entity(1L, (short)2, null, 4L, 5, new Date(0)); - entities.add(new SyncEntity(e1a)); - entities.add(new SyncEntity(e1b)); - // e1b comes before e1 (lastSeen) but we add it after it to test - // sorting - dsr.setEntities(entities); - - assertEquals(2, dsr.getEntities().size()); - // e1b has earlier time - assertEquals(e1b, dsr.getEntities().get(0).asEntity()); - assertEquals(e1a, dsr.getEntities().get(1).asEntity()); - - dsr.setKey(null); - dsr.setEntities(null); - assertNull(dsr.getKey()); - assertNull(dsr.getEntities()); - } - - @Test - public void testDeviceSyncRepresentationFromDevice() { - ITopologyService mockTopology = makeMockTopologyAllPortsAp(); - replay(mockTopology); - deviceManager.topology = mockTopology; - - deviceManager.entityClassifier = new MockEntityClassifier(); - - //************************************** - // Test 1: a single entity - Entity e1 = new Entity(1L, (short)2, 3, 4L, 5, new Date(1000)); - Device d1 = deviceManager.learnDeviceByEntity(e1); - assertEquals("Sanity check failed. Device doesn't have the expected " + - "entity class. Something with the test setup is strange", - "DefaultEntityClass", d1.getEntityClass().getName()); - assertEquals("Sanity check failed. Device doesn't have the expected " + - "entity class. Something with the test setup is strange", - EnumSet.of(DeviceField.MAC, DeviceField.VLAN), - d1.getEntityClass().getKeyFields()); - - Long deviceKey = d1.getDeviceKey(); - DeviceSyncRepresentation dsr1 = new DeviceSyncRepresentation(d1); - assertEquals("DefaultEntityClass::00:00:00:00:00:01::[2]::", - dsr1.getKey()); - assertEquals(1, dsr1.getEntities().size()); - assertEquals(e1, dsr1.getEntities().get(0).asEntity()); - - //************************************** - // Test 1b: same device, now with a second entity (no IP). - // this second entity has a lastSeen time that is earlier than the - // first entity - Entity e1b = new Entity(1L, (short)2, null, 4L, 5, new Date(0)); - d1 = deviceManager.learnDeviceByEntity(e1b); - assertEquals("Sanity check failed. Should still be same device but " + - "deviceKeys differs", deviceKey, d1.getDeviceKey()); - dsr1 = new DeviceSyncRepresentation(d1); - assertEquals("DefaultEntityClass::00:00:00:00:00:01::[2]::", - dsr1.getKey()); - assertEquals(2, dsr1.getEntities().size()); - // Entities are ordered by their lastSeen time. e1b should come - // before e1. - assertEquals(e1, dsr1.getEntities().get(1).asEntity()); - assertEquals(e1b, dsr1.getEntities().get(0).asEntity()); - - //************************************** - // Test 1c: same device with a third entity that does not have a - // switch port. It should be added to the DeviceSyncRepresentation - Entity e1c = new Entity(1L, (short)2, 33, null, null, new Date(2000)); - d1 = deviceManager.learnDeviceByEntity(e1c); - assertEquals("Sanity check failed. Should still be same device but " + - "deviceKeys differs", deviceKey, d1.getDeviceKey()); - dsr1 = new DeviceSyncRepresentation(d1); - assertEquals("DefaultEntityClass::00:00:00:00:00:01::[2]::", - dsr1.getKey()); - assertEquals(3, dsr1.getEntities().size()); - // Entities are ordered by their lastSeen time - assertEquals(e1c, dsr1.getEntities().get(2).asEntity()); - assertEquals(e1, dsr1.getEntities().get(1).asEntity()); - assertEquals(e1b, dsr1.getEntities().get(0).asEntity()); - - //************************************** - // Test 1d: same device with a fourth entity that has a different - // attachment point and that is newer. Device should move and - // non-attachment point entities should be removed (e1b). Although - // e1 is non-attachment point it will remain because it has an IP - Entity e1d = new Entity(1L, (short)2, 33, 4L, 6, new Date(3000)); - d1 = deviceManager.learnDeviceByEntity(e1d); - assertEquals("Sanity check failed. Should still be same device but " + - "deviceKeys differs", deviceKey, d1.getDeviceKey()); - dsr1 = new DeviceSyncRepresentation(d1); - assertEquals("DefaultEntityClass::00:00:00:00:00:01::[2]::", - dsr1.getKey()); - assertEquals(3, dsr1.getEntities().size()); - assertEquals(e1, dsr1.getEntities().get(0).asEntity()); - assertEquals(e1c, dsr1.getEntities().get(1).asEntity()); - assertEquals(e1d, dsr1.getEntities().get(2).asEntity()); - - d1 = null; - - - //************************************** - // Test 2: a second device with a different entity class. The - // mock entity classifier will return an entity class where all - // fields are keys if the DPID is > 10L - Entity e2 = new Entity(2L, (short)23, 24, 11L, 1, new Date(0)); - Device d2 = deviceManager.learnDeviceByEntity(e2); - DeviceSyncRepresentation dsr2 = new DeviceSyncRepresentation(d2); - assertEquals("Sanity check failed. Device doesn't have the expected " + - "entity class. Something with the test setup is strange", - "TestEntityClass", d2.getEntityClass().getName()); - assertEquals("Sanity check failed. Device doesn't have the expected " + - "entity class. Something with the test setup is strange", - EnumSet.of(DeviceField.MAC, DeviceField.VLAN, - DeviceField.SWITCH, DeviceField.PORT), - d2.getEntityClass().getKeyFields()); - SwitchPort swp = new SwitchPort(11L, 1, null); - assertEquals("TestEntityClass::00:00:00:00:00:02::[23]::[" + - swp.toString() + "]::", - dsr2.getKey()); - } - - /* interate through all entries in the sync store and return them as - * list. We don't return the key from the store however, we assert - * that the key from the store matches the key in the representation. - * If we have a null value (tombstone) we simply add the null value to - * the list to return. - */ - private List<DeviceSyncRepresentation> getEntriesFromStore() - throws Exception { - List<DeviceSyncRepresentation> entries = - new ArrayList<DeviceSyncRepresentation>(); - IClosableIterator<Entry<String, Versioned<DeviceSyncRepresentation>>> iter = - storeClient.entries(); - try { - while(iter.hasNext()) { - Entry<String, Versioned<DeviceSyncRepresentation>> entry = - iter.next(); - DeviceSyncRepresentation dsr = entry.getValue().getValue(); - if (dsr != null) - assertEquals(entry.getKey(), dsr.getKey()); - entries.add(dsr); - } - } finally { - if (iter != null) - iter.close(); - } - return entries; - } - - /* - * assert whether the given Entity expected is equals to the given - * SyncEntity actual. This method also compares the times (lastSeen, - * activeSince). Entity.equals will not do that! - */ - private static void assertEntityEquals(Entity expected, SyncEntity actual) { - assertNotNull(actual); - assertNotNull(expected); - Entity actualEntity = actual.asEntity(); - assertEquals("entityFields", expected, actualEntity); - assertEquals("lastSeenTimestamp", - expected.getLastSeenTimestamp(), - actualEntity.getLastSeenTimestamp()); - assertEquals("activeSince", - expected.getActiveSince(), actualEntity.getActiveSince()); - } - - /* This test tests the normal operation as master when we write to the sync - * store or delete from the store. - */ - @Test - public void testWriteToSyncStore() throws Exception { - int syncStoreIntervalMs = 50; - ITopologyService mockTopology = makeMockTopologyAllPortsAp(); - replay(mockTopology); - deviceManager.topology = mockTopology; - deviceManager.setSyncStoreWriteInterval(syncStoreIntervalMs); - - Entity e1a = new Entity(1L, (short)2, 3, 4L, 5, new Date(1000)); - e1a.setActiveSince(new Date(0)); - deviceManager.learnDeviceByEntity(e1a); - - //storeClient.put("FooBar", new DeviceSyncRepresentation()); - - List<DeviceSyncRepresentation> entries = getEntriesFromStore(); - assertEquals(1, entries.size()); - DeviceSyncRepresentation dsr1 = entries.get(0); - assertEquals(1, dsr1.getEntities().size()); - assertEntityEquals(e1a, dsr1.getEntities().get(0)); - - // Same entity but newer timestamp. Since the device hasn't changed, - // only the timestamp is updated and the write should be throttled. - Entity e1b = new Entity(1L, (short)2, 3, 4L, 5, new Date(2000)); - e1b.setActiveSince(new Date(0)); - deviceManager.learnDeviceByEntity(e1a); - entries = getEntriesFromStore(); - assertEquals(1, entries.size()); - dsr1 = entries.get(0); - assertEquals(1, dsr1.getEntities().size()); - assertEntityEquals(e1a, dsr1.getEntities().get(0)); //e1a not e1b !!! - - // Wait for the write interval to expire then write again. - Thread.sleep(syncStoreIntervalMs+5); - Entity e1c = new Entity(1L, (short)2, 3, 4L, 5, new Date(3000)); - e1c.setActiveSince(new Date(0)); - deviceManager.learnDeviceByEntity(e1c); - entries = getEntriesFromStore(); - assertEquals(1, entries.size()); - dsr1 = entries.get(0); - assertEquals(1, dsr1.getEntities().size()); - assertEntityEquals(e1c, dsr1.getEntities().get(0)); // e1c !! - - // Entity for same device but with different IP. should be added - // immediately - Entity e1d = new Entity(1L, (short)2, 33, 4L, 5, new Date(4000)); - e1d.setActiveSince(new Date(0)); - deviceManager.learnDeviceByEntity(e1d); - entries = getEntriesFromStore(); - assertEquals(1, entries.size()); - dsr1 = entries.get(0); - assertEquals(2, dsr1.getEntities().size()); - assertEntityEquals(e1c, dsr1.getEntities().get(0)); // e1c !! - assertEntityEquals(e1d, dsr1.getEntities().get(1)); // e1d !! - - // Entity for same device with new switch port ==> moved ==> write - // update immediately without throttle. - // Note: the previous entities will still be there because they have - // IPs (even though they aren't for the current attachment point) - Entity e1e = new Entity(1L, (short)2, 33, 4L, 6, new Date(5000)); - e1e.setActiveSince(new Date(0)); - deviceManager.learnDeviceByEntity(e1e); - entries = getEntriesFromStore(); - assertEquals(1, entries.size()); - dsr1 = entries.get(0); - assertEquals(3, dsr1.getEntities().size()); - assertEntityEquals(e1c, dsr1.getEntities().get(0)); - assertEntityEquals(e1d, dsr1.getEntities().get(1)); - assertEntityEquals(e1e, dsr1.getEntities().get(2)); - - // Add a second device - Entity e2 = new Entity(2L, null, null, 5L, 5, new Date()); - deviceManager.learnDeviceByEntity(e2); - entries = getEntriesFromStore(); - assertEquals(2, entries.size()); - for (DeviceSyncRepresentation dsr: entries) { - // This is a kinda ugly way to ensure we have the two - // devices we need..... but it will work for now - if (dsr.getKey().contains("::00:00:00:00:00:01::")) { - assertEquals(3, dsr.getEntities().size()); - assertEntityEquals(e1c, dsr.getEntities().get(0)); - assertEntityEquals(e1d, dsr.getEntities().get(1)); - assertEntityEquals(e1e, dsr.getEntities().get(2)); - } else if (dsr.getKey().contains("::00:00:00:00:00:02::")) { - assertEquals(1, dsr.getEntities().size()); - assertEntityEquals(e2, dsr.getEntities().get(0)); - } else { - fail("Unknown entry in store: " + dsr); - } - } - - - // Run entity cleanup. Since we've used phony time stamps for - // device 1 its entities should be cleared and the device should be - // removed from the store. Device 2 should remain in the store. - deviceManager.cleanupEntities(); - entries = getEntriesFromStore(); - assertEquals(2, entries.size()); - for (DeviceSyncRepresentation dsr: entries) { - if (dsr == null) { - // pass - } else if (dsr.getKey().contains("::00:00:00:00:00:02::")) { - assertEquals(1, dsr.getEntities().size()); - assertEntityEquals(e2, dsr.getEntities().get(0)); - } else { - fail("Unknown entry in store: " + dsr); - } - } - } - - - private void assertDeviceIps(Integer[] expected, IDevice d) { - List<Integer> expectedList = Arrays.asList(expected); - Collections.sort(expectedList); - List<Integer> actualList = Arrays.asList(d.getIPv4Addresses()); - Collections.sort(actualList); - assertEquals(expectedList, actualList); - } - - private IDevice getSingleDeviceFromDeviceManager(long mac) { - Iterator<? extends IDevice> diter = - deviceManager.queryDevices(mac, null, null, null, null); - assertTrue("Query didn't return a device", diter.hasNext()); - IDevice d = diter.next(); - assertFalse("Query returned more than one device", diter.hasNext()); - return d; - } - - @Test - public void testToMaster() throws Exception { - int syncStoreWriteIntervalMs = 0; - int initialSyncStoreConsolidateIntervalMs = 50; - ITopologyService mockTopology = makeMockTopologyAllPortsAp(); - replay(mockTopology); - deviceManager.topology = mockTopology; - // We want an EntityClassifier that has switch/port as key fields - deviceManager.entityClassifier = new MockEntityClassifier(); - deviceManager.setSyncStoreWriteInterval(syncStoreWriteIntervalMs); - deviceManager.setInitialSyncStoreConsolidateMs(initialSyncStoreConsolidateIntervalMs); - - // Add Device1 with two entities with two different IPs - Entity e1a = new Entity(1L, null, 3, 4L, 5, new Date(1000)); - Entity e1b = new Entity(1L, null, 33, 4L, 5, new Date(2000)); - Device d1 = deviceManager.allocateDevice(1L, e1a, - DefaultEntityClassifier.entityClass); - d1 = deviceManager.allocateDevice(d1, e1b, -1); - DeviceSyncRepresentation dsr = new DeviceSyncRepresentation(d1); - storeClient.put(dsr.getKey(), dsr); - - // Add Device2 with different switch-ports. Only the most recent - // one should be the attachment point - Entity e2a = new Entity(2L, null, null, 4L, 4, new Date(1000)); - Entity e2b = new Entity(2L, null, null, 4L, 5, new Date(2000)); - Device d2 = deviceManager.allocateDevice(2L, e2a, - DefaultEntityClassifier.entityClass); - d2 = deviceManager.allocateDevice(d2, e2b, -1); - d2.updateAttachmentPoint(4L, (short)5, - e2b.getLastSeenTimestamp().getTime()); - SwitchPort swp = new SwitchPort(4L, 5); - SwitchPort[] aps = d2.getAttachmentPoints(); - // sanity check - assertArrayEquals("Sanity check: should only have AP(4L,5)", - new SwitchPort[] {swp}, aps); - dsr = new DeviceSyncRepresentation(d2); - storeClient.put(dsr.getKey(), dsr); - - // Add a tombstone entry to the store to make sure we don't trip a - // NPE - dsr = null; - Versioned<DeviceSyncRepresentation> versionedDsr = - storeClient.get("FooBar"); - storeClient.put("FooBar", versionedDsr); - - deviceManager.getHAListener().transitionToMaster(); - - // Query for the Device1. Make sure we have the two IPs we stored. - IDevice d = getSingleDeviceFromDeviceManager(1L); - assertDeviceIps(new Integer[] {3, 33}, d); - assertArrayEquals(new Short[] { Ethernet.VLAN_UNTAGGED }, d.getVlanId()); - swp = new SwitchPort(4L, 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 Short[] { Ethernet.VLAN_UNTAGGED }, d.getVlanId()); - swp = new SwitchPort(4L, 5); - assertArrayEquals(new SwitchPort[] { swp }, d.getAttachmentPoints()); - - //---------------------------- - // add another entry device to the store. since device manager is - // already master we won't read this device and it should be - // removed from the store by the consolidate task - Entity e3 = new Entity(3L, null, null, 1L, 1, null); - dsr = new DeviceSyncRepresentation(); - dsr.setKey("Device3"); - dsr.setEntities(Collections.singletonList(new SyncEntity(e3))); - storeClient.put(dsr.getKey(), dsr); - - // make sure it's in the store - List<DeviceSyncRepresentation> entries = getEntriesFromStore(); - boolean found = false; - for (DeviceSyncRepresentation entry: entries) { - if (entry!=null && entry.getKey().equals("Device3")) - found = true; - } - assertTrue("Device3 not in store. Entries in store: " + entries, found); - // make sure it's not in DevManager - Iterator<? extends IDevice> diter = - deviceManager.queryDevices(3L, null, null, null, null); - assertFalse("Device3 found in DeviceManager. Should be there", - diter.hasNext()); - - // Wait for consolidate - Thread.sleep(initialSyncStoreConsolidateIntervalMs + 5); - // make sure it's in NOT the store - entries = getEntriesFromStore(); - found = false; - for (DeviceSyncRepresentation entry: entries) { - if (entry!=null && entry.getKey().equals("Device3")) - found = true; - } - assertFalse("Device3 not is still in the store. Entries in store: " - + entries, found); - // make sure it's not in DevManager - diter = deviceManager.queryDevices(3L, null, null, null, null); - assertFalse("Device3 found in DeviceManager. Should be there", - diter.hasNext()); - } - - - @Test - public void testConsolitateStore() throws Exception { - int syncStoreInternalMs = 0; - ITopologyService mockTopology = makeMockTopologyAllPortsAp(); - replay(mockTopology); - deviceManager.topology = mockTopology; - // We want an EntityClassifier that has switch/port as key fields - deviceManager.entityClassifier = new MockEntityClassifier(); - deviceManager.setSyncStoreWriteInterval(syncStoreInternalMs); - - // Add Device1 with two entities to store and let device manager - // learn - Entity e1a = new Entity(1L, null, null, 4L, 5, new Date(1000)); - Entity e1b = new Entity(1L, null, 3, 4L, 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(2L, null, null, 5L, 5, new Date()); - Device d2 = deviceManager.allocateDevice(42L, e2, - DefaultEntityClassifier.entityClass); - DeviceSyncRepresentation dsr = new DeviceSyncRepresentation(d2); - storeClient.put(dsr.getKey(), dsr); - String dev2Key = DeviceSyncRepresentation.computeKey(d2); - - // Make sure we have two devices in the store - List<DeviceSyncRepresentation> entries = getEntriesFromStore(); - assertEquals(2, entries.size()); - - deviceManager.scheduleConsolidateStoreNow(); - Thread.sleep(25); // give the scheduler time to run the task - - // We should still have two entries, however one of them will be a - // tombstone - entries = getEntriesFromStore(); - assertEquals(2, entries.size()); - - // Device 1 should still be in store - Versioned<DeviceSyncRepresentation> versioned = - storeClient.get(dev1Key); - dsr = versioned.getValue(); - assertNotNull(dsr); - assertEquals(2, dsr.getEntities().size()); - assertEntityEquals(e1a, dsr.getEntities().get(0)); - assertEntityEquals(e1b, dsr.getEntities().get(1)); - - // Device2 should be gone - versioned = storeClient.get(dev2Key); - assertNull(versioned.getValue()); - - // Run consolitate again. This time we check that tombstones in - // the store are handled correctly - deviceManager.scheduleConsolidateStoreNow(); - Thread.sleep(25); // give the scheduler time to run the task - - // Now write a device to the store that doesn't have any switch-port - // it should be removed - Entity e3 = new Entity(3L, null, null, null, null, null); - dsr.setKey("Device3"); - dsr.setEntities(Collections.singletonList(new SyncEntity(e3))); - storeClient.put(dsr.getKey(), dsr); - - // Run consolitate again. This time we check that tombstones in - // the store are handled correctly - deviceManager.scheduleConsolidateStoreNow(); - Thread.sleep(25); // give the scheduler time to run the task - versioned = storeClient.get("Device3"); - assertNull(versioned.getValue()); - - } - -} diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java deleted file mode 100644 index 1ac1f1c35d5a13601df137c7e4669bf605c76d8b..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndexTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/** -* Copyright 2012 Big Switch Networks, Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); you may -* not use this file except in compliance with the License. You may obtain -* a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -**/ - -package net.floodlightcontroller.devicemanager.internal; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Iterator; - -import org.junit.Test; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import junit.framework.TestCase; - -/** - * - * @author gregor - * - */ -public class DeviceUniqueIndexTest extends TestCase { - protected Entity e1a; - protected Entity e1b; - protected Device d1; - protected Entity e2; - protected Entity e2alt; - protected Entity e3; - protected Entity e4; - - @Override - protected void setUp() throws Exception { - super.setUp(); - e1a = new Entity(1L, (short)1, 1, 1L, 1, new Date()); - e1b = new Entity(1L, (short)2, 1, 1L, 1, new Date()); - List<Entity> d1Entities = new ArrayList<Entity>(2); - d1Entities.add(e1a); - d1Entities.add(e1b); - d1 = new Device(null, Long.valueOf(1), null, null, null, - d1Entities, null); - - // e2 and e2 alt match in MAC and VLAN - e2 = new Entity(2L, (short)2, 2, 2L, 2, new Date()); - e2alt = new Entity(2, (short)2, null, null, null, null); - - // IP is null - e3 = new Entity(3L, (short)3, null, 3L, 3, new Date()); - - // IP and switch and port are null - e4 = new Entity(4L, (short)4, null, null, null, new Date()); - } - - /* - * Checks that the iterator it returns the elements in the Set expected - * Doesn't check how often an element is returned as long it's at least - * once - */ - protected void verifyIterator(Set<Long> expected, Iterator<Long> it) { - HashSet<Long> actual = new HashSet<Long>(); - while (it.hasNext()) { - actual.add(it.next()); - } - assertEquals(expected, actual); - } - - @Test - public void testDeviceUniqueIndex() { - DeviceUniqueIndex idx1 = new DeviceUniqueIndex( - EnumSet.of(DeviceField.MAC, - DeviceField.VLAN)); - - idx1.updateIndex(d1, d1.getDeviceKey()); - idx1.updateIndex(e2, 2L); - - //------------- - // Test findByEntity lookups - assertEquals(Long.valueOf(1L), idx1.findByEntity(e1a)); - assertEquals(Long.valueOf(1L), idx1.findByEntity(e1b)); - assertEquals(Long.valueOf(2L), idx1.findByEntity(e2)); - // we didn't add e2alt but since they key fields are the same we - // should find it - assertEquals(Long.valueOf(2L), idx1.findByEntity(e2alt)); - assertEquals(null, idx1.findByEntity(e3)); - assertEquals(null, idx1.findByEntity(e4)); - - //------------- - // Test getAll() - HashSet<Long> expectedKeys = new HashSet<Long>(); - expectedKeys.add(1L); - expectedKeys.add(2L); - verifyIterator(expectedKeys, idx1.getAll()); - - - //------------- - // Test queryByEntity() - verifyIterator(Collections.<Long>singleton(1L), - idx1.queryByEntity(e1a)); - verifyIterator(Collections.<Long>singleton(1L), - idx1.queryByEntity(e1b)); - verifyIterator(Collections.<Long>singleton(2L), - idx1.queryByEntity(e2)); - verifyIterator(Collections.<Long>singleton(2L), - idx1.queryByEntity(e2alt)); - assertEquals(false, idx1.queryByEntity(e3).hasNext()); - assertEquals(false, idx1.queryByEntity(e3).hasNext()); - - - //------------- - // Test removal - idx1.removeEntity(e1a, 42L); // No-op. e1a isn't mapped to this key - assertEquals(Long.valueOf(1L), idx1.findByEntity(e1a)); - idx1.removeEntity(e1a, 1L); - assertEquals(null, idx1.findByEntity(e1a)); - assertEquals(Long.valueOf(1L), idx1.findByEntity(e1b)); - assertEquals(Long.valueOf(2L), idx1.findByEntity(e2)); - idx1.removeEntity(e2); - assertEquals(null, idx1.findByEntity(e2)); - assertEquals(Long.valueOf(1L), idx1.findByEntity(e1b)); - - - //------------- - // Test null keys - DeviceUniqueIndex idx2 = new DeviceUniqueIndex( - EnumSet.of(DeviceField.IPV4, - DeviceField.SWITCH)); - // only one key field is null - idx2.updateIndex(e3, 3L); - assertEquals(Long.valueOf(3L), idx2.findByEntity(e3)); - e3.ipv4Address = 3; - assertEquals(null, idx2.findByEntity(e3)); - // all key fields are null - idx2.updateIndex(e4, 4L); - assertEquals(null, idx2.findByEntity(e4)); - Device d4 = new Device(null, 4L, null, null, null, - Collections.<Entity>singleton(e4), null); - idx2.updateIndex(d4, 4L); - assertEquals(null, idx2.findByEntity(e4)); - - - - //------------- - // entity already exists with different deviceKey - DeviceUniqueIndex idx3 = new DeviceUniqueIndex( - EnumSet.of(DeviceField.MAC, - DeviceField.VLAN)); - idx3.updateIndex(e1a, 42L); - assertEquals(false, idx3.updateIndex(d1, 1L)); - // TODO: shouldn't this fail as well so that the behavior - // is consistent? - idx3.updateIndex(e1a, 1L); - // anyways. We can now add d1 ;-) - assertEquals(true, idx3.updateIndex(d1, 1L)); - } -} diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java deleted file mode 100644 index 5657cc515792d534179e5d66116f362a232c2098..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java +++ /dev/null @@ -1,92 +0,0 @@ -/** -* 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.devicemanager.test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.TreeSet; - -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.SwitchPort; -import net.floodlightcontroller.devicemanager.internal.AttachmentPoint; -import net.floodlightcontroller.devicemanager.internal.Device; -import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl; -import net.floodlightcontroller.devicemanager.internal.Entity; - -/** - * This mock device removes the dependency on topology and a parent device - * manager and simply assumes all its entities are current and correct - */ -public class MockDevice extends Device { - - public MockDevice(DeviceManagerImpl deviceManager, - Long deviceKey, - Entity entity, - IEntityClass entityClass) { - super(deviceManager, deviceKey, entity, entityClass); - } - - public MockDevice(Device device, Entity newEntity, int insertionpoint) { - super(device, newEntity, insertionpoint); - } - - public MockDevice(DeviceManagerImpl deviceManager, Long deviceKey, - List<AttachmentPoint> aps, - List<AttachmentPoint> trueAPs, - Collection<Entity> entities, - IEntityClass entityClass) { - super(deviceManager, deviceKey, null, aps, trueAPs, - entities, entityClass); - } - - @Override - public Integer[] getIPv4Addresses() { - TreeSet<Integer> vals = new TreeSet<Integer>(); - for (Entity e : entities) { - if (e.getIpv4Address() == null) continue; - vals.add(e.getIpv4Address()); - } - - return vals.toArray(new Integer[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 && - deviceManager.isValidAttachmentPoint(e.getSwitchDPID(), e.getSwitchPort())) { - SwitchPort sp = new SwitchPort(e.getSwitchDPID(), - e.getSwitchPort()); - vals.add(sp); - } - } - return vals.toArray(new SwitchPort[vals.size()]); - } - - @Override - public String toString() { - return "MockDevice [getEntityClass()=" + getEntityClass() - + ", getEntities()=" + Arrays.toString(getEntities()) + "]"; - } - -} diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java deleted file mode 100644 index f15061ad0a1397cf7564124e26dd071a148fe997..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - **/ - -package net.floodlightcontroller.devicemanager.test; - -import java.util.Collection; -import java.util.Date; -import java.util.List; - -import org.sdnplatform.sync.test.MockSyncService; - -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.module.FloodlightModuleException; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceListener; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IEntityClassifierService; -import net.floodlightcontroller.devicemanager.internal.AttachmentPoint; -import net.floodlightcontroller.devicemanager.internal.Device; -import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl; -import net.floodlightcontroller.devicemanager.internal.Entity; - -/** - * Mock device manager useful for unit tests - * @author readams - */ -public class MockDeviceManager extends DeviceManagerImpl { - /** - * Set a new IEntityClassifier - * Use this as a quick way to use a particular entity classifier in a - * single test without having to setup the full FloodlightModuleContext - * again. - * @param ecs - */ - public void setEntityClassifier(IEntityClassifierService ecs) { - this.entityClassifier = ecs; - try { - this.startUp(null); - } catch (FloodlightModuleException e) { - throw new RuntimeException(e); - } - } - - /** - * 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 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, - boolean processUpdates) { - List<IDeviceListener> listeners = deviceListeners.getOrderedListeners(); - if (!processUpdates) { - deviceListeners.clearListeners(); - } - - if (vlan != null && vlan.shortValue() <= 0) - vlan = null; - if (ipv4Address != null && ipv4Address == 0) - ipv4Address = null; - IDevice res = learnDeviceByEntity(new Entity(macAddress, vlan, - ipv4Address, switchDPID, - switchPort, new Date())); - // Restore listeners - if (listeners != null) { - for (IDeviceListener listener : listeners) { - deviceListeners.addListener("device", listener); - } - } - return res; - } - - @Override - public void deleteDevice(Device device) { - super.deleteDevice(device); - } - - /** - * Learn a device using the given characteristics. - * @param macAddress the MAC - * @param vlan the VLAN (can be null) - * @param ipv4Address the IP (can be null) - * @param switchDPID the attachment point switch DPID (can be null) - * @param switchPort the attachment point switch port (can be null) - * @return the device, either new or not - */ - public IDevice learnEntity(long macAddress, Short vlan, - Integer ipv4Address, Long switchDPID, - Integer switchPort) { - return learnEntity(macAddress, vlan, ipv4Address, - switchDPID, switchPort, true); - } - - @Override - protected Device allocateDevice(Long deviceKey, - Entity entity, - IEntityClass entityClass) { - return new MockDevice(this, deviceKey, entity, entityClass); - } - - @Override - protected Device allocateDevice(Long deviceKey, - String dhcpClientName, - List<AttachmentPoint> aps, - List<AttachmentPoint> trueAPs, - Collection<Entity> entities, - IEntityClass entityClass) { - return new MockDevice(this, deviceKey, aps, trueAPs, entities, entityClass); - } - - @Override - protected Device allocateDevice(Device device, - Entity entity, - int insertionpoint) { - return new MockDevice(device, entity, insertionpoint); - } - - @Override - public void init(FloodlightModuleContext fmc) throws FloodlightModuleException { - super.init(fmc); - setSyncServiceIfNotSet(new MockSyncService()); - } -} diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java deleted file mode 100644 index 7a35049a94f79d4a5b0701b28cd682fc95bc7299..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifier.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - **/ - -package net.floodlightcontroller.devicemanager.test; - -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.MAC; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.PORT; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.SWITCH; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.VLAN; - -import java.util.EnumSet; - -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.devicemanager.internal.Entity; - -/** A simple IEntityClassifier. Useful for tests that need IEntityClassifiers - * and IEntityClass'es with switch and/or port key fields - */ -public class MockEntityClassifier extends DefaultEntityClassifier { - public static class TestEntityClass implements IEntityClass { - @Override - public EnumSet<DeviceField> getKeyFields() { - return EnumSet.of(MAC, VLAN, SWITCH, PORT); - } - - @Override - public String getName() { - return "TestEntityClass"; - } - } - public static IEntityClass testEC = - new MockEntityClassifier.TestEntityClass(); - - @Override - public IEntityClass classifyEntity(Entity entity) { - if (entity.getSwitchDPID() >= 10L) { - return testEC; - } - return DefaultEntityClassifier.entityClass; - } - - @Override - 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 deleted file mode 100644 index 521b9b7929833dcca5114a6062e7f0475be4738a..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockEntityClassifierMac.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - **/ - -package net.floodlightcontroller.devicemanager.test; - -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.MAC; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.PORT; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.SWITCH; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.VLAN; - -import java.util.EnumSet; - -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.devicemanager.internal.Entity; - -/** A simple IEntityClassifier. Useful for tests that need an IEntityClassifier - * with switch/port as key fields. - */ -public class MockEntityClassifierMac extends DefaultEntityClassifier { - public static class TestEntityClassMac implements IEntityClass { - protected String name; - public TestEntityClassMac(String name) { - this.name = name; - } - - @Override - public EnumSet<DeviceField> getKeyFields() { - return EnumSet.of(MAC, VLAN); - } - - @Override - public String getName() { - return name; - } - } - public static IEntityClass testECMac1 = - new MockEntityClassifierMac.TestEntityClassMac("testECMac1"); - public static IEntityClass testECMac2 = - new MockEntityClassifierMac.TestEntityClassMac("testECMac2"); - - @Override - public IEntityClass classifyEntity(Entity entity) { - if (entity.getSwitchDPID() == null) { - throw new IllegalArgumentException("Not all key fields specified." - + " Required fields: " + getKeyFields()); - } else if (entity.getSwitchDPID() == 1L) { - return testECMac1; - } else if (entity.getSwitchDPID() == 2L) { - return testECMac2; - } else if (entity.getSwitchDPID() == -1L) { - return null; - } - return DefaultEntityClassifier.entityClass; - } - - @Override - 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/MockFlexEntityClassifier.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.java deleted file mode 100644 index 1e2f4587e7aee1d2a4f204b6360e4bba47cd1769..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockFlexEntityClassifier.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - **/ - - -package net.floodlightcontroller.devicemanager.test; - -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.MAC; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.PORT; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.SWITCH; -import static net.floodlightcontroller.devicemanager.IDeviceService.DeviceField.VLAN; - -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; - -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IEntityClass; -import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.devicemanager.internal.Entity; - -/** - * Extension to simple entity classifier to help in unit tests to provide table - * based multiple entity classification mock for reclassification tests - * - */ -public class MockFlexEntityClassifier extends DefaultEntityClassifier { - Map <Long, IEntityClass> switchEntities; - Map <Short, IEntityClass> vlanEntities; - - public static class TestEntityClass implements IEntityClass { - String name; - public TestEntityClass(String name) { - this.name = name; - } - @Override - public EnumSet<DeviceField> getKeyFields() { - return EnumSet.of(MAC); - } - - @Override - public String getName() { - return name; - } - } - public static IEntityClass defaultClass = new TestEntityClass("default"); - public MockFlexEntityClassifier() { - switchEntities = new HashMap<Long, IEntityClass> (); - vlanEntities = new HashMap<Short, IEntityClass> (); - } - public IEntityClass createTestEntityClass(String name) { - return new TestEntityClass(name); - } - - public void addSwitchEntity(Long dpid, IEntityClass entityClass) { - switchEntities.put(dpid, entityClass); - } - public void removeSwitchEntity(Long dpid) { - switchEntities.remove(dpid); - } - public void addVlanEntities(Short vlan, IEntityClass entityClass) { - vlanEntities.put(vlan, entityClass); - } - public void removeVlanEntities(Short vlan) { - vlanEntities.remove(vlan); - } - @Override - public IEntityClass classifyEntity(Entity entity) { - if (switchEntities.containsKey(entity.getSwitchDPID())) - return switchEntities.get(entity.getSwitchDPID()); - if (vlanEntities.containsKey(entity.getVlan())) - return vlanEntities.get(entity.getVlan()); - return defaultClass; - } - @Override - public EnumSet<IDeviceService.DeviceField> getKeyFields() { - return EnumSet.of(MAC, VLAN, SWITCH, PORT); - } -} diff --git a/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java b/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java deleted file mode 100644 index e10d320d91a305313151d039240a80b4824616c9..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java +++ /dev/null @@ -1,524 +0,0 @@ -/** - * Copyright 2011, Big Switch Networks, Inc. - * Originally created by Amer Tahir - * - * 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.firewall; - -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.packet.ARP; -import net.floodlightcontroller.packet.Data; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.TCP; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestApiServer; -import net.floodlightcontroller.routing.IRoutingDecision; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.memory.MemoryStorageSource; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.util.MACAddress; - -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFType; -import org.openflow.util.HexString; - -/** - * Unit test for stateless firewall implemented as a Google Summer of Code project. - * - * @author Amer Tahir - */ -public class FirewallTest extends FloodlightTestCase { - protected FloodlightContext cntx; - protected OFPacketIn packetIn; - protected IOFSwitch sw; - protected IPacket tcpPacket; - protected IPacket broadcastARPPacket; - protected IPacket ARPReplyPacket; - protected IPacket broadcastIPPacket; - protected IPacket tcpPacketReply; - protected IPacket broadcastMalformedPacket; - private Firewall firewall; - public static String TestSwitch1DPID = "00:00:00:00:00:00:00:01"; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - cntx = new FloodlightContext(); - mockFloodlightProvider = getMockFloodlightProvider(); - firewall = new Firewall(); - IStorageSourceService storageService = new MemoryStorageSource(); - RestApiServer restApi = new RestApiServer(); - - // Mock switches - long dpid = HexString.toLong(TestSwitch1DPID); - sw = EasyMock.createNiceMock(IOFSwitch.class); - expect(sw.getId()).andReturn(dpid).anyTimes(); - expect(sw.getStringId()).andReturn(TestSwitch1DPID).anyTimes(); - replay(sw); - // Load the switch map - Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); - switches.put(dpid, sw); - mockFloodlightProvider.setSwitches(switches); - - FloodlightModuleContext fmc = new FloodlightModuleContext(); - fmc.addService(IFloodlightProviderService.class, - mockFloodlightProvider); - fmc.addService(IFirewallService.class, firewall); - fmc.addService(IStorageSourceService.class, storageService); - fmc.addService(IRestApiService.class, restApi); - - restApi.init(fmc); - - firewall.init(fmc); - firewall.startUp(fmc); - - // Build our test packet - this.tcpPacket = new Ethernet() - .setDestinationMACAddress("00:11:22:33:44:55") - .setSourceMACAddress("00:44:33:22:11:00") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.1") - .setDestinationAddress("192.168.1.2") - .setPayload(new TCP() - .setSourcePort((short) 81) - .setDestinationPort((short) 80) - .setPayload(new Data(new byte[] {0x01})))); - - // Build a broadcast ARP packet - this.broadcastARPPacket = new Ethernet() - .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") - .setSourceMACAddress("00:44:33:22:11:00") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_ARP) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setOpCode(ARP.OP_REQUEST) - .setHardwareAddressLength((byte)6) - .setProtocolAddressLength((byte)4) - .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) - .setSenderProtocolAddress(IPv4.toIPv4Address("192.168.1.1")) - .setTargetHardwareAddress(Ethernet.toMACAddress("00:00:00:00:00:00")) - .setTargetProtocolAddress(IPv4.toIPv4Address("192.168.1.2")) - .setPayload(new Data(new byte[] {0x01}))); - - // Build a ARP packet - this.ARPReplyPacket = new Ethernet() - .setDestinationMACAddress("00:44:33:22:11:00") - .setSourceMACAddress("00:11:22:33:44:55") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_ARP) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setOpCode(ARP.OP_REQUEST) - .setHardwareAddressLength((byte)6) - .setProtocolAddressLength((byte)4) - .setSenderHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55")) - .setSenderProtocolAddress(IPv4.toIPv4Address("192.168.1.2")) - .setTargetHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00")) - .setTargetProtocolAddress(IPv4.toIPv4Address("192.168.1.1")) - .setPayload(new Data(new byte[] {0x01}))); - - // Build a broadcast IP packet - this.broadcastIPPacket = new Ethernet() - .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") - .setSourceMACAddress("00:44:33:22:11:00") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.1") - .setDestinationAddress("192.168.1.255") - .setPayload(new UDP() - .setSourcePort((short) 5000) - .setDestinationPort((short) 5001) - .setPayload(new Data(new byte[] {0x01})))); - - // Build a malformed broadcast packet - this.broadcastMalformedPacket = new Ethernet() - .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") - .setSourceMACAddress("00:44:33:22:11:00") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_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})))); - - this.tcpPacketReply = new Ethernet() - .setDestinationMACAddress("00:44:33:22:11:00") - .setSourceMACAddress("00:11:22:33:44:55") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.2") - .setDestinationAddress("192.168.1.1") - .setPayload(new TCP() - .setSourcePort((short) 80) - .setDestinationPort((short) 81) - .setPayload(new Data(new byte[] {0x02})))); - } - - protected void setPacketIn(IPacket packet) { - byte[] serializedPacket = packet.serialize(); - // Build the PacketIn - this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(serializedPacket) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) serializedPacket.length); - - // Add the packet to the context store - IFloodlightProviderService.bcStore. - put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet)packet); - } - - @Test - public void testNoRules() throws Exception { - // enable firewall first - firewall.enableFirewall(true); - // simulate a packet-in event - this.setPacketIn(tcpPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - assertEquals(0, firewall.rules.size()); - - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - // no rules to match, so firewall should deny - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); - } - - @Test - public void testReadRulesFromStorage() throws Exception { - // add 2 rules first - FirewallRule rule = new FirewallRule(); - rule.in_port = 2; - rule.dl_src = MACAddress.valueOf("00:00:00:00:00:01").toLong(); - rule.dl_dst = MACAddress.valueOf("00:00:00:00:00:02").toLong(); - rule.priority = 1; - rule.action = FirewallRule.FirewallAction.DENY; - firewall.addRule(rule); - rule = new FirewallRule(); - rule.in_port = 3; - rule.dl_src = MACAddress.valueOf("00:00:00:00:00:02").toLong(); - rule.dl_dst = MACAddress.valueOf("00:00:00:00:00:01").toLong(); - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - rule.tp_dst = 80; - rule.priority = 2; - rule.action = FirewallRule.FirewallAction.ALLOW; - firewall.addRule(rule); - - List<FirewallRule> rules = firewall.readRulesFromStorage(); - // verify rule 1 - FirewallRule r = rules.get(0); - assertEquals(r.in_port, 2); - assertEquals(r.priority, 1); - assertEquals(r.dl_src, MACAddress.valueOf("00:00:00:00:00:01").toLong()); - assertEquals(r.dl_dst, MACAddress.valueOf("00:00:00:00:00:02").toLong()); - assertEquals(r.action, FirewallRule.FirewallAction.DENY); - // verify rule 2 - r = rules.get(1); - assertEquals(r.in_port, 3); - assertEquals(r.priority, 2); - assertEquals(r.dl_src, MACAddress.valueOf("00:00:00:00:00:02").toLong()); - assertEquals(r.dl_dst, MACAddress.valueOf("00:00:00:00:00:01").toLong()); - assertEquals(r.nw_proto, IPv4.PROTOCOL_TCP); - assertEquals(r.tp_dst, 80); - assertEquals(r.wildcard_nw_proto, false); - assertEquals(r.action, FirewallRule.FirewallAction.ALLOW); - } - - @Test - public void testRuleInsertionIntoStorage() throws Exception { - // add TCP rule - FirewallRule rule = new FirewallRule(); - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - rule.priority = 1; - firewall.addRule(rule); - - List<Map<String, Object>> rulesFromStorage = firewall.getStorageRules(); - assertEquals(1, rulesFromStorage.size()); - assertEquals(Integer.parseInt((String)rulesFromStorage.get(0).get("ruleid")), rule.ruleid); - } - - @Test - public void testRuleDeletion() throws Exception { - // add TCP rule - FirewallRule rule = new FirewallRule(); - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - rule.priority = 1; - firewall.addRule(rule); - int rid = rule.ruleid; - - List<Map<String, Object>> rulesFromStorage = firewall.getStorageRules(); - assertEquals(1, rulesFromStorage.size()); - assertEquals(Integer.parseInt((String)rulesFromStorage.get(0).get("ruleid")), rid); - - // delete rule - firewall.deleteRule(rid); - rulesFromStorage = firewall.getStorageRules(); - assertEquals(0, rulesFromStorage.size()); - } - - @Test - public void testFirewallDisabled() throws Exception { - // firewall isn't enabled by default - // so, it shouldn't make any decision - - // add TCP rule - FirewallRule rule = new FirewallRule(); - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - rule.priority = 1; - firewall.addRule(rule); - - this.setPacketIn(tcpPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - assertEquals(1, firewall.rules.size()); - - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertNull(decision); - } - - @Test - public void testSimpleAllowRule() throws Exception { - // enable firewall first - firewall.enableFirewall(true); - - // add TCP rule - FirewallRule rule = new FirewallRule(); - rule.dl_type = Ethernet.TYPE_IPv4; - rule.wildcard_dl_type = false; - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - // source is IP 192.168.1.2 - rule.nw_src_prefix = IPv4.toIPv4Address("192.168.1.2"); - rule.wildcard_nw_src = false; - // dest is network 192.168.1.0/24 - rule.nw_dst_prefix = IPv4.toIPv4Address("192.168.1.0"); - rule.nw_dst_maskbits = 24; - rule.wildcard_nw_dst = false; - rule.priority = 1; - firewall.addRule(rule); - - // simulate a packet-in events - - this.setPacketIn(tcpPacketReply); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); - - // clear decision - IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION); - - this.setPacketIn(tcpPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); - } - - @Test - public void testOverlappingRules() throws Exception { - firewall.enableFirewall(true); - - // add TCP port 80 (destination only) allow rule - FirewallRule rule = new FirewallRule(); - rule.dl_type = Ethernet.TYPE_IPv4; - rule.wildcard_dl_type = false; - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - rule.tp_dst = 80; - rule.priority = 1; - firewall.addRule(rule); - - // add block all rule - rule = new FirewallRule(); - rule.action = FirewallRule.FirewallAction.DENY; - rule.priority = 2; - firewall.addRule(rule); - - assertEquals(2, firewall.rules.size()); - - // packet destined to TCP port 80 - should be allowed - - this.setPacketIn(tcpPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); - - // clear decision - IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION); - - // packet destined for port 81 - should be denied - - this.setPacketIn(tcpPacketReply); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); - } - - @Test - public void testARP() throws Exception { - // enable firewall first - firewall.enableFirewall(true); - - // no rules inserted so all traffic other than broadcast and ARP-request-broadcast should be blocked - - // simulate an ARP broadcast packet-in event - - this.setPacketIn(broadcastARPPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - // broadcast-ARP traffic should be allowed - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(IRoutingDecision.RoutingAction.MULTICAST, decision.getRoutingAction()); - - // clear decision - IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION); - - // simulate an ARP reply packet-in event - - this.setPacketIn(ARPReplyPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - // ARP reply traffic should be denied - decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); - } - - @Test - public void testIPBroadcast() throws Exception { - // enable firewall first - firewall.enableFirewall(true); - - // set subnet mask for IP broadcast - firewall.setSubnetMask("255.255.255.0"); - - // no rules inserted so all traffic other than broadcast and ARP-request-broadcast should be blocked - - // simulate a packet-in event - - this.setPacketIn(broadcastIPPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - // broadcast traffic should be allowed - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(IRoutingDecision.RoutingAction.MULTICAST, decision.getRoutingAction()); - } - - @Test - public void testMalformedIPBroadcast() throws Exception { - // enable firewall first - firewall.enableFirewall(true); - - // no rules inserted so all traffic other than broadcast and ARP-request-broadcast should be blocked - - // simulate a packet-in event - - this.setPacketIn(broadcastMalformedPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - // malformed broadcast traffic should NOT be allowed - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP); - } - - @Test - public void testLayer2Rule() throws Exception { - // enable firewall first - firewall.enableFirewall(true); - - // add L2 rule - FirewallRule rule = new FirewallRule(); - rule.dl_src = MACAddress.valueOf("00:44:33:22:11:00").toLong(); - rule.wildcard_dl_src = false; - rule.dl_dst = MACAddress.valueOf("00:11:22:33:44:55").toLong(); - rule.wildcard_dl_dst = false; - rule.priority = 1; - firewall.addRule(rule); - - // add TCP deny all rule - rule = new FirewallRule(); - rule.nw_proto = IPv4.PROTOCOL_TCP; - rule.wildcard_nw_proto = false; - rule.priority = 2; - rule.action = FirewallRule.FirewallAction.DENY; - firewall.addRule(rule); - - // simulate a packet-in event - - this.setPacketIn(tcpPacket); - firewall.receive(sw, this.packetIn, cntx); - verify(sw); - - IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); - assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD); - } -} diff --git a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java b/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java deleted file mode 100644 index 62ccecdf69fefab4db37686abb7c273d4420075f..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java +++ /dev/null @@ -1,514 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.flowcache; - -import static org.easymock.EasyMock.*; - -import java.util.ArrayList; -import java.util.Date; -import java.util.ListIterator; - -import net.floodlightcontroller.core.IListener.Command; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.counter.SimpleCounter; -import net.floodlightcontroller.counter.CounterValue.CounterType; -import net.floodlightcontroller.flowcache.IFlowReconcileListener; -import net.floodlightcontroller.flowcache.OFMatchReconcile; -import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import org.easymock.EasyMock; -import org.easymock.IAnswer; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFStatisticsRequest; -import org.openflow.protocol.OFType; - -public class FlowReconcileMgrTest extends FloodlightTestCase { - - protected FlowReconcileManager flowReconcileMgr; - protected MockThreadPoolService threadPool; - protected ICounterStoreService counterStore; - protected FloodlightModuleContext fmc; - - OFStatisticsRequest ofStatsRequest; - - protected int NUM_FLOWS_PER_THREAD = 100; - protected int NUM_THREADS = 20; - - @Before - public void setUp() throws Exception { - super.setUp(); - - fmc = new FloodlightModuleContext(); - flowReconcileMgr = new FlowReconcileManager(); - threadPool = new MockThreadPoolService(); - counterStore = createMock(ICounterStoreService.class); - - fmc.addService(ICounterStoreService.class, counterStore); - fmc.addService(IThreadPoolService.class, threadPool); - - threadPool.init(fmc); - flowReconcileMgr.init(fmc); - - threadPool.startUp(fmc); - flowReconcileMgr.startUp(fmc); - } - - /** Verify pipeline listener registration and ordering - * - * @throws Exception - */ - @SuppressWarnings("unchecked") - @Test - public void testFlowReconcilePipeLine() throws Exception { - flowReconcileMgr.flowReconcileEnabled = true; - - IFlowReconcileListener r1 = - EasyMock.createNiceMock(IFlowReconcileListener.class); - IFlowReconcileListener r2 = - EasyMock.createNiceMock(IFlowReconcileListener.class); - IFlowReconcileListener r3 = - EasyMock.createNiceMock(IFlowReconcileListener.class); - - expect(r1.getName()).andReturn("r1").anyTimes(); - expect(r2.getName()).andReturn("r2").anyTimes(); - expect(r3.getName()).andReturn("r3").anyTimes(); - - // Set the listeners' order: r1 -> r2 -> r3 - expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - expect(r2.isCallbackOrderingPrereq((OFType)anyObject(), - eq("r1"))).andReturn(true).anyTimes(); - expect(r2.isCallbackOrderingPrereq((OFType)anyObject(), - eq("r3"))).andReturn(false).anyTimes(); - expect(r2.isCallbackOrderingPostreq((OFType)anyObject(), - eq("r1"))).andReturn(false).anyTimes(); - expect(r2.isCallbackOrderingPostreq((OFType)anyObject(), - eq("r3"))).andReturn(true).anyTimes(); - expect(r3.isCallbackOrderingPrereq((OFType)anyObject(), - eq("r1"))).andReturn(false).anyTimes(); - expect(r3.isCallbackOrderingPrereq((OFType)anyObject(), - eq("r2"))).andReturn(true).anyTimes(); - expect(r3.isCallbackOrderingPostreq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())). - andThrow(new RuntimeException("This is NOT an error! " + - "We are testing exception catching.")); - - SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter( - new Date(), - CounterType.LONG); - cnt.increment(); - expect(counterStore.getCounter( - flowReconcileMgr.controllerPktInCounterName)) - .andReturn(cnt) - .anyTimes(); - - replay(r1, r2, r3, counterStore); - flowReconcileMgr.clearFlowReconcileListeners(); - flowReconcileMgr.addFlowReconcileListener(r1); - flowReconcileMgr.addFlowReconcileListener(r2); - flowReconcileMgr.addFlowReconcileListener(r3); - - int pre_flowReconcileThreadRunCount = - flowReconcileMgr.flowReconcileThreadRunCount.get(); - Date startTime = new Date(); - OFMatchReconcile ofmRcIn = new OFMatchReconcile(); - try { - flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH); - flowReconcileMgr.doReconcile(); - } catch (RuntimeException e) { - assertEquals(e.getMessage() - .startsWith("This is NOT an error!"), true); - } - - verify(r1, r2, r3); - - // verify STOP works - reset(r1, r2, r3); - - // restart reconcileThread since it exited due to previous runtime - // exception. - flowReconcileMgr.startUp(fmc); - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.STOP).times(1); - expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())); - expectLastCall().andAnswer(new IAnswer<Object>() { - public Object answer() { - fail("Unexpected call"); - return Command.STOP; - } - }).anyTimes(); - - pre_flowReconcileThreadRunCount = - flowReconcileMgr.flowReconcileThreadRunCount.get(); - startTime = new Date(); - replay(r1, r2, r3); - flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH); - while (flowReconcileMgr.flowReconcileThreadRunCount.get() <= - pre_flowReconcileThreadRunCount) { - Thread.sleep(10); - Date currTime = new Date(); - assertTrue((currTime.getTime() - startTime.getTime()) < 1000); - } - verify(r1, r2, r3); - - // verify CONTINUE works - reset(r1, r2, r3); - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.CONTINUE).times(1); - expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.STOP).times(1); - expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())); - expectLastCall().andAnswer(new IAnswer<Object>() { - public Object answer() { - fail("Unexpected call"); - return Command.STOP; - } - }).anyTimes(); - - pre_flowReconcileThreadRunCount = - flowReconcileMgr.flowReconcileThreadRunCount.get(); - startTime = new Date(); - - replay(r1, r2, r3); - flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH); - while (flowReconcileMgr.flowReconcileThreadRunCount.get() <= - pre_flowReconcileThreadRunCount) { - Thread.sleep(10); - Date currTime = new Date(); - assertTrue((currTime.getTime() - startTime.getTime()) < 1000); - } - verify(r1, r2, r3); - - // verify CONTINUE works - reset(r1, r2, r3); - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.CONTINUE).times(1); - expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.CONTINUE).times(1); - expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.STOP).times(1); - - pre_flowReconcileThreadRunCount = - flowReconcileMgr.flowReconcileThreadRunCount.get(); - startTime = new Date(); - - replay(r1, r2, r3); - flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH); - while (flowReconcileMgr.flowReconcileThreadRunCount.get() <= - pre_flowReconcileThreadRunCount) { - Thread.sleep(10); - Date currTime = new Date(); - assertTrue((currTime.getTime() - startTime.getTime()) < 1000); - } - verify(r1, r2, r3); - - // Verify removeFlowReconcileListener - flowReconcileMgr.removeFlowReconcileListener(r1); - reset(r1, r2, r3); - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())); - expectLastCall().andAnswer(new IAnswer<Object>() { - public Object answer() { - fail("Unexpected call to a listener that is " + - "removed from the chain."); - return Command.STOP; - } - }).anyTimes(); - expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.CONTINUE).times(1); - expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.STOP).times(1); - - pre_flowReconcileThreadRunCount = - flowReconcileMgr.flowReconcileThreadRunCount.get(); - startTime = new Date(); - replay(r1, r2, r3); - flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH); - while (flowReconcileMgr.flowReconcileThreadRunCount.get() <= - pre_flowReconcileThreadRunCount) { - Thread.sleep(10); - Date currTime = new Date(); - assertTrue((currTime.getTime() - startTime.getTime()) < 1000); - } - verify(r1, r2, r3); - } - - @Test - public void testGetPktInRate() { - internalTestGetPktInRate(CounterType.LONG); - internalTestGetPktInRate(CounterType.DOUBLE); - } - - protected void internalTestGetPktInRate(CounterType type) { - Date currentTime = new Date(); - SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter( - currentTime, type); - newCnt.increment(currentTime, 1); - - // Set the lastCounter time in the future of the current time - Date lastCounterTime = new Date(currentTime.getTime() + 1000); - flowReconcileMgr.lastPacketInCounter = - (SimpleCounter)SimpleCounter.createCounter( - lastCounterTime, type); - flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1); - - assertEquals(FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND, - flowReconcileMgr.getPktInRate(newCnt, new Date())); - - // Verify the rate == 0 time difference is zero. - lastCounterTime = new Date(currentTime.getTime() - 1000); - flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1); - assertEquals(0, flowReconcileMgr.getPktInRate(newCnt, lastCounterTime)); - - /** verify the computation is correct. - * new = 2000, old = 1000, Tdiff = 1 second. - * rate should be 1000/second - */ - newCnt = (SimpleCounter)SimpleCounter.createCounter( - currentTime, type); - newCnt.increment(currentTime, 2000); - - lastCounterTime = new Date(currentTime.getTime() - 1000); - flowReconcileMgr.lastPacketInCounter = - (SimpleCounter)SimpleCounter.createCounter( - lastCounterTime, type); - flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, 1000); - assertEquals(1000, flowReconcileMgr.getPktInRate(newCnt, currentTime)); - - /** verify the computation is correct. - * new = 2,000,000, old = 1,000,000, Tdiff = 2 second. - * rate should be 1000/second - */ - newCnt = (SimpleCounter)SimpleCounter.createCounter( - currentTime, type); - newCnt.increment(currentTime, 2000000); - - lastCounterTime = new Date(currentTime.getTime() - 2000); - flowReconcileMgr.lastPacketInCounter = - (SimpleCounter)SimpleCounter.createCounter( - lastCounterTime, type); - flowReconcileMgr.lastPacketInCounter.increment(lastCounterTime, - 1000000); - assertEquals(500000, flowReconcileMgr.getPktInRate(newCnt, - currentTime)); - } - - @Test - public void testGetCurrentCapacity() throws Exception { - // Disable the reconcile thread. - flowReconcileMgr.flowReconcileEnabled = false; - - int minFlows = FlowReconcileManager.MIN_FLOW_RECONCILE_PER_SECOND * - FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000; - - /** Verify the initial state, when packetIn counter has not - * been created. - */ - expect(counterStore.getCounter( - flowReconcileMgr.controllerPktInCounterName)) - .andReturn(null) - .times(1); - - replay(counterStore); - assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity()); - verify(counterStore); - - /** Verify the initial state, when lastPacketInCounter is null */ - reset(counterStore); - Date currentTime = new Date(); - SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter( - currentTime, CounterType.LONG); - - expect(counterStore.getCounter( - flowReconcileMgr.controllerPktInCounterName)) - .andReturn(newCnt) - .times(1); - long initPktInCount = 1000; - newCnt.increment(currentTime, initPktInCount); - - replay(counterStore); - assertEquals(minFlows, flowReconcileMgr.getCurrentCapacity()); - verify(counterStore); - - /** Now the lastPacketInCounter has been set. - * lastCounter = 1,000 and newCounter = 3,000, t = 1 second - * packetInRate = 2,000/sec. - * capacity should be 10k - 2k = 8k - */ - reset(counterStore); - newCnt = (SimpleCounter)SimpleCounter.createCounter( - currentTime, CounterType.LONG); - currentTime = new Date(currentTime.getTime() + 200); - long nextPktInCount = 3000; - newCnt.increment(currentTime, nextPktInCount); - - expect(counterStore.getCounter( - flowReconcileMgr.controllerPktInCounterName)) - .andReturn(newCnt) - .times(1); - - replay(counterStore); - // Wait for 1 second so that enough elapsed time to compute capacity. - Thread.sleep(1000); - int capacity = flowReconcileMgr.getCurrentCapacity(); - verify(counterStore); - long expectedCap = (FlowReconcileManager.MAX_SYSTEM_LOAD_PER_SECOND - - (nextPktInCount - initPktInCount)) * - FlowReconcileManager.FLOW_RECONCILE_DELAY_MILLISEC / 1000; - assertEquals(expectedCap, capacity); - } - - /** Verify the flows are sent to the reconcile pipeline in order. - */ - @SuppressWarnings("unchecked") - @Test - public void testQueueFlowsOrder() { - flowReconcileMgr.flowReconcileEnabled = false; - - IFlowReconcileListener r1 = - EasyMock.createNiceMock(IFlowReconcileListener.class); - - expect(r1.getName()).andReturn("r1").anyTimes(); - - // Set the listeners' order: r1 -> r2 -> r3 - expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andAnswer(new IAnswer<Command>() { - @Override - public Command answer() throws Throwable { - ArrayList<OFMatchReconcile> ofmList = - (ArrayList<OFMatchReconcile>)EasyMock. - getCurrentArguments()[0]; - ListIterator<OFMatchReconcile> lit = ofmList.listIterator(); - int index = 0; - while (lit.hasNext()) { - OFMatchReconcile ofm = lit.next(); - assertEquals(index++, ofm.cookie); - } - return Command.STOP; - } - }).times(1); - - SimpleCounter cnt = (SimpleCounter)SimpleCounter.createCounter( - new Date(), - CounterType.LONG); - cnt.increment(); - expect(counterStore.getCounter( - flowReconcileMgr.controllerPktInCounterName)) - .andReturn(cnt) - .anyTimes(); - - replay(r1, counterStore); - flowReconcileMgr.clearFlowReconcileListeners(); - flowReconcileMgr.addFlowReconcileListener(r1); - - OFMatchReconcile ofmRcIn = new OFMatchReconcile(); - int index = 0; - for (index = 0; index < 10; index++) { - ofmRcIn.cookie = index; - flowReconcileMgr.reconcileFlow(ofmRcIn,EventPriority.HIGH); - } - flowReconcileMgr.flowReconcileEnabled = true; - flowReconcileMgr.doReconcile(); - - verify(r1); - } - - @SuppressWarnings("unchecked") - @Test - public void testQueueFlowsByManyThreads() { - // Disable the reconcile thread so that the queue won't be emptied. - flowQueueTest(false); - - // Enable the reconcile thread. The queue should be empty. - Date currentTime = new Date(); - SimpleCounter newCnt = (SimpleCounter)SimpleCounter.createCounter( - currentTime, CounterType.LONG); - - expect(counterStore.getCounter( - flowReconcileMgr.controllerPktInCounterName)) - .andReturn(newCnt) - .anyTimes(); - long initPktInCount = 10000; - newCnt.increment(currentTime, initPktInCount); - - IFlowReconcileListener r1 = - EasyMock.createNiceMock(IFlowReconcileListener.class); - - expect(r1.getName()).andReturn("r1").anyTimes(); - - // Set the listeners' order: r1 -> r2 -> r3 - expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), - (String)anyObject())).andReturn(false).anyTimes(); - - expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())) - .andReturn(Command.CONTINUE).anyTimes(); - - flowReconcileMgr.clearFlowReconcileListeners(); - replay(r1, counterStore); - flowQueueTest(true); - verify(r1, counterStore); - } - - protected void flowQueueTest(boolean enableReconcileThread) { - flowReconcileMgr.flowReconcileEnabled = enableReconcileThread; - - // Simulate flow - for (int i = 0; i < NUM_THREADS; i++) { - Runnable worker = this.new FlowReconcileWorker(); - Thread t = new Thread(worker); - t.start(); - } - - Date startTime = new Date(); - int totalFlows = NUM_THREADS * NUM_FLOWS_PER_THREAD; - if (enableReconcileThread) { - totalFlows = 0; - } - while (flowReconcileMgr.flowQueue.size() != totalFlows) { - Date currTime = new Date(); - assertTrue((currTime.getTime() - startTime.getTime()) < 1000); - } - - // Make sure all flows are in the queue. - assertEquals(totalFlows, flowReconcileMgr.flowQueue.size()); - } - - private class FlowReconcileWorker implements Runnable { - @Override - public void run() { - OFMatchReconcile ofmRc = new OFMatchReconcile(); - // push large number of flows to be reconciled. - for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) { - flowReconcileMgr.reconcileFlow(ofmRc,EventPriority.LOW); - } - } - } -} diff --git a/src/test/java/net/floodlightcontroller/flowcache/PortDownReconciliationTest.java b/src/test/java/net/floodlightcontroller/flowcache/PortDownReconciliationTest.java deleted file mode 100644 index 9eb15be4fe2e86b199d2883ebbc2cc8ffe94c1be..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/flowcache/PortDownReconciliationTest.java +++ /dev/null @@ -1,457 +0,0 @@ -/** - * Copyright 2012, Jason Parraga, Marist College - * - * 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.flowcache; - -import static org.easymock.EasyMock.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; - -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMatchWithSwDpid; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFStatisticsRequest; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.statistics.OFFlowStatisticsReply; -import org.openflow.protocol.statistics.OFFlowStatisticsRequest; -import org.openflow.protocol.statistics.OFStatistics; -import org.openflow.protocol.statistics.OFStatisticsType; -import org.openflow.util.U16; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.devicemanager.IEntityClassifierService; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.flowcache.FlowReconcileManager; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.flowcache.OFMatchReconcile; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyService; - -/** - * Unit test for PortDownReconciliation. To test the class I have generated - * there very simple network topologies. an OFMatchReconcile object with - * information about the PORT_DOWN event is passed to the class, where it begins - * breaking down the information,analyzing the switches for flows and deleting - * those that are invalid. This Test specifically verifies that each switch is - * queried for flows once and is sent the appropriate OFFlowMod delete message. - * - * @author Jason Parraga - */ - -public class PortDownReconciliationTest extends FloodlightTestCase { - - protected FloodlightModuleContext fmc; - protected ILinkDiscoveryService lds; - protected FlowReconcileManager flowReconcileMgr; - protected MockThreadPoolService tps; - protected DefaultEntityClassifier entityClassifier; - protected PortDownReconciliation pdr; - protected ITopologyService topology; - protected IOFSwitch sw1, sw2, sw3, sw4; - protected Map<Long, IOFSwitch> switches; - protected Capture<List<OFMessage>> wc1, wc2, wc3, wc4; - protected Capture<FloodlightContext> bc1, bc2, bc3, bc4; - protected OFMessage fm, fm2; - protected ArrayList<OFMatchReconcile> lofmr; - protected OFMatchReconcile ofmr; - protected static Logger log; - protected FloodlightContext cntx; - protected List<OFStatistics> statsReply; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - log = LoggerFactory.getLogger(PortDownReconciliation.class); - fmc = new FloodlightModuleContext(); - mockFloodlightProvider = getMockFloodlightProvider(); - pdr = new PortDownReconciliation(); - lds = createMock(ILinkDiscoveryService.class); - entityClassifier = new DefaultEntityClassifier(); - tps = new MockThreadPoolService(); - flowReconcileMgr = new FlowReconcileManager(); - topology = createMock(ITopologyService.class); - cntx = new FloodlightContext(); - statsReply = new ArrayList<OFStatistics>(); - - fmc.addService(IThreadPoolService.class, tps); - fmc.addService(IFloodlightProviderService.class, - getMockFloodlightProvider()); - fmc.addService(IFlowReconcileService.class, flowReconcileMgr); - fmc.addService(ITopologyService.class, topology); - fmc.addService(IEntityClassifierService.class, entityClassifier); - fmc.addService(ILinkDiscoveryService.class, lds); - - tps.init(fmc); - flowReconcileMgr.init(fmc); - entityClassifier.init(fmc); - getMockFloodlightProvider().init(fmc); - pdr.init(fmc); - - tps.startUp(fmc); - flowReconcileMgr.startUp(fmc); - entityClassifier.startUp(fmc); - getMockFloodlightProvider().startUp(fmc); - pdr.startUp(fmc); - - // The STATS_REQUEST object used when querying the switches for flows - OFStatisticsRequest req = new OFStatisticsRequest(); - req.setStatisticType(OFStatisticsType.FLOW); - int requestLength = req.getLengthU(); - OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest(); - specificReq.setMatch(new OFMatch().setWildcards(0xffffffff)); - specificReq.setOutPort((short) 3); - specificReq.setTableId((byte) 0xff); - req.setStatistics(Collections.singletonList((OFStatistics) specificReq)); - requestLength += specificReq.getLength(); - req.setLengthU(requestLength); - - // Actions for the STATS_REPLY object - OFActionOutput action = new OFActionOutput((short) 3, (short) 0xffff); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - // Match for the STATS_REPLY object - OFMatch m = new OFMatch(); - // Set the incoming port to 1 so that it will find the connected - m.setInputPort((short) 1); - - // STATS_REPLY object - OFFlowStatisticsReply reply = new OFFlowStatisticsReply(); - reply.setActions(actions); - reply.setMatch(m); - // Add the reply to the list of OFStatistics - statsReply.add(reply); - - // Create the STATS_REPLY asynchronous reply object - Callable<List<OFStatistics>> replyFuture = new ReplyFuture(); - // Assign the callable object to a Futuretask so that it will produce - // future results - FutureTask<List<OFStatistics>> futureStats = new FutureTask<List<OFStatistics>>( - replyFuture); - - // Assign the results of calling the object (the asynchronous reply) - Future<List<OFStatistics>> results = getResults(futureStats); - - // SW1 -- Mock switch for base and multiple switch test case - sw1 = EasyMock.createNiceMock(IOFSwitch.class); - // Expect that the switch's ID is 1 - expect(sw1.getId()).andReturn(1L).anyTimes(); - expect(sw1.queryStatistics(req)).andReturn(results).once(); - // Captures to hold resulting flowmod delete messages - wc1 = new Capture<List<OFMessage>>(CaptureType.ALL); - bc1 = new Capture<FloodlightContext>(CaptureType.ALL); - // Capture the parameters passed when sw1.write is invoked - sw1.write(capture(wc1), capture(bc1)); - expectLastCall().once(); - replay(sw1); - - // SW2 -- Mock switch for extended test cases - sw2 = EasyMock.createNiceMock(IOFSwitch.class); - // Expect that the switch's ID is 2 - expect(sw2.getId()).andReturn(2L).anyTimes(); - expect(sw2.queryStatistics(req)).andReturn(results).once(); - wc2 = new Capture<List<OFMessage>>(CaptureType.ALL); - bc2 = new Capture<FloodlightContext>(CaptureType.ALL); - // Capture the parameters passwed when sw1.write is invoked - sw2.write(capture(wc2), capture(bc2)); - expectLastCall().anyTimes(); - replay(sw2); - - // SW3 -- Mock switch for extended test cases - sw3 = EasyMock.createNiceMock(IOFSwitch.class); - // Expect that the switch's ID is 3 - expect(sw3.getId()).andReturn(3L).anyTimes(); - expect(sw3.queryStatistics(req)).andReturn(results).once(); - wc3 = new Capture<List<OFMessage>>(CaptureType.ALL); - bc3 = new Capture<FloodlightContext>(CaptureType.ALL); - // Capture the parameters passwed when sw1.write is invoked - sw3.write(capture(wc3), capture(bc3)); - expectLastCall().anyTimes(); - replay(sw3); - - // SW4 -- Mock switch for extended test cases - sw4 = EasyMock.createNiceMock(IOFSwitch.class); - // Expect that the switch's ID is 4 - expect(sw4.getId()).andReturn(4L).anyTimes(); - expect(sw4.queryStatistics(req)).andReturn(results).once(); - wc4 = new Capture<List<OFMessage>>(CaptureType.ALL); - bc4 = new Capture<FloodlightContext>(CaptureType.ALL); - // Capture the parameters passed when sw1.write is invoked - sw4.write(capture(wc4), capture(bc4)); - expectLastCall().anyTimes(); - replay(sw4); - - // Here we create the OFMatch Reconcile list we wish to pass - lofmr = new ArrayList<OFMatchReconcile>(); - - // Create the only OFMatch Reconcile object that will be in the list - ofmr = new OFMatchReconcile(); - long affectedSwitch = sw1.getId(); - OFMatchWithSwDpid ofmatchsw = new OFMatchWithSwDpid(new OFMatch().setWildcards(OFMatch.OFPFW_ALL), - affectedSwitch); - ofmr.rcAction = OFMatchReconcile.ReconcileAction.UPDATE_PATH; - ofmr.ofmWithSwDpid = ofmatchsw; - - // We'll say port 3 went down - ofmr.outPort = 3; - - // Add the OFMatch Reconcile object to the list - lofmr.add(ofmr); - - // Expected Flow Mod Deletes Messages - // Flow Mod Delete for base switch - fm = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD)).setMatch(new OFMatch().setWildcards(OFMatch.OFPFW_ALL)) - .setCommand(OFFlowMod.OFPFC_DELETE) - // Notice - // we - // specify - // an - // outPort - .setOutPort((short) 3) - .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH)); - - // Flow Mod Delete for the neighborswitches - fm2 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory() - .getMessage(OFType.FLOW_MOD)) - // Notice that this Match object is more specific - .setMatch(reply.getMatch()) - .setCommand(OFFlowMod.OFPFC_DELETE) - // Notice - // we - // specific - // an - // outPort - .setOutPort((short) 3) - .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH)); - - } - - // This generates the asynchronous reply to sw.getStatistics() - public Future<List<OFStatistics>> - getResults(FutureTask<List<OFStatistics>> futureStats) { - Thread t = new Thread(futureStats); - t.start(); - return futureStats; - - } - - // Class for the asynchronous reply - public class ReplyFuture implements Callable<List<OFStatistics>> { - @Override - public List<OFStatistics> call() throws Exception { - // return stats reply defined above - return statsReply; - } - } - - /** - * This tests the port down reconciliation in the event that the base switch - * is the only switch involved in the PORT_DOWN event. It simply deletes - * flows concerning the downed port. - * - * @verify checks to see that a general clearFlowMods(Short outPort) is - * called - * @throws Exception - */ - @Test - public void testSingleSwitchPortDownReconciliation() throws Exception { - log.debug("Starting single switch port down reconciliation test"); - // Load the switch map - switches = new HashMap<Long, IOFSwitch>(); - switches.put(1L, sw1); - mockFloodlightProvider.setSwitches(switches); - - // Reconcile flows with specified OFMatchReconcile - pdr.reconcileFlows(lofmr); - // Validate results - verify(sw1); - - assertTrue(wc1.hasCaptured()); - - List<OFMessage> msglist = wc1.getValues().get(0); - - // Make sure the messages we captures correct - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm, m); - } - } - - /** - * This tests the port down reconciliation in the event that the base switch - * is connected to a chain of three switches. It discovers that is has 1 - * neighbor, which recursively finds out that it has 1 neighbor until the - * final switch "sw4" is evaluated, which has no neighbors. - * - * @verify checks to see that a general clearFlowMods(Short outPort) is - * called on the base switch while specific clearFlowMods(OFMatch - * match, Short outPort) are called on the neighboring switches - * @throws Exception - */ - @Test - public void testLinearLinkPortDownReconciliation() throws Exception { - log.debug("Starting linear link port down reconciliation test"); - - // Load the switch map - switches = new HashMap<Long, IOFSwitch>(); - switches.put(1L, sw1); - switches.put(2L, sw2); - switches.put(3L, sw3); - switches.put(4L, sw4); - mockFloodlightProvider.setSwitches(switches); - - // Create the links between the switches - // (Switch 4) --> (Switch 3) --> (Switch 2) --> (Switch 1) - Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>(); - Link link = new Link(2L, (short) 3, 1L, (short) 1); - Link link2 = new Link(3L, (short) 3, 2L, (short) 1); - Link link3 = new Link(4L, (short) 3, 3L, (short) 1); - LinkInfo linkinfo = null; - links.put(link, linkinfo); - links.put(link2, linkinfo); - links.put(link3, linkinfo); - - // Make sure that the link discovery service provides the link we made - expect(lds.getLinks()).andReturn(links).anyTimes(); - replay(lds); - - // Reconcile flows with specified OFMatchReconcile - pdr.reconcileFlows(lofmr); - // Validate results - verify(sw1, sw2, sw3, sw4); - - // Make sure each capture is not null - assertTrue(wc2.hasCaptured()); - assertTrue(wc3.hasCaptured()); - assertTrue(wc4.hasCaptured()); - - // Make sure each capture has captured the proper Flow Mod Delete - // message - List<OFMessage> msglist = wc2.getValues().get(0); - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm2, m); - } - - msglist = wc3.getValues().get(0); - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm2, m); - } - - msglist = wc4.getValues().get(0); - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm2, m); - } - } - - /** - * This tests the port down reconciliation in the event that the base switch - * has three separate neighboring switches with invalid flows. It discovers - * that is has 3 neighbors and each of them delete flows with the specific - * OFMatch and outPort. - * - * @verify checks to see that a general clearFlowMods(Short outPort) is - * called on the base switch while specific clearFlowMods(OFMatch - * match, Short outPort) are called on the neighboring switches - * @throws Exception - */ - @Test - public void testMultipleLinkPortDownReconciliation() throws Exception { - log.debug("Starting multiple link port down reconciliation test"); - - // Load the switch map - switches = new HashMap<Long, IOFSwitch>(); - switches.put(1L, sw1); - switches.put(2L, sw2); - switches.put(3L, sw3); - switches.put(4L, sw4); - mockFloodlightProvider.setSwitches(switches); - - // Create the links between the switches - // (Switch 4 output port 3) --> (Switch 1 input port 1) - // (Switch 3 output port 3) --> (Switch 1 input port 1) - // (Switch 2 output port 3) --> (Switch 1 input port 1) - Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>(); - Link link = new Link(2L, (short) 3, 1L, (short) 1); - Link link2 = new Link(3L, (short) 3, 1L, (short) 1); - Link link3 = new Link(4L, (short) 3, 1L, (short) 1); - LinkInfo linkinfo = null; - links.put(link, linkinfo); - links.put(link2, linkinfo); - links.put(link3, linkinfo); - - // Make sure that the link discovery service provides the link we made - expect(lds.getLinks()).andReturn(links).anyTimes(); - replay(lds); - - // Reconcile flows with specified OFMatchReconcile - pdr.reconcileFlows(lofmr); - // Validate results - verify(sw1, sw2, sw3, sw4); - - // Make sure each capture is not null - assertTrue(wc2.hasCaptured()); - assertTrue(wc3.hasCaptured()); - assertTrue(wc4.hasCaptured()); - - // Make sure each capture has captured the proper Flow Mod Delete - // message - List<OFMessage> msglist = wc2.getValues().get(0); - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm2, m); - } - - msglist = wc3.getValues().get(0); - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm2, m); - } - - msglist = wc4.getValues().get(0); - for (OFMessage m : msglist) { - if (m instanceof OFFlowMod) assertEquals(fm2, m); - } - } -} diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java deleted file mode 100644 index 1209cb1842c2d2373d20dcc510543e6149df7be4..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java +++ /dev/null @@ -1,526 +0,0 @@ -/** -* 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; - -import static org.easymock.EasyMock.*; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; -import net.floodlightcontroller.devicemanager.test.MockDeviceManager; -import net.floodlightcontroller.counter.CounterStore; -import net.floodlightcontroller.counter.ICounterStoreService; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.devicemanager.IEntityClassifierService; -import net.floodlightcontroller.packet.Data; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyListener; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; -import net.floodlightcontroller.flowcache.FlowReconcileManager; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.forwarding.Forwarding; - -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.easymock.EasyMock; -import org.junit.Test; -import org.openflow.protocol.OFFeaturesReply; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.util.HexString; -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 FlowReconcileManager flowReconcileMgr; - 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; - - @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(); - flowReconcileMgr = new FlowReconcileManager(); - 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(ICounterStoreService.class, new CounterStore()); - fmc.addService(IDeviceService.class, deviceManager); - fmc.addService(IFlowReconcileService.class, flowReconcileMgr); - fmc.addService(IEntityClassifierService.class, entityClassifier); - fmc.addService(ISyncService.class, mockSyncService); - - topology.addListener(anyObject(ITopologyListener.class)); - expectLastCall().anyTimes(); - replay(topology); - - threadPool.init(fmc); - mockSyncService.init(fmc); - forwarding.init(fmc); - deviceManager.init(fmc); - flowReconcileMgr.init(fmc); - entityClassifier.init(fmc); - threadPool.startUp(fmc); - mockSyncService.startUp(fmc); - deviceManager.startUp(fmc); - forwarding.startUp(fmc); - flowReconcileMgr.startUp(fmc); - entityClassifier.startUp(fmc); - verify(topology); - - swFeatures = new OFFeaturesReply(); - swFeatures.setBuffers(1000); - // Mock switches - sw1 = EasyMock.createMock(IOFSwitch.class); - expect(sw1.getId()).andReturn(1L).anyTimes(); - expect(sw1.getBuffers()).andReturn(swFeatures.getBuffers()).anyTimes(); - expect(sw1.getStringId()) - .andReturn(HexString.toHexString(1L)).anyTimes(); - - sw2 = EasyMock.createMock(IOFSwitch.class); - expect(sw2.getId()).andReturn(2L).anyTimes(); - expect(sw2.getBuffers()).andReturn(swFeatures.getBuffers()).anyTimes(); - expect(sw2.getStringId()) - .andReturn(HexString.toHexString(2L)).anyTimes(); - - //fastWilcards mocked as this constant - int fastWildcards = - OFMatch.OFPFW_IN_PORT | - OFMatch.OFPFW_NW_PROTO | - OFMatch.OFPFW_TP_SRC | - OFMatch.OFPFW_TP_DST | - OFMatch.OFPFW_NW_SRC_ALL | - OFMatch.OFPFW_NW_DST_ALL | - OFMatch.OFPFW_NW_TOS; - - expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); - expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); - - expect(sw2.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); - expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); - - // Load the switch map - Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); - switches.put(1L, sw1); - switches.put(2L, sw2); - mockFloodlightProvider.setSwitches(switches); - - // Build test packet - testPacket = new Ethernet() - .setDestinationMACAddress("00:11:22:33:44:55") - .setSourceMACAddress("00:44:33:22:11:00") - .setEtherType(Ethernet.TYPE_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 = - ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(testPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) testPacketSerialized.length); - - // Mock Packet-out - packetOut = - (OFPacketOut) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.PACKET_OUT); - packetOut.setBufferId(this.packetIn.getBufferId()) - .setInPort(this.packetIn.getInPort()); - List<OFAction> poactions = new ArrayList<OFAction>(); - poactions.add(new OFActionOutput((short) 3, (short) 0xffff)); - packetOut.setActions(poactions) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setPacketData(testPacketSerialized) - .setLengthU(OFPacketOut.MINIMUM_LENGTH+ - packetOut.getActionsLength()+ - testPacketSerialized.length); - - // Mock Packet-out with OFPP_FLOOD action - packetOutFlooded = - (OFPacketOut) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.PACKET_OUT); - packetOutFlooded.setBufferId(this.packetIn.getBufferId()) - .setInPort(this.packetIn.getInPort()); - poactions = new ArrayList<OFAction>(); - poactions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(), - (short) 0xffff)); - packetOutFlooded.setActions(poactions) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setPacketData(testPacketSerialized) - .setLengthU(OFPacketOut.MINIMUM_LENGTH+ - packetOutFlooded.getActionsLength()+ - testPacketSerialized.length); - - expected_wildcards = fastWildcards; - expected_wildcards &= ~OFMatch.OFPFW_IN_PORT & - ~OFMatch.OFPFW_DL_VLAN & - ~OFMatch.OFPFW_DL_SRC & - ~OFMatch.OFPFW_DL_DST; - expected_wildcards &= ~OFMatch.OFPFW_NW_SRC_MASK & - ~OFMatch.OFPFW_NW_DST_MASK; - - 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 - byte[] dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress(); - byte[] dataLayerDest = - ((Ethernet)testPacket).getDestinationMACAddress(); - int networkSource = - ((IPv4)((Ethernet)testPacket).getPayload()). - getSourceAddress(); - int networkDest = - ((IPv4)((Ethernet)testPacket).getPayload()). - getDestinationAddress(); - - reset(topology); - expect(topology.isAttachmentPointPort(1L, (short)1)) - .andReturn(true) - .anyTimes(); - expect(topology.isAttachmentPointPort(2L, (short)3)) - .andReturn(true) - .anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)3)) - .andReturn(true) - .anyTimes(); - replay(topology); - - srcDevice = - deviceManager.learnEntity(Ethernet.toLong(dataLayerSource), - null, networkSource, - 1L, 1); - IDeviceService.fcStore. put(cntx, - IDeviceService.CONTEXT_SRC_DEVICE, - srcDevice); - if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) { - dstDevice1 = - deviceManager.learnEntity(Ethernet.toLong(dataLayerDest), - null, networkDest, - 2L, 3); - IDeviceService.fcStore.put(cntx, - IDeviceService.CONTEXT_DST_DEVICE, - dstDevice1); - } - if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) { - dstDevice2 = - deviceManager.learnEntity(Ethernet.toLong(dataLayerDest), - null, networkDest, - 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); - Capture<FloodlightContext> bc1 = - new Capture<FloodlightContext>(CaptureType.ALL); - Capture<FloodlightContext> bc2 = - new Capture<FloodlightContext>(CaptureType.ALL); - - - Route route = new Route(1L, 2L); - List<NodePortTuple> nptList = new ArrayList<NodePortTuple>(); - nptList.add(new NodePortTuple(1L, (short)1)); - nptList.add(new NodePortTuple(1L, (short)3)); - nptList.add(new NodePortTuple(2L, (short)1)); - nptList.add(new NodePortTuple(2L, (short)3)); - route.setPath(nptList); - expect(routingEngine.getRoute(1L, (short)1, 2L, (short)3, 0)).andReturn(route).atLeastOnce(); - - // Expected Flow-mods - OFMatch match = new OFMatch(); - match.loadFromPacket(testPacketSerialized, (short) 1); - OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - OFFlowMod fm1 = - (OFFlowMod) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.FLOW_MOD); - fm1.setIdleTimeout((short)5) - .setMatch(match.clone() - .setWildcards(expected_wildcards)) - .setActions(actions) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setCookie(2L << 52) - .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); - OFFlowMod fm2 = fm1.clone(); - ((OFActionOutput)fm2.getActions().get(0)).setPort((short) 3); - - sw1.writeThrottled(capture(wc1), capture(bc1)); - expectLastCall().anyTimes(); - sw2.writeThrottled(capture(wc2), capture(bc2)); - expectLastCall().anyTimes(); - - reset(topology); - expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(2L, (short)3)).andReturn(true).anyTimes(); - expect(topology.isIncomingBroadcastAllowed(anyLong(), 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) - assertEquals(fm1, m); - else if (m instanceof OFPacketOut) - assertEquals(packetOut, m); - } - - OFMessage m = wc2.getValue(); - assert (m instanceof OFFlowMod); - assertTrue(m.equals(fm2)); - } - - @Test - public void testForwardSingleSwitchPath() throws Exception { - learnDevices(DestDeviceToLearn.DEVICE2); - - Route route = new Route(1L, 1L); - route.getPath().add(new NodePortTuple(1L, (short)1)); - route.getPath().add(new NodePortTuple(1L, (short)3)); - expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3, 0)).andReturn(route).atLeastOnce(); - - // Expected Flow-mods - OFMatch match = new OFMatch(); - match.loadFromPacket(testPacketSerialized, (short) 1); - OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - OFFlowMod fm1 = - (OFFlowMod) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.FLOW_MOD); - fm1.setIdleTimeout((short)5) - .setMatch(match.clone() - .setWildcards(expected_wildcards)) - .setActions(actions) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setCookie(2L << 52) - .setLengthU(OFFlowMod.MINIMUM_LENGTH + - OFActionOutput.MINIMUM_LENGTH); - - // Record expected packet-outs/flow-mods - sw1.writeThrottled(fm1, cntx); - sw1.writeThrottled(packetOut, cntx); - - reset(topology); - expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); - expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)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); - } - - @Test - public void testFlowModDampening() throws Exception { - learnDevices(DestDeviceToLearn.DEVICE2); - - reset(topology); - expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort())) - .andReturn(true).anyTimes(); - expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - replay(topology); - - - Route route = new Route(1L, 1L); - route.getPath().add(new NodePortTuple(1L, (short)1)); - route.getPath().add(new NodePortTuple(1L, (short)3)); - expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3, 0)).andReturn(route).atLeastOnce(); - - // Expected Flow-mods - OFMatch match = new OFMatch(); - match.loadFromPacket(testPacketSerialized, (short) 1); - OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); - List<OFAction> actions = new ArrayList<OFAction>(); - actions.add(action); - - OFFlowMod fm1 = - (OFFlowMod) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.FLOW_MOD); - fm1.setIdleTimeout((short)5) - .setMatch(match.clone() - .setWildcards(expected_wildcards)) - .setActions(actions) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setCookie(2L << 52) - .setLengthU(OFFlowMod.MINIMUM_LENGTH + - OFActionOutput.MINIMUM_LENGTH); - - // 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.writeThrottled(fm1, cntx); - expectLastCall().once(); - sw1.writeThrottled(packetOut, cntx); - expectLastCall().times(3); - - reset(topology); - expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); - expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)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 - - // Reset mocks, trigger the packet in, and validate results - reset(topology); - expect(topology.isIncomingBroadcastAllowed(1L, (short)1)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(EasyMock.anyLong(), - EasyMock.anyShort())) - .andReturn(true) - .anyTimes(); - expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) - .andReturn(true).anyTimes(); - sw1.writeThrottled(packetOutFlooded, cntx); - expectLastCall().once(); - replay(sw1, sw2, routingEngine, topology); - forwarding.receive(sw1, this.packetIn, cntx); - verify(sw1, sw2, routingEngine); - } - -} diff --git a/src/test/java/net/floodlightcontroller/hub/HubTest.java b/src/test/java/net/floodlightcontroller/hub/HubTest.java index 22dfd855ffb94d0cbb0587b769ecb47eaefde552..ecef81215eb24b6ff2a2f1e625585a2184481817 100644 --- a/src/test/java/net/floodlightcontroller/hub/HubTest.java +++ b/src/test/java/net/floodlightcontroller/hub/HubTest.java @@ -21,10 +21,11 @@ import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.easymock.EasyMock.capture; +import static org.junit.Assert.*; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; -import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.test.MockFloodlightProvider; @@ -39,14 +40,18 @@ import org.easymock.Capture; import org.easymock.CaptureType; import org.junit.Before; import org.junit.Test; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.OFFactories; +import org.projectfloodlight.openflow.protocol.OFPacketIn; +import org.projectfloodlight.openflow.protocol.OFPacketInReason; +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFPacketOut; +import org.projectfloodlight.openflow.protocol.OFType; +import org.projectfloodlight.openflow.protocol.OFVersion; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.match.MatchField; +import org.projectfloodlight.openflow.types.OFBufferId; +import org.projectfloodlight.openflow.types.OFPort; /** * @@ -56,7 +61,7 @@ public class HubTest extends FloodlightTestCase { protected OFPacketIn packetIn; protected IPacket testPacket; protected byte[] testPacketSerialized; - private MockFloodlightProvider mockFloodlightProvider; + private MockFloodlightProvider mockFloodlightProvider; private Hub hub; @Before @@ -85,33 +90,36 @@ public class HubTest extends FloodlightTestCase { this.testPacketSerialized = testPacket.serialize(); // Build the PacketIn - this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(this.testPacketSerialized) + //TODO @Ryan should this just be OF_13 or include OF_10 too? + this.packetIn = (OFPacketIn) 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.testPacketSerialized) .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) this.testPacketSerialized.length); + .setTotalLen((short) this.testPacketSerialized.length).build(); } @Test public void testFloodNoBufferId() throws Exception { - // build our expected flooded packetOut - OFPacketOut po = ((OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT)) - .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())})) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(this.testPacketSerialized); - po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU() - + this.testPacketSerialized.length); - // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); + // build our expected flooded packetOut + OFActionOutput ao = OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput().setPort(OFPort.FLOOD).build(); + List<OFAction> al = new ArrayList<OFAction>(); + al.add(ao); + OFPacketOut po = OFFactories.getFactory(OFVersion.OF_13).buildPacketOut() + .setActions(al) + .setBufferId(OFBufferId.NO_BUFFER) + .setXid(1) + .setInPort(OFPort.of(1)) + .setData(this.testPacketSerialized).build(); + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); - Capture<FloodlightContext> bc1 = new Capture<FloodlightContext>(CaptureType.ALL); - mockSwitch.write(capture(wc1), capture(bc1)); + mockSwitch.write(capture(wc1)); // Start recording the replay on the mocks replay(mockSwitch); @@ -126,28 +134,34 @@ public class HubTest extends FloodlightTestCase { assertTrue(wc1.hasCaptured()); OFMessage m = wc1.getValue(); + //TODO @Ryan the wc1 message has inport=ANY and the next xid + // Can this be asserted anymore with OF1.3? assertEquals(po, m); } @Test public void testFloodBufferId() throws Exception { MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider(); - this.packetIn.setBufferId(10); - + this.packetIn = this.packetIn.createBuilder() + .setBufferId(OFBufferId.of(10)) + .setXid(1) + .build(); + + OFActionOutput ao = OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput().setPort(OFPort.FLOOD).build(); + List<OFAction> al = new ArrayList<OFAction>(); + al.add(ao); // build our expected flooded packetOut - OFPacketOut po = ((OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT)) - .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())})) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setBufferId(10) - .setInPort((short) 1); - po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU()); + OFPacketOut po = OFFactories.getFactory(OFVersion.OF_13).buildPacketOut() + .setActions(al) + .setXid(1) + .setBufferId(OFBufferId.of(10)) + .setInPort(OFPort.of(1)) + .build(); // Mock up our expected behavior IOFSwitch mockSwitch = createMock(IOFSwitch.class); - Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); - Capture<FloodlightContext> bc1 = new Capture<FloodlightContext>(CaptureType.ALL); - - mockSwitch.write(capture(wc1), capture(bc1)); + Capture<OFPacketOut> wc1 = new Capture<OFPacketOut>(CaptureType.ALL); + mockSwitch.write(capture(wc1)); // Start recording the replay on the mocks replay(mockSwitch); @@ -161,6 +175,9 @@ public class HubTest extends FloodlightTestCase { verify(mockSwitch); assertTrue(wc1.hasCaptured()); + //TODO @Ryan the wc1 message has inport=ANY, + // bufferid=NONE, and the next xid + // Can this be asserted anymore with OF1.3? OFMessage m = wc1.getValue(); assertEquals(po, m); } diff --git a/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java b/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java deleted file mode 100644 index d8da84ff89bea099c40af6792b7c0ad632a99514..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java +++ /dev/null @@ -1,255 +0,0 @@ -/** -* 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.learningswitch; - -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightTestModuleLoader; -import net.floodlightcontroller.core.module.IFloodlightModule; -import net.floodlightcontroller.core.test.MockFloodlightProvider; -import net.floodlightcontroller.packet.Data; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.test.FloodlightTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.action.OFActionType; - -/** - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public class LearningSwitchTest extends FloodlightTestCase { - protected OFPacketIn packetIn; - protected IPacket testPacket; - protected byte[] testPacketSerialized; - protected IPacket broadcastPacket; - protected byte[] broadcastPacketSerialized; - protected IPacket testPacketReply; - protected byte[] testPacketReplySerialized; - private LearningSwitch learningSwitch; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader(); - Collection<Class<? extends IFloodlightModule>> mods - = new ArrayList<Class<? extends IFloodlightModule>>(); - mods.add(LearningSwitch.class); - - fml.setupModules(mods, null); - learningSwitch = (LearningSwitch) fml.getModuleByName(LearningSwitch.class); - mockFloodlightProvider = - (MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class); - - // Build our test packet - this.testPacket = new Ethernet() - .setDestinationMACAddress("00:11:22:33:44:55") - .setSourceMACAddress("00:44:33:22:11:00") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_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})))); - this.testPacketSerialized = testPacket.serialize(); - // Build a broadcast packet - this.broadcastPacket = new Ethernet() - .setDestinationMACAddress("FF:FF:FF:FF:FF:FF") - .setSourceMACAddress("00:44:33:22:11:00") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.1") - .setDestinationAddress("192.168.255.255") - .setPayload(new UDP() - .setSourcePort((short) 5000) - .setDestinationPort((short) 5001) - .setPayload(new Data(new byte[] {0x01})))); - - this.broadcastPacketSerialized = broadcastPacket.serialize(); - this.testPacketReply = new Ethernet() - .setDestinationMACAddress("00:44:33:22:11:00") - .setSourceMACAddress("00:11:22:33:44:55") - .setVlanID((short) 42) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.2") - .setDestinationAddress("192.168.1.1") - .setPayload(new UDP() - .setSourcePort((short) 5001) - .setDestinationPort((short) 5000) - .setPayload(new Data(new byte[] {0x02})))); - this.testPacketReplySerialized = testPacketReply.serialize(); - - // Build the PacketIn - this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setInPort((short) 1) - .setPacketData(this.testPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) this.testPacketSerialized.length); - } - - @Test - public void testFlood() throws Exception { - // build our expected flooded packetOut - OFPacketOut po = new OFPacketOut() - .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())})) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setBufferId(-1) - .setInPort((short)1) - .setPacketData(this.testPacketSerialized); - po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU() - + this.testPacketSerialized.length); - - // Mock up our expected behavior - IOFSwitch mockSwitch = createMock(IOFSwitch.class); - expect(mockSwitch.getStringId()).andReturn("00:11:22:33:44:55:66:77").anyTimes(); - mockSwitch.write(po, null); - - // Start recording the replay on the mocks - replay(mockSwitch); - // Get the listener and trigger the packet in - IOFMessageListener listener = mockFloodlightProvider.getListeners().get( - OFType.PACKET_IN).get(0); - // Make sure it's the right listener - listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn)); - - // Verify the replay matched our expectations - short result = learningSwitch.getFromPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:44:33:22:11:00")), (short) 42).shortValue(); - verify(mockSwitch); - - // Verify the MAC table inside the switch - assertEquals(1, result); - } - - @Test - public void testFlowMod() throws Exception { - // tweak the test packet in since we need a bufferId - this.packetIn.setBufferId(50); - - // build expected flow mods - OFMessage fm1 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD)) - .setActions(Arrays.asList(new OFAction[] { - new OFActionOutput().setPort((short) 2).setMaxLength((short) -1)})) - .setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setCommand(OFFlowMod.OFPFC_ADD) - .setIdleTimeout((short) 5) - .setMatch(new OFMatch() - .loadFromPacket(testPacketSerialized, (short) 1) - .setWildcards(OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST - | OFMatch.OFPFW_NW_TOS)) - .setOutPort(OFPort.OFPP_NONE.getValue()) - .setCookie(1L << 52) - .setPriority((short) 100) - .setFlags((short)(1 << 0)) - .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); - OFMessage fm2 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD)) - .setActions(Arrays.asList(new OFAction[] { - new OFActionOutput().setPort((short) 1).setMaxLength((short) -1)})) - .setBufferId(-1) - .setCommand(OFFlowMod.OFPFC_ADD) - .setIdleTimeout((short) 5) - .setMatch(new OFMatch() - .loadFromPacket(testPacketReplySerialized, (short) 2) - .setWildcards(OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST - | OFMatch.OFPFW_NW_TOS)) - .setOutPort(OFPort.OFPP_NONE.getValue()) - .setCookie(1L << 52) - .setPriority((short) 100) - .setFlags((short)(1 << 0)) - .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); - - OFActionOutput ofAcOut = new OFActionOutput(); - ofAcOut.setMaxLength((short) -1); - ofAcOut.setPort((short)2); - ofAcOut.setLength((short) 8); - ofAcOut.setType(OFActionType.OUTPUT); - - OFPacketOut packetOut = new OFPacketOut(); - packetOut.setActions(Arrays.asList(new OFAction[] {ofAcOut})) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setBufferId(50) - .setInPort((short)1) - .setPacketData(null) - .setLength((short) (OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH)); - packetOut.setActionFactory(mockFloodlightProvider.getOFMessageFactory()); - - // Mock up our expected behavior - IOFSwitch mockSwitch = createMock(IOFSwitch.class); - expect(mockSwitch.getId()).andReturn(1L).anyTimes(); - expect(mockSwitch.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO - | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL - | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS)); - expect(mockSwitch.getBuffers()).andReturn(100).anyTimes(); - mockSwitch.write(packetOut, null); - mockSwitch.write(fm1, null); - mockSwitch.write(fm2, null); - - // Start recording the replay on the mocks - replay(mockSwitch); - - // Populate the MAC table - learningSwitch.addToPortMap(mockSwitch, - Ethernet.toLong(Ethernet.toMACAddress("00:11:22:33:44:55")), (short) 42, (short) 2); - - // Get the listener and trigger the packet in - IOFMessageListener listener = mockFloodlightProvider.getListeners().get( - OFType.PACKET_IN).get(0); - listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn)); - - // Verify the replay matched our expectations - short result = learningSwitch.getFromPortMap(mockSwitch, Ethernet.toLong(Ethernet.toMACAddress("00:44:33:22:11:00")), (short) 42).shortValue(); - verify(mockSwitch); - - // Verify the MAC table inside the switch - assertEquals(1, result); - } -} diff --git a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java deleted file mode 100644 index 940bd076ed4e4cecf46dd502c8466bbe4647596e..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java +++ /dev/null @@ -1,568 +0,0 @@ -/** -* 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.linkdiscovery.internal; - -import static org.easymock.EasyMock.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.createNiceMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IListener.Command; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.linkdiscovery.LinkInfo; -import net.floodlightcontroller.packet.Data; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestApiServer; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Link; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.memory.MemoryStorageSource; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; -import net.floodlightcontroller.topology.TopologyManager; - -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.OFPhysicalPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.factory.BasicFactory; -import org.openflow.util.HexString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public class LinkDiscoveryManagerTest extends FloodlightTestCase { - - private TestLinkDiscoveryManager ldm; - protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManagerTest.class); - - public class TestLinkDiscoveryManager extends LinkDiscoveryManager { - public boolean isSendLLDPsCalled = false; - public boolean isClearLinksCalled = false; - - @Override - protected void discoverOnAllPorts() { - isSendLLDPsCalled = true; - super.discoverOnAllPorts(); - } - - public void reset() { - isSendLLDPsCalled = false; - isClearLinksCalled = false; - } - - @Override - protected void clearAllLinks() { - isClearLinksCalled = true; - super.clearAllLinks(); - } - } - - public LinkDiscoveryManager getLinkDiscoveryManager() { - return ldm; - } - - private IOFSwitch createMockSwitch(Long id) { - IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class); - expect(mockSwitch.getId()).andReturn(id).anyTimes(); - return mockSwitch; - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - FloodlightModuleContext cntx = new FloodlightModuleContext(); - ldm = new TestLinkDiscoveryManager(); - TopologyManager routingEngine = new TopologyManager(); - ldm.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>(); - MockThreadPoolService tp = new MockThreadPoolService(); - RestApiServer restApi = new RestApiServer(); - cntx.addService(IRestApiService.class, restApi); - cntx.addService(IThreadPoolService.class, tp); - cntx.addService(IRoutingService.class, routingEngine); - cntx.addService(ILinkDiscoveryService.class, ldm); - cntx.addService(ITopologyService.class, ldm); - cntx.addService(IStorageSourceService.class, new MemoryStorageSource()); - cntx.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); - restApi.init(cntx); - tp.init(cntx); - routingEngine.init(cntx); - ldm.init(cntx); - restApi.startUp(cntx); - tp.startUp(cntx); - routingEngine.startUp(cntx); - ldm.startUp(cntx); - - IOFSwitch sw1 = createMockSwitch(1L); - IOFSwitch sw2 = createMockSwitch(2L); - Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); - switches.put(1L, sw1); - switches.put(2L, sw2); - getMockFloodlightProvider().setSwitches(switches); - replay(sw1, sw2); - } - - @Test - public void testAddOrUpdateLink() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - - Link lt = new Link(1L, 2, 2L, 1); - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - - - NodePortTuple srcNpt = new NodePortTuple(1L, 2); - NodePortTuple dstNpt = new NodePortTuple(2L, 1); - - // check invariants hold - assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(srcNpt)); - assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(dstNpt)); - assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt)); - assertTrue(linkDiscovery.links.containsKey(lt)); - } - - @Test - public void testDeleteLink() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - - Link lt = new Link(1L, 2, 2L, 1); - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - linkDiscovery.deleteLinks(Collections.singletonList(lt), "Test"); - - // check invariants hold - assertNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertNull(linkDiscovery.switchLinks.get(lt.getDst())); - assertNull(linkDiscovery.portLinks.get(lt.getSrc())); - assertNull(linkDiscovery.portLinks.get(lt.getDst())); - assertTrue(linkDiscovery.links.isEmpty()); - } - - @Test - public void testAddOrUpdateLinkToSelf() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - - Link lt = new Link(1L, 2, 2L, 3); - NodePortTuple srcNpt = new NodePortTuple(1L, 2); - NodePortTuple dstNpt = new NodePortTuple(2L, 3); - - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - - // check invariants hold - assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(srcNpt)); - assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(dstNpt)); - assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt)); - assertTrue(linkDiscovery.links.containsKey(lt)); - } - - @Test - public void testDeleteLinkToSelf() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - - Link lt = new Link(1L, 2, 1L, 3); - NodePortTuple srcNpt = new NodePortTuple(1L, 2); - NodePortTuple dstNpt = new NodePortTuple(2L, 3); - - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - linkDiscovery.deleteLinks(Collections.singletonList(lt), "Test to self"); - - // check invariants hold - assertNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertNull(linkDiscovery.switchLinks.get(lt.getDst())); - assertNull(linkDiscovery.portLinks.get(srcNpt)); - assertNull(linkDiscovery.portLinks.get(dstNpt)); - assertTrue(linkDiscovery.links.isEmpty()); - } - - @Test - public void testRemovedSwitch() { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - - Link lt = new Link(1L, 2, 2L, 1); - NodePortTuple srcNpt = new NodePortTuple(1L, 2); - NodePortTuple dstNpt = new NodePortTuple(2L, 1); - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - - IOFSwitch sw1 = getMockFloodlightProvider().getSwitch(1L); - IOFSwitch sw2 = getMockFloodlightProvider().getSwitch(2L); - // Mock up our expected behavior - linkDiscovery.switchRemoved(sw1.getId()); - verify(sw1, sw2); - - // check invariants hold - assertNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertNull(linkDiscovery.switchLinks.get(lt.getDst())); - assertNull(linkDiscovery.portLinks.get(srcNpt)); - assertNull(linkDiscovery.portLinks.get(dstNpt)); - assertTrue(linkDiscovery.links.isEmpty()); - } - - @Test - public void testRemovedSwitchSelf() { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - IOFSwitch sw1 = createMockSwitch(1L); - replay(sw1); - Link lt = new Link(1L, 2, 1L, 3); - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - - // Mock up our expected behavior - linkDiscovery.switchRemoved(sw1.getId()); - - verify(sw1); - // check invariants hold - assertNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertNull(linkDiscovery.portLinks.get(lt.getSrc())); - assertNull(linkDiscovery.portLinks.get(lt.getDst())); - assertTrue(linkDiscovery.links.isEmpty()); - } - - @Test - public void testAddUpdateLinks() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - - Link lt = new Link(1L, 1, 2L, 1); - NodePortTuple srcNpt = new NodePortTuple(1L, 1); - NodePortTuple dstNpt = new NodePortTuple(2L, 1); - - LinkInfo info; - - info = new LinkInfo(System.currentTimeMillis() - 40000, - System.currentTimeMillis() - 40000, null); - linkDiscovery.addOrUpdateLink(lt, info); - - // check invariants hold - assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(srcNpt)); - assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(dstNpt)); - assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt)); - assertTrue(linkDiscovery.links.containsKey(lt)); - - linkDiscovery.timeoutLinks(); - - - info = new LinkInfo(System.currentTimeMillis(),/* firstseen */ - null,/* unicast */ - System.currentTimeMillis()); - linkDiscovery.addOrUpdateLink(lt, info); - assertTrue(linkDiscovery.links.get(lt).getUnicastValidTime() == null); - assertTrue(linkDiscovery.links.get(lt).getMulticastValidTime() != null); - - - // Add a link info based on info that woudld be obtained from unicast LLDP - // Setting the unicast LLDP reception time to be 40 seconds old, so we can use - // this to test timeout after this test. Although the info is initialized - // with LT_OPENFLOW_LINK, the link property should be changed to LT_NON_OPENFLOW - // by the addOrUpdateLink method. - info = new LinkInfo(System.currentTimeMillis() - 40000, - System.currentTimeMillis() - 40000, null); - linkDiscovery.addOrUpdateLink(lt, info); - - // Expect to timeout the unicast Valid Time, but not the multicast Valid time - // So the link type should go back to non-openflow link. - linkDiscovery.timeoutLinks(); - assertTrue(linkDiscovery.links.get(lt).getUnicastValidTime() == null); - assertTrue(linkDiscovery.links.get(lt).getMulticastValidTime() != null); - - // Set the multicastValidTime to be old and see if that also times out. - info = new LinkInfo(System.currentTimeMillis() - 40000, - null, System.currentTimeMillis() - 40000); - linkDiscovery.addOrUpdateLink(lt, info); - linkDiscovery.timeoutLinks(); - assertTrue(linkDiscovery.links.get(lt) == null); - - // Test again only with multicast LLDP - info = new LinkInfo(System.currentTimeMillis() - 40000, - null, System.currentTimeMillis() - 40000); - linkDiscovery.addOrUpdateLink(lt, info); - assertTrue(linkDiscovery.links.get(lt).getUnicastValidTime() == null); - assertTrue(linkDiscovery.links.get(lt).getMulticastValidTime() != null); - - // Call timeout and check if link is no longer present. - linkDiscovery.timeoutLinks(); - assertTrue(linkDiscovery.links.get(lt) == null); - - // Start clean and see if loops are also added. - lt = new Link(1L, 1, 1L, 2); - srcNpt = new NodePortTuple(1L, 1); - dstNpt = new NodePortTuple(1L, 2); - info = new LinkInfo(System.currentTimeMillis() - 40000, - null, System.currentTimeMillis() - 40000); - linkDiscovery.addOrUpdateLink(lt, info); - - - // Start clean and see if loops are also added. - lt = new Link(1L, 1, 1L, 3); - srcNpt = new NodePortTuple(1L, 1); - dstNpt = new NodePortTuple(1L, 3); - info = new LinkInfo(System.currentTimeMillis() - 40000, - null, System.currentTimeMillis() - 40000); - linkDiscovery.addOrUpdateLink(lt, info); - - // Start clean and see if loops are also added. - lt = new Link(1L, 4, 1L, 5); - srcNpt = new NodePortTuple(1L, 4); - dstNpt = new NodePortTuple(1L, 5); - info = new LinkInfo(System.currentTimeMillis() - 40000, - null, System.currentTimeMillis() - 40000); - linkDiscovery.addOrUpdateLink(lt, info); - - // Start clean and see if loops are also added. - lt = new Link(1L, 3, 1L, 5); - srcNpt = new NodePortTuple(1L, 3); - dstNpt = new NodePortTuple(1L, 5); - info = new LinkInfo(System.currentTimeMillis() - 40000, - null, System.currentTimeMillis() - 40000); - linkDiscovery.addOrUpdateLink(lt, info); - } - - @Test - public void testHARoleChange() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - IOFSwitch sw1 = createMockSwitch(1L); - IOFSwitch sw2 = createMockSwitch(2L); - replay(sw1, sw2); - Link lt = new Link(1L, 2, 2L, 1); - NodePortTuple srcNpt = new NodePortTuple(1L, 2); - NodePortTuple dstNpt = new NodePortTuple(2L, 1); - LinkInfo info = new LinkInfo(System.currentTimeMillis(), - System.currentTimeMillis(), null); - linkDiscovery.addOrUpdateLink(lt, info); - - // check invariants hold - assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc())); - assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(srcNpt)); - assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt)); - assertNotNull(linkDiscovery.portLinks.get(dstNpt)); - assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt)); - assertTrue(linkDiscovery.links.containsKey(lt)); - - /* FIXME: what's the right thing to do here: - // check that it clears from memory - getMockFloodlightProvider().dispatchRoleChanged(Role.SLAVE); - assertTrue(linkDiscovery.switchLinks.isEmpty()); - getMockFloodlightProvider().dispatchRoleChanged(Role.MASTER); - // check that lldps were sent - assertTrue(ldm.isSendLLDPsCalled); - assertTrue(ldm.isClearLinksCalled); - ldm.reset(); - */ - } - - @Test - public void testSwitchAdded() throws Exception { - LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager(); - Capture<OFMessage> wc; - Capture<FloodlightContext> fc; - Set<Short> qPorts; - OFPhysicalPort ofpp = new OFPhysicalPort(); - ofpp.setName("eth4242"); - ofpp.setPortNumber((short)4242); - ofpp.setHardwareAddress(HexString.fromHexString("5c:16:c7:00:00:01")); - ofpp.setCurrentFeatures(0); - ImmutablePort p1 = ImmutablePort.fromOFPhysicalPort(ofpp); - IOFSwitch sw1 = createMockSwitch(1L); - - // Set switch map in floodlightProvider. - Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); - switches.put(1L, sw1); - getMockFloodlightProvider().setSwitches(switches); - - // Create the set of ports - List<Short> ports = new ArrayList<Short>(); - for(short p=1; p<=20; ++p) { - ports.add(p); - } - - // Set the captures. - wc = new Capture<OFMessage>(CaptureType.ALL); - fc = new Capture<FloodlightContext>(CaptureType.ALL); - - // Expect switch to return those ports. - expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes(); - expect(sw1.getPort(EasyMock.anyShort())).andReturn(p1).anyTimes(); - sw1.write(capture(wc), capture(fc)); - expectLastCall().anyTimes(); - replay(sw1); - - linkDiscovery.switchActivated(sw1.getId()); - verify(sw1); - - qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId()); - assertNotNull(qPorts); - assertFalse(qPorts.isEmpty()); - - Thread.sleep(100); - qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId()); - assertNotNull(qPorts); - assertFalse(qPorts.isEmpty()); - - Thread.sleep(200); - qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId()); - assertNotNull(qPorts); - assertTrue(qPorts.isEmpty()); - - // Ensure that through every switch port, an LLDP and BDDP - // packet was sent out. Total # of packets = # of ports * 2. - assertTrue(wc.hasCaptured()); - List<OFMessage> msgList = wc.getValues(); - assertTrue(msgList.size() == ports.size() * 2); - } - - private OFPacketIn createPacketIn(String srcMAC, String dstMAC, - String srcIp, String dstIp, short vlan) { - IPacket testPacket = new Ethernet() - .setDestinationMACAddress(dstMAC) - .setSourceMACAddress(srcMAC) - .setVlanID(vlan) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress(srcIp) - .setDestinationAddress(dstIp) - .setPayload(new UDP() - .setSourcePort((short) 5000) - .setDestinationPort((short) 5001) - .setPayload(new Data(new byte[] {0x01})))); - byte[] testPacketSerialized = testPacket.serialize(); - OFPacketIn pi; - // build out input packet - pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(testPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) testPacketSerialized.length); - return pi; - } - - @Test - public void testIgnoreSrcMAC() throws Exception { - String mac1 = "00:11:22:33:44:55"; - String mac2 = "00:44:33:22:11:00"; - String mac3 = "00:44:33:22:11:02"; - String srcIp = "192.168.1.1"; - String dstIp = "192.168.1.2"; - short vlan = 42; - - IOFSwitch mockSwitch = createMock(IOFSwitch.class); - expect(mockSwitch.getId()).andReturn(1L).anyTimes(); - replay(mockSwitch); - - /* TEST1: See basic packet flow */ - OFPacketIn pi; - pi = createPacketIn(mac1, mac2, srcIp, dstIp, vlan); - FloodlightContext cntx = new FloodlightContext(); - Ethernet eth = new Ethernet(); - eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - eth); - Command ret; - ret = ldm.receive(mockSwitch, pi, cntx); - assertEquals(Command.CONTINUE, ret); - - /* TEST2: Add mac1 to the ignore MAC list and see that the packet is - * dropped - */ - ldm.addMACToIgnoreList(HexString.toLong(mac1), 0); - ret = ldm.receive(mockSwitch, pi, cntx); - assertEquals(Command.STOP, ret); - /* Verify that if we send a packet with another MAC it still works */ - pi = createPacketIn(mac2, mac3, srcIp, dstIp, vlan); - cntx = new FloodlightContext(); - eth = new Ethernet(); - eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - eth); - ret = ldm.receive(mockSwitch, pi, cntx); - assertEquals(Command.CONTINUE, ret); - - /* TEST3: Add a MAC range and see if that is ignored */ - ldm.addMACToIgnoreList(HexString.toLong(mac2), 8); - ret = ldm.receive(mockSwitch, pi, cntx); - assertEquals(Command.STOP, ret); - /* Send a packet with source MAC as mac3 and see that that is ignored - * as well. - */ - pi = createPacketIn(mac3, mac1, srcIp, dstIp, vlan); - cntx = new FloodlightContext(); - eth = new Ethernet(); - eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - eth); - ret = ldm.receive(mockSwitch, pi, cntx); - assertEquals(Command.STOP, ret); - - verify(mockSwitch); - } -} \ 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 deleted file mode 100644 index b1f6b0253a4c0be0cec494d0767c18c58212119e..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java +++ /dev/null @@ -1,699 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.loadbalancer; - -import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyShort; -import static org.easymock.EasyMock.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.reset; -import static org.easymock.EasyMock.verify; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPacketOut; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.OFType; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.util.HexString; -import org.sdnplatform.sync.ISyncService; -import org.sdnplatform.sync.test.MockSyncService; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.counter.CounterStore; -import net.floodlightcontroller.counter.ICounterStoreService; -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.flowcache.FlowReconcileManager; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.packet.ARP; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.ICMP; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestApiServer; -import net.floodlightcontroller.routing.IRoutingService; -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; -import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.memory.MemoryStorageSource; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.topology.NodePortTuple; - -public class LoadBalancerTest extends FloodlightTestCase { - protected LoadBalancer lb; - - protected FloodlightContext cntx; - protected FloodlightModuleContext fmc; - protected MockDeviceManager deviceManager; - protected MockThreadPoolService tps; - protected FlowReconcileManager frm; - protected DefaultEntityClassifier entityClassifier; - protected IRoutingService routingEngine; - protected ITopologyService topology; - protected StaticFlowEntryPusher sfp; - protected MemoryStorageSource storage; - protected RestApiServer restApi; - protected VipsResource vipsResource; - protected PoolsResource poolsResource; - protected MembersResource membersResource; - private MockSyncService mockSyncService; - - protected LBVip vip1, vip2; - protected LBPool pool1, pool2, pool3; - protected LBMember member1, member2, member3, member4; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - lb = new LoadBalancer(); - - cntx = new FloodlightContext(); - fmc = new FloodlightModuleContext(); - entityClassifier = new DefaultEntityClassifier(); // dependency for device manager - frm = new FlowReconcileManager(); //dependency for device manager - tps = new MockThreadPoolService(); //dependency for device manager - deviceManager = new MockDeviceManager(); - topology = createMock(ITopologyService.class); - routingEngine = createMock(IRoutingService.class); - restApi = new RestApiServer(); - sfp = new StaticFlowEntryPusher(); - storage = new MemoryStorageSource(); //dependency for sfp - mockSyncService = new MockSyncService(); - - fmc.addService(IRestApiService.class, restApi); - fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); - fmc.addService(IEntityClassifierService.class, entityClassifier); - fmc.addService(IFlowReconcileService.class, frm); - fmc.addService(IThreadPoolService.class, tps); - fmc.addService(IDeviceService.class, deviceManager); - fmc.addService(ITopologyService.class, topology); - fmc.addService(IRoutingService.class, routingEngine); - fmc.addService(ICounterStoreService.class, new CounterStore()); - fmc.addService(IStaticFlowEntryPusherService.class, sfp); - fmc.addService(ILoadBalancerService.class, lb); - fmc.addService(IStorageSourceService.class, storage); - fmc.addService(ISyncService.class, mockSyncService); - - lb.init(fmc); - getMockFloodlightProvider().init(fmc); - entityClassifier.init(fmc); - frm.init(fmc); - tps.init(fmc); - mockSyncService.init(fmc); - deviceManager.init(fmc); - restApi.init(fmc); - sfp.init(fmc); - storage.init(fmc); - - topology.addListener(deviceManager); - expectLastCall().times(1); - replay(topology); - - lb.startUp(fmc); - getMockFloodlightProvider().startUp(fmc); - entityClassifier.startUp(fmc); - frm.startUp(fmc); - tps.startUp(fmc); - mockSyncService.startUp(fmc); - deviceManager.startUp(fmc); - restApi.startUp(fmc); - sfp.startUp(fmc); - storage.startUp(fmc); - - verify(topology); - - vipsResource = new VipsResource(); - poolsResource = new PoolsResource(); - membersResource = new MembersResource(); - - vip1=null; - vip2=null; - - pool1=null; - pool2=null; - pool3=null; - - member1=null; - member2=null; - member3=null; - member4=null; - } - - @Test - public void testCreateVip() { - String postData1, postData2; - IOException error = null; - - postData1 = "{\"id\":\"1\",\"name\":\"vip1\",\"protocol\":\"icmp\",\"address\":\"10.0.0.100\",\"port\":\"8\"}"; - postData2 = "{\"id\":\"2\",\"name\":\"vip2\",\"protocol\":\"tcp\",\"address\":\"10.0.0.200\",\"port\":\"100\"}"; - - try { - vip1 = vipsResource.jsonToVip(postData1); - } catch (IOException e) { - error = e; - } - try { - vip2 = vipsResource.jsonToVip(postData2); - } catch (IOException e) { - error = e; - } - - // verify correct parsing - assertFalse(vip1==null); - assertFalse(vip2==null); - assertTrue(error==null); - - lb.createVip(vip1); - lb.createVip(vip2); - - // verify correct creation - assertTrue(lb.vips.containsKey(vip1.id)); - assertTrue(lb.vips.containsKey(vip2.id)); - } - - @Test - public void testRemoveVip() { - - testCreateVip(); - - // verify correct initial condition - assertFalse(vip1==null); - assertFalse(vip2==null); - - lb.removeVip(vip1.id); - lb.removeVip(vip2.id); - - // verify correct removal - assertFalse(lb.vips.containsKey(vip1.id)); - assertFalse(lb.vips.containsKey(vip2.id)); - - } - - @Test - public void testCreatePool() { - String postData1, postData2, postData3; - IOException error = null; - - testCreateVip(); - - postData1 = "{\"id\":\"1\",\"name\":\"pool1\",\"protocol\":\"icmp\",\"vip_id\":\"1\"}"; - postData2 = "{\"id\":\"2\",\"name\":\"pool2\",\"protocol\":\"tcp\",\"vip_id\":\"2\"}"; - postData3 = "{\"id\":\"3\",\"name\":\"pool3\",\"protocol\":\"udp\",\"vip_id\":\"3\"}"; - - try { - pool1 = poolsResource.jsonToPool(postData1); - } catch (IOException e) { - error = e; - } - try { - pool2 = poolsResource.jsonToPool(postData2); - } catch (IOException e) { - error = e; - } - try { - pool3 = poolsResource.jsonToPool(postData3); - } catch (IOException e) { - error = e; - } - - // verify correct parsing - assertFalse(pool1==null); - assertFalse(pool2==null); - assertFalse(pool3==null); - assertTrue(error==null); - - lb.createPool(pool1); - lb.createPool(pool2); - lb.createPool(pool3); - - // verify successful creates; two registered with vips and one not - assertTrue(lb.pools.containsKey(pool1.id)); - assertTrue(lb.vips.get(pool1.vipId).pools.contains(pool1.id)); - assertTrue(lb.pools.containsKey(pool2.id)); - assertTrue(lb.vips.get(pool2.vipId).pools.contains(pool2.id)); - assertTrue(lb.pools.containsKey(pool3.id)); - assertFalse(lb.vips.containsKey(pool3.vipId)); - - } - - @Test - public void testRemovePool() { - testCreateVip(); - testCreatePool(); - - // verify correct initial condition - assertFalse(vip1==null); - assertFalse(vip2==null); - assertFalse(pool1==null); - assertFalse(pool2==null); - assertFalse(pool3==null); - - lb.removePool(pool1.id); - lb.removePool(pool2.id); - lb.removePool(pool3.id); - - // verify correct removal - assertFalse(lb.pools.containsKey(pool1.id)); - assertFalse(lb.pools.containsKey(pool2.id)); - assertFalse(lb.pools.containsKey(pool3.id)); - - //verify pool cleanup from vip - assertFalse(lb.vips.get(pool1.vipId).pools.contains(pool1.id)); - assertFalse(lb.vips.get(pool2.vipId).pools.contains(pool2.id)); - } - - @Test - public void testCreateMember() { - String postData1, postData2, postData3, postData4; - IOException error = null; - - testCreateVip(); - testCreatePool(); - - postData1 = "{\"id\":\"1\",\"address\":\"10.0.0.3\",\"port\":\"8\",\"pool_id\":\"1\"}"; - postData2 = "{\"id\":\"2\",\"address\":\"10.0.0.4\",\"port\":\"8\",\"pool_id\":\"1\"}"; - postData3 = "{\"id\":\"3\",\"address\":\"10.0.0.5\",\"port\":\"100\",\"pool_id\":\"2\"}"; - postData4 = "{\"id\":\"4\",\"address\":\"10.0.0.6\",\"port\":\"100\",\"pool_id\":\"2\"}"; - - try { - member1 = membersResource.jsonToMember(postData1); - } catch (IOException e) { - error = e; - } - try { - member2 = membersResource.jsonToMember(postData2); - } catch (IOException e) { - error = e; - } - try { - member3 = membersResource.jsonToMember(postData3); - } catch (IOException e) { - error = e; - } - try { - member4 = membersResource.jsonToMember(postData4); - } catch (IOException e) { - error = e; - } - - // verify correct parsing - assertFalse(member1==null); - assertFalse(member2==null); - assertFalse(member3==null); - assertFalse(member4==null); - assertTrue(error==null); - - lb.createMember(member1); - lb.createMember(member2); - lb.createMember(member3); - lb.createMember(member4); - - // add the same server a second time - lb.createMember(member1); - - // verify successful creates - assertTrue(lb.members.containsKey(member1.id)); - assertTrue(lb.members.containsKey(member2.id)); - assertTrue(lb.members.containsKey(member3.id)); - assertTrue(lb.members.containsKey(member4.id)); - - assertTrue(lb.pools.get(member1.poolId).members.size()==2); - assertTrue(lb.pools.get(member3.poolId).members.size()==2); - - // member1 should inherit valid vipId from pool - assertTrue(lb.vips.get(member1.vipId)!=null); - } - - @Test - public void testRemoveMember() { - testCreateVip(); - testCreatePool(); - testCreateMember(); - - // verify correct initial condition - assertFalse(vip1==null); - assertFalse(vip2==null); - assertFalse(pool1==null); - assertFalse(pool2==null); - assertFalse(pool3==null); - assertFalse(member1==null); - assertFalse(member2==null); - assertFalse(member3==null); - assertFalse(member4==null); - - lb.removeMember(member1.id); - lb.removeMember(member2.id); - lb.removeMember(member3.id); - lb.removeMember(member4.id); - - // verify correct removal - assertFalse(lb.members.containsKey(member1.id)); - assertFalse(lb.members.containsKey(member2.id)); - assertFalse(lb.members.containsKey(member3.id)); - assertFalse(lb.members.containsKey(member4.id)); - - //verify member cleanup from pool - assertFalse(lb.pools.get(member1.poolId).members.contains(member1.id)); - assertFalse(lb.pools.get(member2.poolId).members.contains(member2.id)); - assertFalse(lb.pools.get(member3.poolId).members.contains(member3.id)); - assertFalse(lb.pools.get(member4.poolId).members.contains(member4.id)); - - } - - @Test - public void testTwoSubsequentIcmpRequests() throws Exception { - testCreateVip(); - testCreatePool(); - testCreateMember(); - - IOFSwitch sw1; - - IPacket arpRequest1, arpReply1, icmpPacket1, icmpPacket2; - - byte[] arpRequest1Serialized; - byte[] arpReply1Serialized; - byte[] icmpPacket1Serialized, icmpPacket2Serialized; - - OFPacketIn arpRequestPacketIn1; - OFPacketIn icmpPacketIn1, icmpPacketIn2; - - OFPacketOut arpReplyPacketOut1; - - Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); - Capture<FloodlightContext> bc1 = - new Capture<FloodlightContext>(CaptureType.ALL); - - int fastWildcards = - OFMatch.OFPFW_IN_PORT | - OFMatch.OFPFW_NW_PROTO | - OFMatch.OFPFW_TP_SRC | - OFMatch.OFPFW_TP_DST | - OFMatch.OFPFW_NW_SRC_ALL | - OFMatch.OFPFW_NW_DST_ALL | - OFMatch.OFPFW_NW_TOS; - - sw1 = EasyMock.createNiceMock(IOFSwitch.class); - expect(sw1.getId()).andReturn(1L).anyTimes(); - expect(sw1.getStringId()).andReturn("00:00:00:00:00:01").anyTimes(); - expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); - expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); - sw1.writeThrottled(capture(wc1), capture(bc1)); - expectLastCall().anyTimes(); - sw1.flush(); - expectLastCall().anyTimes(); - - replay(sw1); - sfp.switchAdded(1L); - verify(sw1); - - /* Test plan: - * - two clients and two servers on sw1 port 1, 2, 3, 4 - * - mock arp request received towards vip1 from (1L, 1) - * - proxy arp got pushed out to (1L, 1)- check sw1 getting the packetout - * - mock icmp request received towards vip1 from (1L, 1) - * - device manager list of devices queried to identify source and dest devices - * - routing engine queried to get inbound and outbound routes - * - check getRoute calls and responses - * - sfp called to install flows - * - check sfp calls - */ - - // Build topology - reset(topology); - expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); - expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)2)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)3)).andReturn(true).anyTimes(); - expect(topology.isAttachmentPointPort(1L, (short)4)).andReturn(true).anyTimes(); - replay(topology); - - - - // Build arp packets - arpRequest1 = new Ethernet() - .setSourceMACAddress("00:00:00:00:00:01") - .setDestinationMACAddress("ff:ff:ff:ff:ff:ff") - .setEtherType(Ethernet.TYPE_ARP) - .setVlanID((short) 0) - .setPriorityCode((byte) 0) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REQUEST) - .setSenderHardwareAddress(HexString.fromHexString("00:00:00:00:00:01")) - .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.1")) - .setTargetHardwareAddress(HexString.fromHexString("00:00:00:00:00:00")) - .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.100"))); - - arpRequest1Serialized = arpRequest1.serialize(); - - arpRequestPacketIn1 = - ((OFPacketIn) getMockFloodlightProvider().getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(arpRequest1Serialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) arpRequest1Serialized.length); - - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet) arpRequest1); - - // Mock proxy arp packet-out - arpReply1 = new Ethernet() - .setSourceMACAddress(LBVip.LB_PROXY_MAC) - .setDestinationMACAddress(HexString.fromHexString("00:00:00:00:00:01")) - .setEtherType(Ethernet.TYPE_ARP) - .setVlanID((short) 0) - .setPriorityCode((byte) 0) - .setPayload( - new ARP() - .setHardwareType(ARP.HW_TYPE_ETHERNET) - .setProtocolType(ARP.PROTO_TYPE_IP) - .setHardwareAddressLength((byte) 6) - .setProtocolAddressLength((byte) 4) - .setOpCode(ARP.OP_REPLY) - .setSenderHardwareAddress(HexString.fromHexString(LBVip.LB_PROXY_MAC)) - .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.100")) - .setTargetHardwareAddress(HexString.fromHexString("00:00:00:00:00:01")) - .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.1"))); - - arpReply1Serialized = arpReply1.serialize(); - - arpReplyPacketOut1 = - (OFPacketOut) getMockFloodlightProvider().getOFMessageFactory(). - getMessage(OFType.PACKET_OUT); - arpReplyPacketOut1.setBufferId(OFPacketOut.BUFFER_ID_NONE) - .setInPort(OFPort.OFPP_NONE.getValue()); - List<OFAction> poactions = new ArrayList<OFAction>(); - poactions.add(new OFActionOutput(arpRequestPacketIn1.getInPort(), (short) 0xffff)); - arpReplyPacketOut1.setActions(poactions) - .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) - .setPacketData(arpReply1Serialized) - .setLengthU(OFPacketOut.MINIMUM_LENGTH+ - arpReplyPacketOut1.getActionsLength()+ - arpReply1Serialized.length); - - lb.receive(sw1, arpRequestPacketIn1, cntx); - verify(sw1, topology); - - assertTrue(wc1.hasCaptured()); // wc1 should get packetout - - List<OFMessage> msglist1 = wc1.getValues(); - - for (OFMessage m: msglist1) { - if (m instanceof OFPacketOut) - assertEquals(arpReplyPacketOut1, m); - else - assertTrue(false); // unexpected message - } - - // - // Skip arpRequest2 test - in reality this will happen, but for unit test the same logic - // is already validated with arpRequest1 test above - // - - // Build icmp packets - icmpPacket1 = new Ethernet() - .setSourceMACAddress("00:00:00:00:00:01") - .setDestinationMACAddress(LBVip.LB_PROXY_MAC) - .setEtherType(Ethernet.TYPE_IPv4) - .setVlanID((short) 0) - .setPriorityCode((byte) 0) - .setPayload( - new IPv4() - .setSourceAddress("10.0.0.1") - .setDestinationAddress("10.0.0.100") - .setProtocol(IPv4.PROTOCOL_ICMP) - .setPayload(new ICMP() - .setIcmpCode((byte) 0) - .setIcmpType((byte) 0))); - - icmpPacket1Serialized = icmpPacket1.serialize(); - - icmpPacketIn1 = - ((OFPacketIn) getMockFloodlightProvider().getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(icmpPacket1Serialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) icmpPacket1Serialized.length); - - icmpPacket2 = new Ethernet() - .setSourceMACAddress("00:00:00:00:00:02") - .setDestinationMACAddress(LBVip.LB_PROXY_MAC) - .setEtherType(Ethernet.TYPE_IPv4) - .setVlanID((short) 0) - .setPriorityCode((byte) 0) - .setPayload( - new IPv4() - .setSourceAddress("10.0.0.2") - .setDestinationAddress("10.0.0.100") - .setProtocol(IPv4.PROTOCOL_ICMP) - .setPayload(new ICMP() - .setIcmpCode((byte) 0) - .setIcmpType((byte) 0))); - - icmpPacket2Serialized = icmpPacket2.serialize(); - - icmpPacketIn2 = - ((OFPacketIn) getMockFloodlightProvider().getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 2) - .setPacketData(icmpPacket2Serialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) icmpPacket2Serialized.length); - - byte[] dataLayerSource1 = ((Ethernet)icmpPacket1).getSourceMACAddress(); - int networkSource1 = ((IPv4)((Ethernet)icmpPacket1).getPayload()).getSourceAddress(); - byte[] dataLayerDest1 = HexString.fromHexString("00:00:00:00:00:03"); - int networkDest1 = IPv4.toIPv4Address("10.0.0.3"); - byte[] dataLayerSource2 = ((Ethernet)icmpPacket2).getSourceMACAddress(); - int networkSource2 = ((IPv4)((Ethernet)icmpPacket2).getPayload()).getSourceAddress(); - byte[] dataLayerDest2 = HexString.fromHexString("00:00:00:00:00:04"); - int networkDest2 = IPv4.toIPv4Address("10.0.0.4"); - - deviceManager.learnEntity(Ethernet.toLong(dataLayerSource1), - null, networkSource1, - 1L, 1); - deviceManager.learnEntity(Ethernet.toLong(dataLayerSource2), - null, networkSource2, - 1L, 2); - deviceManager.learnEntity(Ethernet.toLong(dataLayerDest1), - null, networkDest1, - 1L, 3); - deviceManager.learnEntity(Ethernet.toLong(dataLayerDest2), - null, networkDest2, - 1L, 4); - - // in bound #1 - Route route1 = new Route(1L, 1L); - List<NodePortTuple> nptList1 = new ArrayList<NodePortTuple>(); - nptList1.add(new NodePortTuple(1L, (short)1)); - nptList1.add(new NodePortTuple(1L, (short)3)); - route1.setPath(nptList1); - expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3, 0)).andReturn(route1).atLeastOnce(); - - // outbound #1 - Route route2 = new Route(1L, 1L); - List<NodePortTuple> nptList2 = new ArrayList<NodePortTuple>(); - nptList2.add(new NodePortTuple(1L, (short)3)); - nptList2.add(new NodePortTuple(1L, (short)1)); - route2.setPath(nptList2); - expect(routingEngine.getRoute(1L, (short)3, 1L, (short)1, 0)).andReturn(route2).atLeastOnce(); - - // inbound #2 - Route route3 = new Route(1L, 1L); - List<NodePortTuple> nptList3 = new ArrayList<NodePortTuple>(); - nptList3.add(new NodePortTuple(1L, (short)2)); - nptList3.add(new NodePortTuple(1L, (short)4)); - route3.setPath(nptList3); - expect(routingEngine.getRoute(1L, (short)2, 1L, (short)4, 0)).andReturn(route3).atLeastOnce(); - - // outbound #2 - Route route4 = new Route(1L, 1L); - List<NodePortTuple> nptList4 = new ArrayList<NodePortTuple>(); - nptList4.add(new NodePortTuple(1L, (short)4)); - nptList4.add(new NodePortTuple(1L, (short)2)); - route4.setPath(nptList3); - expect(routingEngine.getRoute(1L, (short)4, 1L, (short)2, 0)).andReturn(route4).atLeastOnce(); - - replay(routingEngine); - - wc1.reset(); - - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet) icmpPacket1); - lb.receive(sw1, icmpPacketIn1, cntx); - - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet) icmpPacket2); - lb.receive(sw1, icmpPacketIn2, cntx); - - assertTrue(wc1.hasCaptured()); // wc1 should get packetout - - List<OFMessage> msglist2 = wc1.getValues(); - - assertTrue(msglist2.size()==2); // has inbound and outbound packetouts - // TODO: not seeing flowmods yet ... - - Map<String, OFFlowMod> map = sfp.getFlows("00:00:00:00:00:00:00:01"); - - assertTrue(map.size()==4); - } - - -} diff --git a/src/test/java/net/floodlightcontroller/routing/RouteTest.java b/src/test/java/net/floodlightcontroller/routing/RouteTest.java deleted file mode 100644 index 3bd0398980078d54d8275f721eb6ace1912045e2..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/routing/RouteTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/** -* 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.routing; - -import org.junit.Test; - -import net.floodlightcontroller.routing.Route; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.topology.NodePortTuple; - -/** - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public class RouteTest extends FloodlightTestCase { - @Test - public void testCloneable() throws Exception { - Route r1 = new Route(1L, 2L); - Route r2 = new Route(1L, 3L); - - assertNotSame(r1, r2); - assertNotSame(r1.getId(), r2.getId()); - - r1 = new Route(1L, 3L); - r1.getPath().add(new NodePortTuple(1L, (short)1)); - r1.getPath().add(new NodePortTuple(2L, (short)1)); - r1.getPath().add(new NodePortTuple(2L, (short)2)); - r1.getPath().add(new NodePortTuple(3L, (short)1)); - - r2.getPath().add(new NodePortTuple(1L, (short)1)); - r2.getPath().add(new NodePortTuple(2L, (short)1)); - r2.getPath().add(new NodePortTuple(2L, (short)2)); - r2.getPath().add(new NodePortTuple(3L, (short)1)); - - assertEquals(r1, r2); - - NodePortTuple temp = r2.getPath().remove(0); - assertNotSame(r1, r2); - - r2.getPath().add(0, temp); - assertEquals(r1, r2); - - r2.getPath().remove(1); - temp = new NodePortTuple(2L, (short)5); - r2.getPath().add(1, temp); - assertNotSame(r1, r2); - } -} diff --git a/src/test/java/net/floodlightcontroller/staticflowentry/StaticFlowTests.java b/src/test/java/net/floodlightcontroller/staticflowentry/StaticFlowTests.java deleted file mode 100644 index a1e33539ebcb2b7099740fd62d1116fd7364b782..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/staticflowentry/StaticFlowTests.java +++ /dev/null @@ -1,359 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.staticflowentry; - -import java.io.IOException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -import org.easymock.Capture; -import org.easymock.CaptureType; -import org.junit.Test; -import org.openflow.protocol.OFFlowMod; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPort; -import org.openflow.protocol.action.OFAction; -import org.openflow.protocol.action.OFActionOutput; -import org.openflow.protocol.action.OFActionStripVirtualLan; -import org.openflow.util.HexString; - - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockFloodlightProvider; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestApiServer; -import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; -import net.floodlightcontroller.storage.IStorageSourceService; -import net.floodlightcontroller.storage.memory.MemoryStorageSource; -import static net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher.*; -import static org.easymock.EasyMock.*; - -public class StaticFlowTests extends FloodlightTestCase { - - static String TestSwitch1DPID = "00:00:00:00:00:00:00:01"; - static int TotalTestRules = 3; - - /*** - * Create TestRuleXXX and the corresponding FlowModXXX - * for X = 1..3 - */ - static Map<String,Object> TestRule1; - static OFFlowMod FlowMod1; - static { - FlowMod1 = new OFFlowMod(); - TestRule1 = new HashMap<String,Object>(); - TestRule1.put(COLUMN_NAME, "TestRule1"); - TestRule1.put(COLUMN_SWITCH, TestSwitch1DPID); - // setup match - OFMatch match = new OFMatch(); - TestRule1.put(COLUMN_DL_DST, "00:20:30:40:50:60"); - match.fromString("dl_dst=00:20:30:40:50:60"); - // setup actions - List<OFAction> actions = new LinkedList<OFAction>(); - TestRule1.put(COLUMN_ACTIONS, "output=1"); - actions.add(new OFActionOutput((short)1, Short.MAX_VALUE)); - // done - FlowMod1.setMatch(match); - FlowMod1.setActions(actions); - FlowMod1.setBufferId(-1); - FlowMod1.setOutPort(OFPort.OFPP_NONE.getValue()); - FlowMod1.setPriority(Short.MAX_VALUE); - FlowMod1.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions - } - - static Map<String,Object> TestRule2; - static OFFlowMod FlowMod2; - - static { - FlowMod2 = new OFFlowMod(); - TestRule2 = new HashMap<String,Object>(); - TestRule2.put(COLUMN_NAME, "TestRule2"); - TestRule2.put(COLUMN_SWITCH, TestSwitch1DPID); - // setup match - OFMatch match = new OFMatch(); - TestRule2.put(COLUMN_NW_DST, "192.168.1.0/24"); - match.fromString("nw_dst=192.168.1.0/24"); - // setup actions - List<OFAction> actions = new LinkedList<OFAction>(); - TestRule2.put(COLUMN_ACTIONS, "output=1"); - actions.add(new OFActionOutput((short)1, Short.MAX_VALUE)); - // done - FlowMod2.setMatch(match); - FlowMod2.setActions(actions); - FlowMod2.setBufferId(-1); - FlowMod2.setOutPort(OFPort.OFPP_NONE.getValue()); - FlowMod2.setPriority(Short.MAX_VALUE); - FlowMod2.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions - - } - - - static Map<String,Object> TestRule3; - static OFFlowMod FlowMod3; - private StaticFlowEntryPusher staticFlowEntryPusher; - private IOFSwitch mockSwitch; - private Capture<OFMessage> writeCapture; - private Capture<FloodlightContext> contextCapture; - private Capture<List<OFMessage>> writeCaptureList; - private long dpid; - private IStorageSourceService storage; - static { - FlowMod3 = new OFFlowMod(); - TestRule3 = new HashMap<String,Object>(); - TestRule3.put(COLUMN_NAME, "TestRule3"); - TestRule3.put(COLUMN_SWITCH, TestSwitch1DPID); - // setup match - OFMatch match = new OFMatch(); - TestRule3.put(COLUMN_DL_DST, "00:20:30:40:50:60"); - TestRule3.put(COLUMN_DL_VLAN, 4096); - match.fromString("dl_dst=00:20:30:40:50:60,dl_vlan=4096"); - // setup actions - TestRule3.put(COLUMN_ACTIONS, "output=controller"); - List<OFAction> actions = new LinkedList<OFAction>(); - actions.add(new OFActionOutput(OFPort.OFPP_CONTROLLER.getValue(), Short.MAX_VALUE)); - // done - FlowMod3.setMatch(match); - FlowMod3.setActions(actions); - FlowMod3.setBufferId(-1); - FlowMod3.setOutPort(OFPort.OFPP_NONE.getValue()); - FlowMod3.setPriority(Short.MAX_VALUE); - FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 8); // 8 bytes of actions - - } - - private void verifyFlowMod(OFFlowMod testFlowMod, - OFFlowMod goodFlowMod) { - verifyMatch(testFlowMod, goodFlowMod); - verifyActions(testFlowMod, goodFlowMod); - // dont' bother testing the cookie; just copy it over - goodFlowMod.setCookie(testFlowMod.getCookie()); - // .. so we can continue to use .equals() - assertEquals(goodFlowMod, testFlowMod); - } - - - private void verifyMatch(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) { - assertEquals(goodFlowMod.getMatch(), testFlowMod.getMatch()); - } - - - private void verifyActions(OFFlowMod testFlowMod, OFFlowMod goodFlowMod) { - List<OFAction> goodActions = goodFlowMod.getActions(); - List<OFAction> testActions = testFlowMod.getActions(); - assertNotNull(goodActions); - assertNotNull(testActions); - assertEquals(goodActions.size(), testActions.size()); - // assumes actions are marshalled in same order; should be safe - for(int i = 0; i < goodActions.size(); i++) { - assertEquals(goodActions.get(i), testActions.get(i)); - } - - } - - - @Override - public void setUp() throws Exception { - super.setUp(); - staticFlowEntryPusher = new StaticFlowEntryPusher(); - storage = createStorageWithFlowEntries(); - dpid = HexString.toLong(TestSwitch1DPID); - - mockSwitch = createNiceMock(IOFSwitch.class); - writeCapture = new Capture<OFMessage>(CaptureType.ALL); - contextCapture = new Capture<FloodlightContext>(CaptureType.ALL); - writeCaptureList = new Capture<List<OFMessage>>(CaptureType.ALL); - - //OFMessageSafeOutStream mockOutStream = createNiceMock(OFMessageSafeOutStream.class); - mockSwitch.write(capture(writeCapture), capture(contextCapture)); - expectLastCall().anyTimes(); - mockSwitch.write(capture(writeCaptureList), capture(contextCapture)); - expectLastCall().anyTimes(); - mockSwitch.flush(); - expectLastCall().anyTimes(); - - - FloodlightModuleContext fmc = new FloodlightModuleContext(); - fmc.addService(IStorageSourceService.class, storage); - - MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider(); - Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>(); - switchMap.put(dpid, mockSwitch); - // NO ! expect(mockFloodlightProvider.getSwitches()).andReturn(switchMap).anyTimes(); - mockFloodlightProvider.setSwitches(switchMap); - fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); - RestApiServer restApi = new RestApiServer(); - fmc.addService(IRestApiService.class, restApi); - restApi.init(fmc); - staticFlowEntryPusher.init(fmc); - staticFlowEntryPusher.startUp(fmc); // again, to hack unittest - } - - @Test - public void testStaticFlowPush() throws Exception { - - // verify that flowpusher read all three entries from storage - assertEquals(TotalTestRules, staticFlowEntryPusher.countEntries()); - - // if someone calls mockSwitch.getOutputStream(), return mockOutStream instead - //expect(mockSwitch.getOutputStream()).andReturn(mockOutStream).anyTimes(); - - // if someone calls getId(), return this dpid instead - expect(mockSwitch.getId()).andReturn(dpid).anyTimes(); - expect(mockSwitch.getStringId()).andReturn(TestSwitch1DPID).anyTimes(); - replay(mockSwitch); - - // hook the static pusher up to the fake switch - staticFlowEntryPusher.switchAdded(dpid); - - verify(mockSwitch); - - // Verify that the switch has gotten some flow_mods - assertEquals(true, writeCapture.hasCaptured()); - assertEquals(TotalTestRules, writeCapture.getValues().size()); - - // Order assumes how things are stored in hash bucket; - // should be fixed because OFMessage.hashCode() is deterministic - OFFlowMod firstFlowMod = (OFFlowMod) writeCapture.getValues().get(2); - verifyFlowMod(firstFlowMod, FlowMod1); - OFFlowMod secondFlowMod = (OFFlowMod) writeCapture.getValues().get(1); - verifyFlowMod(secondFlowMod, FlowMod2); - OFFlowMod thirdFlowMod = (OFFlowMod) writeCapture.getValues().get(0); - verifyFlowMod(thirdFlowMod, FlowMod3); - - writeCapture.reset(); - contextCapture.reset(); - - - // delete two rules and verify they've been removed - // this should invoke staticFlowPusher.rowsDeleted() - storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule1"); - storage.deleteRow(StaticFlowEntryPusher.TABLE_NAME, "TestRule2"); - - assertEquals(1, staticFlowEntryPusher.countEntries()); - assertEquals(2, writeCapture.getValues().size()); - - OFFlowMod firstDelete = (OFFlowMod) writeCapture.getValues().get(0); - FlowMod1.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); - verifyFlowMod(firstDelete, FlowMod1); - - OFFlowMod secondDelete = (OFFlowMod) writeCapture.getValues().get(1); - FlowMod2.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); - verifyFlowMod(secondDelete, FlowMod2); - - // add rules back to make sure that staticFlowPusher.rowsInserted() works - writeCapture.reset(); - FlowMod2.setCommand(OFFlowMod.OFPFC_ADD); - storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2); - assertEquals(2, staticFlowEntryPusher.countEntries()); - assertEquals(1, writeCaptureList.getValues().size()); - List<OFMessage> outList = - writeCaptureList.getValues().get(0); - assertEquals(1, outList.size()); - OFFlowMod firstAdd = (OFFlowMod) outList.get(0); - verifyFlowMod(firstAdd, FlowMod2); - writeCapture.reset(); - contextCapture.reset(); - writeCaptureList.reset(); - - // now try an overwriting update, calling staticFlowPusher.rowUpdated() - TestRule3.put(COLUMN_DL_VLAN, 333); - storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); - assertEquals(2, staticFlowEntryPusher.countEntries()); - assertEquals(1, writeCaptureList.getValues().size()); - - outList = writeCaptureList.getValues().get(0); - assertEquals(2, outList.size()); - OFFlowMod removeFlowMod = (OFFlowMod) outList.get(0); - FlowMod3.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); - verifyFlowMod(removeFlowMod, FlowMod3); - FlowMod3.setCommand(OFFlowMod.OFPFC_ADD); - FlowMod3.getMatch().fromString("dl_dst=00:20:30:40:50:60,dl_vlan=333"); - OFFlowMod updateFlowMod = (OFFlowMod) outList.get(1); - verifyFlowMod(updateFlowMod, FlowMod3); - writeCaptureList.reset(); - - // now try an action modifying update, calling staticFlowPusher.rowUpdated() - TestRule3.put(COLUMN_ACTIONS, "output=controller,strip-vlan"); // added strip-vlan - storage.updateRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); - assertEquals(2, staticFlowEntryPusher.countEntries()); - assertEquals(1, writeCaptureList.getValues().size()); - - outList = writeCaptureList.getValues().get(0); - assertEquals(1, outList.size()); - OFFlowMod modifyFlowMod = (OFFlowMod) outList.get(0); - FlowMod3.setCommand(OFFlowMod.OFPFC_MODIFY_STRICT); - List<OFAction> modifiedActions = FlowMod3.getActions(); - modifiedActions.add(new OFActionStripVirtualLan()); // add the new action to what we should expect - FlowMod3.setActions(modifiedActions); - FlowMod3.setLengthU(OFFlowMod.MINIMUM_LENGTH + 16); // accommodate the addition of new actions - verifyFlowMod(modifyFlowMod, FlowMod3); - - } - - - IStorageSourceService createStorageWithFlowEntries() { - return populateStorageWithFlowEntries(new MemoryStorageSource()); - } - - IStorageSourceService populateStorageWithFlowEntries(IStorageSourceService storage) { - Set<String> indexedColumns = new HashSet<String>(); - indexedColumns.add(COLUMN_NAME); - storage.createTable(StaticFlowEntryPusher.TABLE_NAME, indexedColumns); - storage.setTablePrimaryKeyName(StaticFlowEntryPusher.TABLE_NAME, COLUMN_NAME); - - storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule1); - storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule2); - storage.insertRow(StaticFlowEntryPusher.TABLE_NAME, TestRule3); - - return storage; - } - - @Test - public void testHARoleChanged() throws IOException { - - assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID)); - assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1)); - assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2)); - assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3)); - - /* FIXME: what's the right behavior here ?? - // Send a notification that we've changed to slave - mfp.dispatchRoleChanged(Role.SLAVE); - // Make sure we've removed all our entries - assert(staticFlowEntryPusher.entry2dpid.isEmpty()); - assert(staticFlowEntryPusher.entriesFromStorage.isEmpty()); - - // Send a notification that we've changed to master - mfp.dispatchRoleChanged(Role.MASTER); - // Make sure we've learned the entries - assert(staticFlowEntryPusher.entry2dpid.containsValue(TestSwitch1DPID)); - assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod1)); - assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod2)); - assert(staticFlowEntryPusher.entriesFromStorage.containsValue(FlowMod3)); - */ - } -} diff --git a/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java b/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java index d127181907f0ca7036132f039006fd89b5eb3653..99e2d4e44458d4f123b8d7ca7a7978ffe85ff3ce 100644 --- a/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java +++ b/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java @@ -30,6 +30,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; + +import static org.junit.Assert.*; +import org.junit.Test; + import net.floodlightcontroller.restserver.RestApiServer; import net.floodlightcontroller.storage.CompoundPredicate; import net.floodlightcontroller.storage.IStorageExceptionHandler; @@ -44,7 +48,6 @@ import net.floodlightcontroller.storage.RowOrdering; import net.floodlightcontroller.storage.nosql.NoSqlStorageSource; import net.floodlightcontroller.test.FloodlightTestCase; -import org.junit.Test; public abstract class StorageTest extends FloodlightTestCase { diff --git a/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java b/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java deleted file mode 100644 index 94496dc2266131b7499085087b29d58eaf785cfa..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java +++ /dev/null @@ -1,104 +0,0 @@ -/** -* 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.test; - -import junit.framework.TestCase; -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.test.MockFloodlightProvider; -import net.floodlightcontroller.devicemanager.IDevice; -import net.floodlightcontroller.devicemanager.IDeviceService; -import net.floodlightcontroller.packet.Ethernet; - -import org.junit.Test; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFPhysicalPort; -import org.openflow.protocol.OFType; - -/** - * This class gets a handle on the application context which is used to - * retrieve Spring beans from during tests - * - * @author David Erickson (daviderickson@cs.stanford.edu) - */ -public class FloodlightTestCase extends TestCase { - protected MockFloodlightProvider mockFloodlightProvider; - - public MockFloodlightProvider getMockFloodlightProvider() { - return mockFloodlightProvider; - } - - public void setMockFloodlightProvider(MockFloodlightProvider mockFloodlightProvider) { - this.mockFloodlightProvider = mockFloodlightProvider; - } - - public FloodlightContext parseAndAnnotate(OFMessage m, - IDevice srcDevice, - IDevice dstDevice) { - FloodlightContext bc = new FloodlightContext(); - return parseAndAnnotate(bc, m, srcDevice, dstDevice); - } - - public FloodlightContext parseAndAnnotate(OFMessage m) { - return parseAndAnnotate(m, null, null); - } - - public FloodlightContext parseAndAnnotate(FloodlightContext bc, - OFMessage m, - IDevice srcDevice, - IDevice dstDevice) { - if (OFType.PACKET_IN.equals(m.getType())) { - OFPacketIn pi = (OFPacketIn)m; - Ethernet eth = new Ethernet(); - eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length); - IFloodlightProviderService.bcStore.put(bc, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - eth); - } - if (srcDevice != null) { - IDeviceService.fcStore.put(bc, - IDeviceService.CONTEXT_SRC_DEVICE, - srcDevice); - } - if (dstDevice != null) { - IDeviceService.fcStore.put(bc, - IDeviceService.CONTEXT_DST_DEVICE, - dstDevice); - } - return bc; - } - - @Override - public void setUp() throws Exception { - mockFloodlightProvider = new MockFloodlightProvider(); - } - - @Test - public void testSanity() throws Exception { - assertTrue(true); - } - - public static OFPhysicalPort createOFPhysicalPort(String name, int number) { - OFPhysicalPort p = new OFPhysicalPort(); - p.setHardwareAddress(new byte [] { 0, 0, 0, 0, 0, 0 }); - p.setPortNumber((short)number); - p.setName(name); - return p; - } -} diff --git a/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java b/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java deleted file mode 100644 index 58d76fe4dc5bc7079a6e9ebce2f637931632dbb2..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java +++ /dev/null @@ -1,470 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import static org.junit.Assert.*; - -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockFloodlightProvider; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; -import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.NodePortTuple; -import net.floodlightcontroller.topology.TopologyInstance; -import net.floodlightcontroller.topology.TopologyManager; - -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TopologyInstanceTest { - protected static Logger log = LoggerFactory.getLogger(TopologyInstanceTest.class); - protected TopologyManager topologyManager; - protected FloodlightModuleContext fmc; - protected ILinkDiscoveryService linkDiscovery; - protected MockFloodlightProvider mockFloodlightProvider; - - protected int DIRECT_LINK = 1; - protected int MULTIHOP_LINK = 2; - protected int TUNNEL_LINK = 3; - - @Before - public void SetUp() throws Exception { - fmc = new FloodlightModuleContext(); - linkDiscovery = EasyMock.createMock(ILinkDiscoveryService.class); - mockFloodlightProvider = new MockFloodlightProvider(); - fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider); - fmc.addService(ILinkDiscoveryService.class, linkDiscovery); - MockThreadPoolService tp = new MockThreadPoolService(); - topologyManager = new TopologyManager(); - fmc.addService(IThreadPoolService.class, tp); - topologyManager.init(fmc); - tp.init(fmc); - tp.startUp(fmc); - } - - protected void verifyClusters(int[][] clusters) { - verifyClusters(clusters, true); - } - - protected void verifyClusters(int[][] clusters, boolean tunnelsEnabled) { - List<Long> verifiedSwitches = new ArrayList<Long>(); - - // Make sure the expected cluster arrays are sorted so we can - // use binarySearch to test for membership - for (int i = 0; i < clusters.length; i++) - Arrays.sort(clusters[i]); - - TopologyInstance ti = - topologyManager.getCurrentInstance(tunnelsEnabled); - Set<Long> switches = ti.getSwitches(); - - for (long sw: switches) { - if (!verifiedSwitches.contains(sw)) { - - int[] expectedCluster = null; - - for (int j = 0; j < clusters.length; j++) { - if (Arrays.binarySearch(clusters[j], (int) sw) >= 0) { - expectedCluster = clusters[j]; - break; - } - } - if (expectedCluster != null) { - Set<Long> cluster = ti.getSwitchesInOpenflowDomain(sw); - assertEquals(expectedCluster.length, cluster.size()); - for (long sw2: cluster) { - assertTrue(Arrays.binarySearch(expectedCluster, (int)sw2) >= 0); - verifiedSwitches.add(sw2); - } - } - } - } - } - - protected void - verifyExpectedBroadcastPortsInClusters(int [][][] ebp) { - verifyExpectedBroadcastPortsInClusters(ebp, true); - } - - protected void - verifyExpectedBroadcastPortsInClusters(int [][][] ebp, - boolean tunnelsEnabled) { - NodePortTuple npt = null; - Set<NodePortTuple> expected = new HashSet<NodePortTuple>(); - for(int i=0; i<ebp.length; ++i) { - int [][] nptList = ebp[i]; - expected.clear(); - for(int j=0; j<nptList.length; ++j) { - npt = new NodePortTuple((long)nptList[j][0], (short)nptList[j][1]); - expected.add(npt); - } - TopologyInstance ti = topologyManager.getCurrentInstance(tunnelsEnabled); - Set<NodePortTuple> computed = ti.getBroadcastNodePortsInCluster(npt.nodeId); - log.info("computed: {}", computed); - if (computed != null) - assertTrue(computed.equals(expected)); - else if (computed == null) - assertTrue(expected.isEmpty()); - } - } - - public void createTopologyFromLinks(int [][] linkArray) throws Exception { - ILinkDiscovery.LinkType type = ILinkDiscovery.LinkType.DIRECT_LINK; - - // Use topologymanager to write this test, it will make it a lot easier. - for (int i = 0; i < linkArray.length; i++) { - int [] r = linkArray[i]; - if (r[4] == DIRECT_LINK) - type= ILinkDiscovery.LinkType.DIRECT_LINK; - else if (r[4] == MULTIHOP_LINK) - type= ILinkDiscovery.LinkType.MULTIHOP_LINK; - else if (r[4] == TUNNEL_LINK) - type = ILinkDiscovery.LinkType.TUNNEL; - - topologyManager.addOrUpdateLink((long)r[0], (short)r[1], (long)r[2], (short)r[3], type); - } - topologyManager.createNewInstance(); - } - - public TopologyManager getTopologyManager() { - return topologyManager; - } - - @Test - public void testClusters() throws Exception { - TopologyManager tm = getTopologyManager(); - { - int [][] linkArray = { - {1, 1, 2, 1, DIRECT_LINK}, - {2, 2, 3, 2, DIRECT_LINK}, - {3, 1, 1, 2, DIRECT_LINK}, - {2, 3, 4, 2, DIRECT_LINK}, - {3, 3, 4, 1, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3}, - {4} - }; - //tm.recompute(); - createTopologyFromLinks(linkArray); - verifyClusters(expectedClusters); - } - - { - int [][] linkArray = { - {5, 3, 6, 1, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3}, - {4}, - {5}, - {6} - }; - createTopologyFromLinks(linkArray); - - verifyClusters(expectedClusters); - } - - { - int [][] linkArray = { - {6, 1, 5, 3, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3}, - {4}, - {5,6} - }; - createTopologyFromLinks(linkArray); - - verifyClusters(expectedClusters); - } - - { - int [][] linkArray = { - {4, 2, 2, 3, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3,4}, - {5,6} - }; - createTopologyFromLinks(linkArray); - - verifyClusters(expectedClusters); - } - { - int [][] linkArray = { - {4, 3, 5, 1, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3,4}, - {5,6} - }; - createTopologyFromLinks(linkArray); - - verifyClusters(expectedClusters); - } - { - int [][] linkArray = { - {5, 2, 2, 4, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3,4,5,6} - }; - createTopologyFromLinks(linkArray); - - verifyClusters(expectedClusters); - } - - //Test 2. - { - int [][] linkArray = { - {3, 2, 2, 2, DIRECT_LINK}, - {2, 1, 1, 1, DIRECT_LINK}, - {1, 2, 3, 1, DIRECT_LINK}, - {4, 1, 3, 3, DIRECT_LINK}, - {5, 1, 4, 3, DIRECT_LINK}, - {2, 4, 5, 2, DIRECT_LINK} - }; - int [][] expectedClusters = { - {1,2,3,4,5,6} - }; - createTopologyFromLinks(linkArray); - verifyClusters(expectedClusters); - } - - // Test 3. Remove links - { - tm.removeLink((long)5,(short)3,(long)6,(short)1); - tm.removeLink((long)6,(short)1,(long)5,(short)3); - - int [][] expectedClusters = { - {1,2,3,4,5}, - }; - topologyManager.createNewInstance(); - verifyClusters(expectedClusters); - } - - // Remove Switch - { - tm.removeSwitch(4); - int [][] expectedClusters = { - {1,2,3,5}, - }; - topologyManager.createNewInstance(); - verifyClusters(expectedClusters); - } - } - - @Test - public void testLoopDetectionInSingleIsland() throws Exception { - - int [][] linkArray = { - {1, 1, 2, 1, DIRECT_LINK}, - {2, 1, 1, 1, DIRECT_LINK}, - {1, 2, 3, 1, DIRECT_LINK}, - {3, 1, 1, 2, DIRECT_LINK}, - {2, 2, 3, 2, DIRECT_LINK}, - {3, 2, 2, 2, DIRECT_LINK}, - {3, 3, 4, 1, DIRECT_LINK}, - {4, 1, 3, 3, DIRECT_LINK}, - {4, 2, 6, 2, DIRECT_LINK}, - {6, 2, 4, 2, DIRECT_LINK}, - {4, 3, 5, 1, DIRECT_LINK}, - {5, 1, 4, 3, DIRECT_LINK}, - {5, 2, 6, 1, DIRECT_LINK}, - {6, 1, 5, 2, DIRECT_LINK}, - - }; - int [][] expectedClusters = { - {1, 2, 3, 4, 5, 6} - }; - int [][][] expectedBroadcastPorts = { - {{1,1}, {2,1}, {1,2}, {3,1}, {3,3}, {4,1}, {4,3}, {5,1}, {4,2}, {6,2}}, - }; - - createTopologyFromLinks(linkArray); - topologyManager.createNewInstance(); - verifyClusters(expectedClusters); - verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); - } - - @Test - public void testLoopDetectionWithIslands() throws Exception { - - // +-------+ +-------+ - // | | TUNNEL | | - // | 1 1|-------------|1 2 | - // | 2 | | 2 | - // +-------+ +-------+ - // | | - // | | - // +-------+ | - // | 1 | | - // | 3 2|-----------------+ - // | 3 | - // +-------+ - // - // - // +-------+ - // | 1 | TUNNEL - // | 4 2|----------------+ - // | 3 | | - // +-------+ | - // | | - // | | - // +-------+ +-------+ - // | 1 | | 2 | - // | 5 2|-------------|1 6 | - // | | | | - // +-------+ +-------+ - { - int [][] linkArray = { - {1, 1, 2, 1, DIRECT_LINK}, - {2, 1, 1, 1, DIRECT_LINK}, - {1, 2, 3, 1, DIRECT_LINK}, - {3, 1, 1, 2, DIRECT_LINK}, - {2, 2, 3, 2, DIRECT_LINK}, - {3, 2, 2, 2, DIRECT_LINK}, - - {4, 2, 6, 2, DIRECT_LINK}, - {6, 2, 4, 2, DIRECT_LINK}, - {4, 3, 5, 1, DIRECT_LINK}, - {5, 1, 4, 3, DIRECT_LINK}, - {5, 2, 6, 1, DIRECT_LINK}, - {6, 1, 5, 2, DIRECT_LINK}, - - }; - - int [][] expectedClusters = { - {1, 2, 3}, - {4, 5, 6} - }; - int [][][] expectedBroadcastPorts = { - {{1,1}, {2,1}, {1,2}, {3,1}}, - {{4,3}, {5,1}, {4,2}, {6,2}}, - }; - - createTopologyFromLinks(linkArray); - topologyManager.createNewInstance(); - verifyClusters(expectedClusters); - verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); - } - - // +-------+ +-------+ - // | | TUNNEL | | - // | 1 1|-------------|1 2 | - // | 2 | | 2 | - // +-------+ +-------+ - // | | - // | | - // +-------+ | - // | 1 | | - // | 3 2|-----------------+ - // | 3 | - // +-------+ - // | - // | TUNNEL - // | - // +-------+ - // | 1 | TUNNEL - // | 4 2|----------------+ - // | 3 | | - // +-------+ | - // | | - // | | - // +-------+ +-------+ - // | 1 | | 2 | - // | 5 2|-------------|1 6 | - // | | | | - // +-------+ +-------+ - - { - int [][] linkArray = { - {3, 3, 4, 1, DIRECT_LINK}, - {4, 1, 3, 3, DIRECT_LINK}, - - }; - int [][] expectedClusters = { - {1, 2, 3, 4, 5, 6} - }; - int [][][] expectedBroadcastPorts = { - {{1,1}, {2,1}, {1,2}, {3,1}, - {3,3}, {4,1}, {4,3}, {5,1}, - {4,2}, {6,2}}, - }; - - createTopologyFromLinks(linkArray); - topologyManager.createNewInstance(); - verifyClusters(expectedClusters, false); - verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); - } - } - - @Test - public void testLinkRemovalOnBroadcastDomainPorts() throws Exception { - { - int [][] linkArray = { - {1, 1, 2, 1, DIRECT_LINK}, - {2, 1, 1, 1, DIRECT_LINK}, - {1, 2, 3, 1, DIRECT_LINK}, - {3, 1, 1, 2, DIRECT_LINK}, - {2, 2, 3, 2, DIRECT_LINK}, - {3, 2, 2, 2, DIRECT_LINK}, - {1, 1, 3, 2, DIRECT_LINK}, - // the last link should make ports - // (1,1) and (3,2) to be broadcast - // domain ports, hence all links - // from these ports must be eliminated. - }; - - int [][] expectedClusters = { - {1, 3}, {2}, - }; - createTopologyFromLinks(linkArray); - topologyManager.createNewInstance(); - if (topologyManager.getCurrentInstance() instanceof TopologyInstance) - verifyClusters(expectedClusters); - } - { - int [][] linkArray = { - {1, 2, 3, 2, DIRECT_LINK}, - // the last link should make ports - // (1,1) and (3,2) to be broadcast - // domain ports, hence all links - // from these ports must be eliminated. - }; - - int [][] expectedClusters = { - {1}, {3}, {2}, - }; - createTopologyFromLinks(linkArray); - topologyManager.createNewInstance(); - if (topologyManager.getCurrentInstance() instanceof TopologyInstance) - verifyClusters(expectedClusters); - } - } -} diff --git a/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java b/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java deleted file mode 100644 index b1027349cfc203a744a9cc18e828fe5d981064d1..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.topology; - -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.linkdiscovery.ILinkDiscovery; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.TopologyManager; - -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TopologyManagerTest extends FloodlightTestCase { - protected static Logger log = LoggerFactory.getLogger(TopologyManagerTest.class); - TopologyManager tm; - FloodlightModuleContext fmc; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - fmc = new FloodlightModuleContext(); - fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); - MockThreadPoolService tp = new MockThreadPoolService(); - fmc.addService(IThreadPoolService.class, tp); - tm = new TopologyManager(); - tp.init(fmc); - tm.init(fmc); - tp.startUp(fmc); - } - - @Test - public void testBasic1() throws Exception { - tm.addOrUpdateLink(1, (short)1, 2, (short)1, ILinkDiscovery.LinkType.DIRECT_LINK); - assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. - assertTrue(tm.getSwitchPorts().get((long)1).size()==1); - assertTrue(tm.getSwitchPorts().get((long)2).size()==1); - assertTrue(tm.getSwitchPortLinks().size()==2); - assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelPorts().size()==0); - - tm.addOrUpdateLink(1, (short)2, 2, (short)2, ILinkDiscovery.LinkType.MULTIHOP_LINK); - assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. - assertTrue(tm.getSwitchPorts().get((long)1).size()==2); - assertTrue(tm.getSwitchPorts().get((long)2).size()==2); - assertTrue(tm.getSwitchPortLinks().size()==4); - assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelPorts().size()==0); - - tm.removeLink(1, (short)2, 2, (short)2); - assertTrue(tm.getSwitchPorts().get((long)1).size()==1); - assertTrue(tm.getSwitchPorts().get((long)2).size()==1); - assertTrue(tm.getSwitchPorts().size() == 2); - assertTrue(tm.getSwitchPortLinks().size()==2); - assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - - tm.removeLink(1, (short)1, 2, (short)1); - assertTrue(tm.getSwitchPorts().size() == 0); - assertTrue(tm.getSwitchPortLinks().size()==0); - assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - } - - @Test - public void testBasic2() throws Exception { - tm.addOrUpdateLink(1, (short)1, 2, (short)1, ILinkDiscovery.LinkType.DIRECT_LINK); - tm.addOrUpdateLink(2, (short)2, 3, (short)1, ILinkDiscovery.LinkType.MULTIHOP_LINK); - assertTrue(tm.getSwitchPorts().size() == 3); // for two nodes. - assertTrue(tm.getSwitchPorts().get((long)1).size()==1); - assertTrue(tm.getSwitchPorts().get((long)2).size()==2); - assertTrue(tm.getSwitchPorts().get((long)3).size()==1); - assertTrue(tm.getSwitchPortLinks().size()==4); - assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - - tm.removeLink(1, (short)1, 2, (short)1); - assertTrue(tm.getSwitchPorts().size() == 2); - assertTrue(tm.getSwitchPorts().get((long)1) == null); - assertTrue(tm.getSwitchPorts().get((long)2).size()==1); - assertTrue(tm.getSwitchPorts().get((long)3).size()==1); - assertTrue(tm.getSwitchPortLinks().size()==2); - assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - - // nonexistent link // no null pointer exceptions. - tm.removeLink(3, (short)1, 2, (short)2); - assertTrue(tm.getSwitchPorts().size() == 2); - assertTrue(tm.getSwitchPorts().get((long)1) == null); - assertTrue(tm.getSwitchPorts().get((long)2).size()==1); - assertTrue(tm.getSwitchPorts().get((long)3).size()==1); - assertTrue(tm.getSwitchPortLinks().size()==2); - assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - - tm.removeLink(3, (short)2, 1, (short)2); - assertTrue(tm.getSwitchPorts().size() == 2); - assertTrue(tm.getSwitchPorts().get((long)1)==null); - assertTrue(tm.getSwitchPorts().get((long)2).size()==1); - assertTrue(tm.getSwitchPorts().get((long)3).size()==1); - assertTrue(tm.getSwitchPortLinks().size()==2); - assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - - tm.removeLink(2, (short)2, 3, (short)1); - assertTrue(tm.getSwitchPorts().size() == 0); // for two nodes. - assertTrue(tm.getSwitchPortLinks().size()==0); - assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelPorts().size()==0); - } - -} diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java index 1e5e4643e894e868ebffff36c7cdad986d5e41c4..547371cc0ba2e3694c2c810d8dd928f5f12059c0 100644 --- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java +++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java @@ -28,20 +28,19 @@ import java.util.concurrent.Future; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.IFloodlightProviderService.Role; -import net.floodlightcontroller.core.ImmutablePort; -import net.floodlightcontroller.core.internal.OLD__Controller; +import net.floodlightcontroller.core.HARole; +import net.floodlightcontroller.core.internal.Controller; import net.floodlightcontroller.debugcounter.IDebugCounterService; import net.floodlightcontroller.threadpool.IThreadPoolService; import org.jboss.netty.channel.Channel; -import org.openflow.protocol.OFFeaturesReply; -import org.openflow.protocol.OFMessage; -import org.openflow.protocol.OFPortStatus; -import org.openflow.protocol.OFStatisticsReply; -import org.openflow.protocol.OFStatisticsRequest; -import org.openflow.protocol.statistics.OFDescriptionStatistics; -import org.openflow.protocol.statistics.OFStatistics; +import org.projectfloodlight.openflow.protocol.OFFeaturesReply; +import org.projectfloodlight.openflow.protocol.OFMessage; +import org.projectfloodlight.openflow.protocol.OFPortStatus; +import org.projectfloodlight.openflow.protocol.OFStatsReply; +import org.projectfloodlight.openflow.protocol.OFStatsRequest; +import org.projectfloodlight.openflow.protocol.OFDescStatsReply; +import org.projectfloodlight.openflow.protocol.OFDescStatsRequest; /** diff --git a/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java b/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java deleted file mode 100644 index d8dc143617beb40454ce9b67c7ea1940ea79a8f2..0000000000000000000000000000000000000000 --- a/src/test/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilterTest.java +++ /dev/null @@ -1,398 +0,0 @@ -/** - * Copyright 2013, Big Switch Networks, Inc. - * - * 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.virtualnetwork; - -import static org.easymock.EasyMock.*; - -import java.util.List; - -import org.easymock.EasyMock; -import org.junit.Before; -import org.junit.Test; -import org.openflow.protocol.OFMatch; -import org.openflow.protocol.OFPacketIn; -import org.openflow.protocol.OFType; -import org.openflow.protocol.OFPacketIn.OFPacketInReason; -import org.sdnplatform.sync.ISyncService; -import org.sdnplatform.sync.test.MockSyncService; - -import net.floodlightcontroller.core.FloodlightContext; -import net.floodlightcontroller.core.IFloodlightProviderService; -import net.floodlightcontroller.core.IOFMessageListener; -import net.floodlightcontroller.core.IListener.Command; -import net.floodlightcontroller.core.IOFSwitch; -import net.floodlightcontroller.core.module.FloodlightModuleContext; -import net.floodlightcontroller.core.test.MockThreadPoolService; -import net.floodlightcontroller.core.test.PacketFactory; -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.flowcache.FlowReconcileManager; -import net.floodlightcontroller.flowcache.IFlowReconcileService; -import net.floodlightcontroller.packet.Data; -import net.floodlightcontroller.packet.Ethernet; -import net.floodlightcontroller.packet.IPacket; -import net.floodlightcontroller.packet.IPv4; -import net.floodlightcontroller.packet.UDP; -import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.restserver.RestApiServer; -import net.floodlightcontroller.test.FloodlightTestCase; -import net.floodlightcontroller.threadpool.IThreadPoolService; -import net.floodlightcontroller.topology.ITopologyService; -import net.floodlightcontroller.util.MACAddress; -import net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter; - -public class VirtualNetworkFilterTest extends FloodlightTestCase { - protected VirtualNetworkFilter vns; - protected MockDeviceManager deviceService; - - protected static String guid1 = "guid1"; - protected static String net1 = "net1"; - protected static String gw1 = "1.1.1.1"; - protected static String guid2 = "guid2"; - protected static String net2 = "net2"; - protected static String guid3 = "guid3"; - protected static String net3 = "net3"; - protected static String gw2 = "2.2.2.2"; - - protected static MACAddress mac1 = - new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:55")); - protected static MACAddress mac2 = - new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:66")); - protected static MACAddress mac3 = - new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:77")); - protected static MACAddress mac4 = - new MACAddress(Ethernet.toMACAddress("00:11:22:33:44:88")); - protected static String hostPort1 = "port1"; - protected static String hostPort2 = "port2"; - protected static String hostPort3 = "port3"; - protected static String hostPort4 = "port4"; - - // For testing forwarding behavior - protected IOFSwitch sw1; - protected FloodlightContext cntx; - protected OFPacketIn mac1ToMac2PacketIn; - protected IPacket mac1ToMac2PacketIntestPacket; - protected byte[] mac1ToMac2PacketIntestPacketSerialized; - protected OFPacketIn mac1ToMac4PacketIn; - protected IPacket mac1ToMac4PacketIntestPacket; - protected byte[] mac1ToMac4PacketIntestPacketSerialized; - protected OFPacketIn mac1ToGwPacketIn; - protected IPacket mac1ToGwPacketIntestPacket; - protected byte[] mac1ToGwPacketIntestPacketSerialized; - protected OFPacketIn packetInDHCPDiscoveryRequest; - private MockSyncService mockSyncService; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - mockSyncService = new MockSyncService(); - - // Module loading stuff - FloodlightModuleContext fmc = new FloodlightModuleContext(); - RestApiServer restApi = new RestApiServer(); - deviceService = new MockDeviceManager(); - FlowReconcileManager frm = new FlowReconcileManager(); - MockThreadPoolService tps = new MockThreadPoolService(); - ITopologyService topology = createMock(ITopologyService.class); - vns = new VirtualNetworkFilter(); - DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); - fmc.addService(IRestApiService.class, restApi); - fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); - fmc.addService(IDeviceService.class, deviceService); - fmc.addService(IFlowReconcileService.class, frm); - fmc.addService(IThreadPoolService.class, tps); - fmc.addService(IEntityClassifierService.class, entityClassifier); - fmc.addService(ITopologyService.class, topology); - fmc.addService(ISyncService.class, mockSyncService); - tps.init(fmc); - frm.init(fmc); - deviceService.init(fmc); - restApi.init(fmc); - getMockFloodlightProvider().init(fmc); - entityClassifier.init(fmc); - tps.startUp(fmc); - vns.init(fmc); - frm.startUp(fmc); - deviceService.startUp(fmc); - restApi.startUp(fmc); - getMockFloodlightProvider().startUp(fmc); - vns.startUp(fmc); - entityClassifier.startUp(fmc); - - topology.addListener(deviceService); - expectLastCall().times(1); - replay(topology); - // Mock switches - //fastWilcards mocked as this constant - int fastWildcards = - OFMatch.OFPFW_IN_PORT | - OFMatch.OFPFW_NW_PROTO | - OFMatch.OFPFW_TP_SRC | - OFMatch.OFPFW_TP_DST | - OFMatch.OFPFW_NW_SRC_ALL | - OFMatch.OFPFW_NW_DST_ALL | - OFMatch.OFPFW_NW_TOS; - sw1 = EasyMock.createNiceMock(IOFSwitch.class); - expect(sw1.getId()).andReturn(1L).anyTimes(); - expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); - expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); - replay(sw1); - - // Mock packets - // Mock from MAC1 -> MAC2 - mac1ToMac2PacketIntestPacket = new Ethernet() - .setDestinationMACAddress(mac2.toBytes()) - .setSourceMACAddress(mac1.toBytes()) - .setEtherType(Ethernet.TYPE_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})))); - mac1ToMac2PacketIntestPacketSerialized = mac1ToMac2PacketIntestPacket.serialize(); - mac1ToMac2PacketIn = - ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(mac1ToMac2PacketIntestPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) mac1ToMac2PacketIntestPacketSerialized.length); - - // Mock from MAC1 -> MAC4 - mac1ToMac4PacketIntestPacket = new Ethernet() - .setDestinationMACAddress(mac4.toBytes()) - .setSourceMACAddress(mac1.toBytes()) - .setEtherType(Ethernet.TYPE_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})))); - mac1ToMac4PacketIntestPacketSerialized = mac1ToMac4PacketIntestPacket.serialize(); - mac1ToMac4PacketIn = - ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(mac1ToMac4PacketIntestPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) mac1ToMac4PacketIntestPacketSerialized.length); - - // Mock from MAC1 to gateway1 - mac1ToGwPacketIntestPacket = new Ethernet() - .setDestinationMACAddress("00:11:33:33:44:55") // mac shouldn't matter, can't be other host - .setSourceMACAddress(mac1.toBytes()) - .setEtherType(Ethernet.TYPE_IPv4) - .setPayload( - new IPv4() - .setTtl((byte) 128) - .setSourceAddress("192.168.1.1") - .setDestinationAddress(gw1) - .setPayload(new UDP() - .setSourcePort((short) 5000) - .setDestinationPort((short) 5001) - .setPayload(new Data(new byte[] {0x01})))); - mac1ToGwPacketIntestPacketSerialized = mac1ToGwPacketIntestPacket.serialize(); - mac1ToGwPacketIn = - ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory(). - getMessage(OFType.PACKET_IN)) - .setBufferId(-1) - .setInPort((short) 1) - .setPacketData(mac1ToGwPacketIntestPacketSerialized) - .setReason(OFPacketInReason.NO_MATCH) - .setTotalLength((short) mac1ToGwPacketIntestPacketSerialized.length); - } - - @Test - public void testCreateNetwork() { - // Test creating a network with all parameters - vns.createNetwork(guid1, net1, IPv4.toIPv4Address(gw1)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); - assertTrue(vns.nameToGuid.get(net1).equals(guid1)); - assertTrue(vns.guidToGateway.get(guid1).equals(IPv4.toIPv4Address(gw1))); - assertTrue(vns.vNetsByGuid.get(guid1).name.equals(net1)); - assertTrue(vns.vNetsByGuid.get(guid1).guid.equals(guid1)); - assertTrue(vns.vNetsByGuid.get(guid1).gateway.equals(gw1)); - assertTrue(vns.vNetsByGuid.get(guid1).portToMac.size()==0); - - // Test creating network without a gateway - vns.createNetwork(guid2, net2, null); - assertTrue(vns.nameToGuid.get(net2).equals(guid2)); - assertTrue(vns.guidToGateway.get(guid2) == null); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 1); - assertTrue(vns.vNetsByGuid.get(guid2).name.equals(net2)); - assertTrue(vns.vNetsByGuid.get(guid2).guid.equals(guid2)); - assertTrue(vns.vNetsByGuid.get(guid2).gateway == null); - assertTrue(vns.vNetsByGuid.get(guid2).portToMac.size()==0); - - // Test creating a network that shares the gateway with net1 - vns.createNetwork(guid3, net3, IPv4.toIPv4Address(gw1)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid3)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 2); - assertTrue(vns.nameToGuid.get(net3).equals(guid3)); - assertTrue(vns.guidToGateway.get(guid3).equals(IPv4.toIPv4Address(gw1))); - assertTrue(vns.vNetsByGuid.get(guid3).name.equals(net3)); - assertTrue(vns.vNetsByGuid.get(guid3).guid.equals(guid3)); - assertTrue(vns.vNetsByGuid.get(guid3).gateway.equals(gw1)); - assertTrue(vns.vNetsByGuid.get(guid3).portToMac.size()==0); - - } - - @Test - public void testModifyNetwork() { - // Create some networks - - testCreateNetwork(); - // Modify net2 to add a gateway - vns.createNetwork(guid2, net2, IPv4.toIPv4Address(gw1)); - assertTrue(vns.nameToGuid.get(net2).equals(guid2)); - assertTrue(vns.guidToGateway.get(guid2).equals(IPv4.toIPv4Address(gw1))); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid2)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid3)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 3); - // Modify net2 to change it's name - vns.createNetwork(guid2, "newnet2", null); - // Make sure the gateway is still there - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid2)); - assertTrue(vns.vNetsByGuid.get(guid2).gateway.equals(gw1)); - // make sure the new name mapping was learned - assertTrue(vns.nameToGuid.get("newnet2").equals(guid2)); - assertTrue(vns.vNetsByGuid.get(guid2).name.equals("newnet2")); - // and the old one was deleted - assertFalse(vns.nameToGuid.containsKey(net2)); - } - - @Test - public void testDeleteNetwork() { - testModifyNetwork(); - // Delete newnet2 - vns.deleteNetwork(guid2); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid1)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).contains(guid3)); - assertTrue(vns.gatewayToGuid.get(IPv4.toIPv4Address(gw1)).size() == 2); - assertFalse(vns.nameToGuid.containsKey(net2)); - assertFalse(vns.guidToGateway.containsKey(net2)); - assertTrue(vns.vNetsByGuid.get(guid2)==null); - } - - @Test - public void testAddHost() { - testModifyNetwork(); - vns.addHost(mac1, guid1, hostPort1); - assertTrue(vns.macToGuid.get(mac1).equals(guid1)); - assertTrue(vns.portToMac.get(hostPort1).equals(mac1)); - assertTrue(vns.vNetsByGuid.get(guid1).portToMac.containsValue(mac1)); - vns.addHost(mac2, guid1, hostPort2); - assertTrue(vns.macToGuid.get(mac2).equals(guid1)); - assertTrue(vns.portToMac.get(hostPort2).equals(mac2)); - assertTrue(vns.vNetsByGuid.get(guid1).portToMac.containsValue(mac2)); - vns.addHost(mac3, guid3, hostPort3); - vns.addHost(mac4, guid3, hostPort4); - assertTrue(vns.vNetsByGuid.get(guid3).portToMac.containsValue(mac4)); - } - - @Test - public void testDeleteHost() { - testAddHost(); - - String host1Guid = vns.macToGuid.get(mac1); - vns.deleteHost(mac1, null); - assertFalse(vns.macToGuid.containsKey(mac1)); - assertFalse(vns.portToMac.containsKey(hostPort1)); - assertFalse(vns.vNetsByGuid.get(host1Guid).portToMac.containsValue(mac1)); - - String host2Guid = vns.macToGuid.get(vns.portToMac.get(hostPort2)); - vns.deleteHost(null, hostPort2); - assertFalse(vns.macToGuid.containsKey(mac2)); - assertFalse(vns.portToMac.containsKey(hostPort2)); - assertFalse(vns.vNetsByGuid.get(host2Guid).portToMac.containsValue(mac2)); - - String host3Guid = vns.macToGuid.get(mac3); - vns.deleteHost(mac3, hostPort3); - assertFalse(vns.macToGuid.containsKey(mac3)); - assertFalse(vns.portToMac.containsKey(hostPort3)); - assertFalse(vns.vNetsByGuid.get(host3Guid).portToMac.containsValue(mac3)); - - } - - @Test - public void testForwarding() { - testAddHost(); - // make sure mac1 can communicate with mac2 - IOFMessageListener listener = getVirtualNetworkListener(); - cntx = new FloodlightContext(); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet)mac1ToMac2PacketIntestPacket); - Command ret = listener.receive(sw1, mac1ToMac2PacketIn, cntx); - assertTrue(ret == Command.CONTINUE); - // make sure mac1 can't communicate with mac4 - cntx = new FloodlightContext(); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet)mac1ToMac4PacketIntestPacket); - ret = listener.receive(sw1, mac1ToMac4PacketIn, cntx); - assertTrue(ret == Command.STOP); - } - - @Test - public void testDefaultGateway() { - testAddHost(); - IOFMessageListener listener = getVirtualNetworkListener(); - cntx = new FloodlightContext(); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - (Ethernet)mac1ToGwPacketIntestPacket); - deviceService.learnEntity(((Ethernet)mac1ToGwPacketIntestPacket).getDestinationMAC().toLong(), - null, IPv4.toIPv4Address(gw1), null, null); - Command ret = listener.receive(sw1, mac1ToGwPacketIn, cntx); - assertTrue(ret == Command.CONTINUE); - } - - @Test - public void testDhcp() { - IOFMessageListener listener = getVirtualNetworkListener(); - Ethernet dhcpPacket = PacketFactory.DhcpDiscoveryRequestEthernet(mac1); - OFPacketIn dhcpPacketOf = PacketFactory.DhcpDiscoveryRequestOFPacketIn(mac1); - cntx = new FloodlightContext(); - IFloodlightProviderService.bcStore.put(cntx, - IFloodlightProviderService.CONTEXT_PI_PAYLOAD, - dhcpPacket); - Command ret = listener.receive(sw1, dhcpPacketOf, cntx); - assertTrue(ret == Command.CONTINUE); - } - - protected IOFMessageListener getVirtualNetworkListener() { - List<IOFMessageListener> listeners = mockFloodlightProvider.getListeners().get(OFType.PACKET_IN); - return listeners.get(listeners.indexOf(vns)); - } -}