package net.floodlightcontroller.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import net.floodlightcontroller.util.EnumBitmaps;
import org.openflow.protocol.OFPhysicalPort;
import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
import org.openflow.protocol.OFPhysicalPort.OFPortState;
import org.openflow.protocol.OFPhysicalPort.PortSpeed;
import org.openflow.util.HexString;
/**
* An immutable version of an OFPhysical port. In addition, it uses EnumSets
* instead of integer bitmaps to represent
* OFPortConfig, OFPortState, and OFPortFeature bitmaps.
*
* Port names are stored with the original case but equals() and XXXX use
* case-insentivie comparisions for port names!!
*
* TODO: create a Builder so we can easily construct OFPhysicalPorts
* TODO: should we verify / ensure that the features make sense, i.e., that
* currentFeatures IsSubsetOf advertisedFeatures IsSubsetOf
* supportedFeatures
*
* @author gregor
*
*/
public class ImmutablePort {
private final short portNumber;
private final byte[] hardwareAddress;
private final String name;
private final EnumSet<OFPortConfig> config;
private final boolean portStateLinkDown;
private final OFPortState stpState;
private final EnumSet<OFPortFeatures> currentFeatures;
private final EnumSet<OFPortFeatures> advertisedFeatures;
private final EnumSet<OFPortFeatures> supportedFeatures;
private final EnumSet<OFPortFeatures> peerFeatures;
/**
* A builder class to create ImmutablePort instances
*
* TODO: add methods to remove elements from the EnumSets
*/
public static class Builder {
private short portNumber;
private byte[] hardwareAddress;
private String name;
private EnumSet<OFPortConfig> config;
private boolean portStateLinkDown;
private OFPortState stpState;
private EnumSet<OFPortFeatures> currentFeatures;
private EnumSet<OFPortFeatures> advertisedFeatures;
private EnumSet<OFPortFeatures> supportedFeatures;
private EnumSet<OFPortFeatures> peerFeatures;
public Builder() {
this.portNumber = (short)1;
this.hardwareAddress = new byte[] { 0, 0, 0, 0, 0, 0 };
this.name = "";
this.config = EnumSet.noneOf(OFPortConfig.class);
this.portStateLinkDown = false;
this.stpState = OFPortState.OFPPS_STP_LISTEN;
this.currentFeatures = EnumSet.noneOf(OFPortFeatures.class);
this.advertisedFeatures = EnumSet.noneOf(OFPortFeatures.class);
this.supportedFeatures = EnumSet.noneOf(OFPortFeatures.class);
this.peerFeatures = EnumSet.noneOf(OFPortFeatures.class);
}
public Builder(ImmutablePort p) {
this.portNumber = p.getPortNumber();
this.hardwareAddress = p.getHardwareAddress();
this.name = p.getName();
this.config = EnumSet.copyOf(p.getConfig());
this.portStateLinkDown = p.isLinkDown();
this.stpState = p.getStpState();
this.currentFeatures = EnumSet.copyOf(p.getCurrentFeatures());
this.advertisedFeatures = EnumSet.copyOf(p.getAdvertisedFeatures());
this.supportedFeatures = EnumSet.copyOf(p.getSupportedFeatures());
this.peerFeatures = EnumSet.copyOf(p.getPeerFeatures());
}
/**
* @param portNumber the portNumber to set
*/
public Builder setPortNumber(short portNumber) {
this.portNumber = portNumber;
return this;
}
/**
* @param hardwareAddress the hardwareAddress to set
*/
public Builder setHardwareAddress(byte[] hardwareAddress) {
if (hardwareAddress== null) {
throw new NullPointerException("Hardware address must not be null");
}
if (hardwareAddress.length != 6) {
throw new IllegalArgumentException("Harware address must be 6 " +
"bytes long but hardware address is " +
Arrays.toString(hardwareAddress));
}
this.hardwareAddress = Arrays.copyOf(hardwareAddress, 6);
return this;
}
/**
* @param name the name to set
*/
public Builder setName(String name) {
if (name == null)
throw new NullPointerException("Port name must not be null");
this.name = name;
return this;
}
/**
* @param config the config to set
*/
public Builder addConfig(OFPortConfig config) {
if (config == null)
throw new NullPointerException("PortConfig must not be null");
this.config.add(config);
return this;
}
/**
* @param portStateLinkDown the portStateLinkDown to set
*/
public Builder setPortStateLinkDown(boolean portStateLinkDown) {
this.portStateLinkDown = portStateLinkDown;
return this;
}
/**
* @param stpState the stpState to set
*/
public Builder setStpState(OFPortState stpState) {
if (stpState == null)
throw new NullPointerException("stpState must not be null");
if (!stpState.isStpState()) {
String msg = String.format("OFPortState enum constant %s " +
"is not an STP state", stpState);
throw new IllegalArgumentException(msg);
}
this.stpState = stpState;
return this;
}
/**
* @param currentFeatures the currentFeatures to set
*/
public Builder addCurrentFeature(OFPortFeatures currentFeature) {
if (currentFeature == null)
throw new NullPointerException("CurrentFeature must not be null");
this.currentFeatures.add(currentFeature);
return this;
}
/**
* @param advertisedFeatures the advertisedFeatures to set
*/
public Builder
addAdvertisedFeature(OFPortFeatures advertisedFeature) {
if (advertisedFeature == null) {
throw new
NullPointerException("AdvertisedFeature must not be null");
}
this.advertisedFeatures.add(advertisedFeature);
return this;
}
/**
* @param supportedFeatures the supportedFeatures to set
*/
public Builder addSupportedFeature(OFPortFeatures supportedFeature) {
if (supportedFeature == null) {
throw new NullPointerException("SupportedFeature must not be null");
}
this.supportedFeatures.add(supportedFeature);
return this;
}
/**
* @param peerFeatures the peerFeatures to set
*/
public Builder addPeerFeature(OFPortFeatures peerFeature) {
if (peerFeature == null)
throw new NullPointerException("PortFeature must not be null");
this.peerFeatures.add(peerFeature);
return this;
}
/**
* @return
*/
public ImmutablePort build() {
return new ImmutablePort(portNumber,
hardwareAddress,
name,
EnumSet.copyOf(config),
portStateLinkDown,
stpState,
EnumSet.copyOf(currentFeatures),
EnumSet.copyOf(advertisedFeatures),
EnumSet.copyOf(supportedFeatures),
EnumSet.copyOf(peerFeatures));
}
}
public static ImmutablePort fromOFPhysicalPort(OFPhysicalPort p) {
if (p == null) {
throw new NullPointerException("OFPhysicalPort must not be null");
}
if (p.getHardwareAddress() == null) {
throw new NullPointerException("Hardware address must not be null");
}
if (p.getName() == null) {
throw new NullPointerException("Port name must not be null");
}
return new ImmutablePort(
p.getPortNumber(),
Arrays.copyOf(p.getHardwareAddress(), 6),
p.getName(),
EnumBitmaps.toEnumSet(OFPortConfig.class, p.getConfig()),
OFPortState.isPortDown(p.getState()),
OFPortState.getStpState(p.getState()),
EnumBitmaps.toEnumSet(OFPortFeatures.class,
p.getCurrentFeatures()),
EnumBitmaps.toEnumSet(OFPortFeatures.class,
p.getAdvertisedFeatures()),
EnumBitmaps.toEnumSet(OFPortFeatures.class,
p.getSupportedFeatures()),
EnumBitmaps.toEnumSet(OFPortFeatures.class,
p.getPeerFeatures())
);
}
public static ImmutablePort create(String name, Short portNumber) {
return new ImmutablePort(portNumber,
new byte[] { 0, 0, 0, 0, 0, 0 },
name,
EnumSet.noneOf(OFPortConfig.class),
false,
OFPortState.OFPPS_STP_LISTEN,
EnumSet.noneOf(OFPortFeatures.class),
EnumSet.noneOf(OFPortFeatures.class),
EnumSet.noneOf(OFPortFeatures.class),
EnumSet.noneOf(OFPortFeatures.class));
}
/**
* Private constructor. Use factory methods.
*
* Verifies pre-conditions of arguments
* Does NOT make defensive copies. Calling factory methods are required
* to copy defensively if required.
*
* @param portNumber
* @param hardwareAddress
* @param name
* @param config
* @param portStateLinkDown
* @param portStateStp
* @param currentFeatures
* @param advertisedFeatures
* @param supportedFeatures
* @param peerFeatures
*/
private ImmutablePort(short portNumber, byte[] hardwareAddress,
String name, EnumSet<OFPortConfig> config,
boolean portStateLinkDown,
OFPortState portStateStp,
EnumSet<OFPortFeatures> currentFeatures,
EnumSet<OFPortFeatures> advertisedFeatures,
EnumSet<OFPortFeatures> supportedFeatures,
EnumSet<OFPortFeatures> peerFeatures) {
if (name == null) {
throw new NullPointerException("Port name must not be null");
}
if (hardwareAddress== null) {
throw new NullPointerException("Hardware address must not be null");
}
if (hardwareAddress.length != 6) {
throw new IllegalArgumentException("Harware address must be 6 " +
"bytes long but hardware address is " +
Arrays.toString(hardwareAddress));
}
if (config == null)
throw new NullPointerException("portConfig must not be null");
if (portStateStp == null)
throw new NullPointerException("portStateStp must not be null");
if (currentFeatures == null)
throw new NullPointerException("currentFeatures must not be null");
if (advertisedFeatures == null)
throw new NullPointerException("advertisedFeatures must not be null");
if (supportedFeatures == null)
throw new NullPointerException("supportedFeatures must not be null");
if (peerFeatures == null)
throw new NullPointerException("peerFeatures must not be null");
this.portNumber = portNumber;
this.hardwareAddress = hardwareAddress;
this.name = name;
this.config = config;
this.portStateLinkDown = portStateLinkDown;
this.stpState = portStateStp;
this.currentFeatures = currentFeatures;
this.advertisedFeatures = advertisedFeatures;
this.supportedFeatures = supportedFeatures;
this.peerFeatures = peerFeatures;
}
public short getPortNumber() {
return portNumber;
}
public byte[] getHardwareAddress() {
// FIXME: don't use arrays.
return Arrays.copyOf(hardwareAddress, 6);
}
public String getName() {
return name;
}
public Set<OFPortConfig> getConfig() {
return Collections.unmodifiableSet(config);
}
/**
* Returns true if the OFPortState indicates the port is down
* @return
*/
public boolean isLinkDown() {
return portStateLinkDown;
}
/**
* Returns the STP state portion of the OFPortState. The returned
* enum constant will be one of the four STP states and will have
* isStpState() return true
* @return
*/
public OFPortState getStpState() {
return this.stpState;
}
public Set<OFPortFeatures> getCurrentFeatures() {
return Collections.unmodifiableSet(currentFeatures);
}
public Set<OFPortFeatures> getAdvertisedFeatures() {
return Collections.unmodifiableSet(advertisedFeatures);
}
public Set<OFPortFeatures> getSupportedFeatures() {
return Collections.unmodifiableSet(supportedFeatures);
}
public Set<OFPortFeatures> getPeerFeatures() {
return Collections.unmodifiableSet(peerFeatures);
}
/**
* Returns true if the port is up, i.e., it's neither administratively
* down nor link down. It currently does NOT take STP state into
* consideration
* @return
*/
public boolean isEnabled() {
return (!portStateLinkDown &&
!config.contains(OFPortConfig.OFPPC_PORT_DOWN));
}
/**
* @return the speed of the port (from currentFeatures) if the port is
* enabled, otherwise return SPEED_NONE
*/
public PortSpeed getCurrentPortSpeed() {
if (!isEnabled())
return PortSpeed.SPEED_NONE;
PortSpeed maxSpeed = PortSpeed.SPEED_NONE;
for (OFPortFeatures f: currentFeatures)
PortSpeed.max(maxSpeed, f.getSpeed());
return maxSpeed;
}
public OFPhysicalPort toOFPhysicalPort() {
OFPhysicalPort ofpp = new OFPhysicalPort();
ofpp.setPortNumber(this.getPortNumber());
ofpp.setHardwareAddress(this.getHardwareAddress());
ofpp.setName(this.getName());
ofpp.setConfig(EnumBitmaps.toBitmap(this.getConfig()));
int state = this.getStpState().getValue();
if (this.isLinkDown())
state |= OFPortState.OFPPS_LINK_DOWN.getValue();
ofpp.setState(state);
ofpp.setCurrentFeatures(EnumBitmaps.toBitmap(this.getCurrentFeatures()));
ofpp.setAdvertisedFeatures(
EnumBitmaps.toBitmap(this.getAdvertisedFeatures()));
ofpp.setSupportedFeatures(
EnumBitmaps.toBitmap(this.getSupportedFeatures()));
ofpp.setPeerFeatures(EnumBitmaps.toBitmap(this.getPeerFeatures()));
return ofpp;
}
/**
* Return a brief String describing this port containing the port number
* and port name
* @return
*/
public String toBriefString() {
return String.format("%s (%d)", name, portNumber);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((advertisedFeatures == null) ? 0
: advertisedFeatures.hashCode());
result = prime * result + ((config == null) ? 0 : config.hashCode());
result = prime
* result
+ ((currentFeatures == null) ? 0
: currentFeatures.hashCode());
result = prime * result + Arrays.hashCode(hardwareAddress);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((peerFeatures == null) ? 0 : peerFeatures.hashCode());
result = prime * result + portNumber;
result = prime * result + (portStateLinkDown ? 1231 : 1237);
result = prime * result
+ ((stpState == null) ? 0 : stpState.hashCode());
result = prime
* result
+ ((supportedFeatures == null) ? 0
: supportedFeatures.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 (getClass() != obj.getClass()) return false;
ImmutablePort other = (ImmutablePort) obj;
if (portNumber != other.portNumber) return false;
if (name == null) {
if (other.name != null) return false;
} else if (!name.equalsIgnoreCase(other.name)) return false;
if (advertisedFeatures == null) {
if (other.advertisedFeatures != null) return false;
} else if (!advertisedFeatures.equals(other.advertisedFeatures))
return false;
if (config == null) {
if (other.config != null) return false;
} else if (!config.equals(other.config)) return false;
if (currentFeatures == null) {
if (other.currentFeatures != null) return false;
} else if (!currentFeatures.equals(other.currentFeatures))
return false;
if (!Arrays.equals(hardwareAddress, other.hardwareAddress))
return false;
if (peerFeatures == null) {
if (other.peerFeatures != null) return false;
} else if (!peerFeatures.equals(other.peerFeatures)) return false;
if (portStateLinkDown != other.portStateLinkDown) return false;
if (stpState != other.stpState) return false;
if (supportedFeatures == null) {
if (other.supportedFeatures != null) return false;
} else if (!supportedFeatures.equals(other.supportedFeatures))
return false;
return true;
}
/**
* Convert a Collection of OFPhysicalPorts to a list of ImmutablePorts.
* All OFPhysicalPorts in the Collection must be non-null and valid.
* No other checks (name / number uniqueness) are performed
* @param ports
* @return a list of {@link ImmutablePort}s. This is list is owned by
* the caller. The returned list is not thread-safe
* @throws NullPointerException if any OFPhysicalPort or important fields
* of any OFPhysicalPort are null
* @throws IllegalArgumentException
*/
public static List<ImmutablePort>
immutablePortListOf(Collection<OFPhysicalPort> ports) {
if (ports == null) {
throw new NullPointerException("Port list must not be null");
}
ArrayList<ImmutablePort> immutablePorts =
new ArrayList<ImmutablePort>(ports.size());
for (OFPhysicalPort p: ports)
immutablePorts.add(fromOFPhysicalPort(p));
return immutablePorts;
}
/**
* Convert a Collection of ImmutablePort to a list of OFPhyscialPorts.
* All ImmutablePorts in the Collection must be non-null.
* No other checks (name / number uniqueness) are performed
* @param ports
* @return a list of {@link OFPhysicalPort}s. This is list is owned by
* the caller. The returned list is not thread-safe
* @throws NullPointerException if any {@link ImmutablePort} or the port
* list is null
* @throws IllegalArgumentException
*/
public static List<OFPhysicalPort>
ofPhysicalPortListOf(Collection<ImmutablePort> ports) {
if (ports == null) {
throw new NullPointerException("Port list must not be null");
}
ArrayList<OFPhysicalPort> ofppList=
new ArrayList<OFPhysicalPort>(ports.size());
for (ImmutablePort p: ports) {
if (p == null)
throw new NullPointerException("Port must not be null");
ofppList.add(p.toOFPhysicalPort());
}
return ofppList;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder2 = new StringBuilder();
String linkState = (portStateLinkDown) ? "DOWN" : "UP";
builder2.append("Port [")
.append(name)
.append("(").append(portNumber).append(")")
.append(", hardwareAddress=")
.append(HexString.toHexString(hardwareAddress))
.append(", config=").append(config)
.append(", link=").append(linkState)
.append(", stpState=").append(stpState)
.append(", currentFeatures=").append(currentFeatures)
.append(", advertisedFeatures=").append(advertisedFeatures)
.append(", supportedFeatures=").append(supportedFeatures)
.append(", peerFeatures=").append(peerFeatures).append("]");
return builder2.toString();
}
}