/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* 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 org.openflow.protocol;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer;
import net.floodlightcontroller.core.web.serializers.UShortSerializer;
import net.floodlightcontroller.util.EnumBitmaps;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.jboss.netty.buffer.ChannelBuffer;
import org.openflow.util.HexString;
/**
* Represents ofp_phy_port
* @author David Erickson (daviderickson@cs.stanford.edu) - Mar 25, 2010
*/
public class OFPhysicalPort {
public final static int MINIMUM_LENGTH = 48;
public final static int OFP_ETH_ALEN = 6;
public enum OFPortConfig implements EnumBitmaps.BitmapableEnum {
OFPPC_PORT_DOWN (1 << 0) {
@Override
public String toString() {
return "port-down (0x1)";
}
},
OFPPC_NO_STP (1 << 1) {
@Override
public String toString() {
return "no-stp (0x2)";
}
},
OFPPC_NO_RECV (1 << 2) {
@Override
public String toString() {
return "no-recv (0x4)";
}
},
OFPPC_NO_RECV_STP (1 << 3) {
@Override
public String toString() {
return "no-recv-stp (0x8)";
}
},
OFPPC_NO_FLOOD (1 << 4) {
@Override
public String toString() {
return "no-flood (0x10)";
}
},
OFPPC_NO_FWD (1 << 5) {
@Override
public String toString() {
return "no-fwd (0x20)";
}
},
OFPPC_NO_PACKET_IN (1 << 6) {
@Override
public String toString() {
return "no-pkt-in (0x40)";
}
},
OFPPC_BSN_MIRROR_DEST (1 << 31) {
@Override
public String toString() {
return "bsn-mirror-dest (0x80000000)";
}
};
protected int value;
private OFPortConfig(int value) {
this.value = value;
}
/**
* @return the value
*/
@Override
public int getValue() {
return value;
}
}
public enum OFPortState {
OFPPS_LINK_DOWN (1 << 0, false) {
@Override
public String toString() {
return "link-down (0x1)";
}
},
OFPPS_STP_LISTEN (0 << 8, true) {
@Override
public String toString() {
return "listen (0x0)";
}
},
OFPPS_STP_LEARN (1 << 8, true) {
@Override
public String toString() {
return "learn-no-relay (0x100)";
}
},
OFPPS_STP_FORWARD (2 << 8, true) {
@Override
public String toString() {
return "forward (0x200)";
}
},
OFPPS_STP_BLOCK (3 << 8, true) {
@Override
public String toString() {
return "block-broadcast (0x300)";
}
},
OFPPS_STP_MASK (3 << 8, false) { // used for STP but not an STP state
@Override
public String toString() {
return "block-broadcast (0x300)";
}
};
protected int value;
protected boolean isStpState;
private OFPortState(int value, boolean isStpState) {
this.value = value;
this.isStpState = isStpState;
}
/**
* Returns true if this constants represents one of the four STP
* states
* @return
*/
public boolean isStpState() {
return isStpState;
}
/**
* return the STP state represented by the given integer.
* the returned value will have isStpState() == true
* @param state
* @return
*/
public static OFPortState getStpState(int state) {
// this ain't pretty
state = state & OFPortState.OFPPS_STP_MASK.getValue();
for (OFPortState s: OFPortState.values()) {
if (!s.isStpState())
continue;
if (state == s.getValue())
return s;
}
return null; // will never happen
}
public static boolean isPortDown(int state) {
if ((state & OFPPS_LINK_DOWN.getValue()) != 0)
return true;
else
return false;
}
/**
* @return the value
*/
public int getValue() {
return value;
}
}
/**
* Represents the speed of a port
*/
public enum PortSpeed {
/** no speed set */
SPEED_NONE(0),
SPEED_10MB(10),
SPEED_100MB(100),
SPEED_1GB(1000),
SPEED_10GB(10000);
private long speedInBps;
private PortSpeed(int speedInMbps) {
this.speedInBps = speedInMbps * 1000*1000;
}
public long getSpeedBps() {
return this.speedInBps;
}
public static PortSpeed max(PortSpeed s1, PortSpeed s2) {
return (s1.getSpeedBps() > s2.getSpeedBps()) ? s1 : s2;
}
public static PortSpeed min(PortSpeed s1, PortSpeed s2) {
return (s1.getSpeedBps() < s2.getSpeedBps()) ? s1 : s2;
}
}
public enum OFPortFeatures implements EnumBitmaps.BitmapableEnum {
OFPPF_10MB_HD (1 << 0, PortSpeed.SPEED_10MB) {
@Override
public String toString() {
return "10mb-hd (0x1)";
}
},
OFPPF_10MB_FD (1 << 1, PortSpeed.SPEED_10MB) {
@Override
public String toString() {
return "10mb-fd (0x2)";
}
},
OFPPF_100MB_HD (1 << 2, PortSpeed.SPEED_100MB) {
@Override
public String toString() {
return "100mb-hd (0x4)";
}
},
OFPPF_100MB_FD (1 << 3, PortSpeed.SPEED_100MB) {
@Override
public String toString() {
return "100mb-fd (0x8)";
}
},
OFPPF_1GB_HD (1 << 4, PortSpeed.SPEED_1GB) {
@Override
public String toString() {
return "1gb-hd (0x10)";
}
},
OFPPF_1GB_FD (1 << 5, PortSpeed.SPEED_1GB) {
@Override
public String toString() {
return "1gb-fd (0x20)";
}
},
OFPPF_10GB_FD (1 << 6, PortSpeed.SPEED_10GB) {
@Override
public String toString() {
return "10gb-fd (0x40)";
}
},
OFPPF_COPPER (1 << 7, PortSpeed.SPEED_NONE) {
@Override
public String toString() {
return "copper (0x80)";
}
},
OFPPF_FIBER (1 << 8, PortSpeed.SPEED_NONE) {
@Override
public String toString() {
return "fiber (0x100)";
}
},
OFPPF_AUTONEG (1 << 9, PortSpeed.SPEED_NONE) {
@Override
public String toString() {
return "autoneg (0x200)";
}
},
OFPPF_PAUSE (1 << 10, PortSpeed.SPEED_NONE) {
@Override
public String toString() {
return "pause (0x400)";
}
},
OFPPF_PAUSE_ASYM (1 << 11, PortSpeed.SPEED_NONE) {
@Override
public String toString() {
return "pause-asym (0x800)";
}
};
protected int value;
protected PortSpeed speed;
private OFPortFeatures(int value, PortSpeed speed) {
this.value = value;
if (speed == null)
throw new NullPointerException();
this.speed = speed;
}
/**
* @return the bitmap value for this constant
*/
@Override
public int getValue() {
return value;
}
/**
* @return the port speed associated with this constant. If the
* constant doesn't represent a port speed it returns SPEED_NONE
*/
public PortSpeed getSpeed() {
return speed;
}
}
protected short portNumber;
protected byte[] hardwareAddress;
protected String name;
protected int config;
protected int state;
protected int currentFeatures;
protected int advertisedFeatures;
protected int supportedFeatures;
protected int peerFeatures;
/**
* @return the portNumber
*/
@JsonSerialize(using=UShortSerializer.class)
public short getPortNumber() {
return portNumber;
}
/**
* @param portNumber the portNumber to set
*/
public void setPortNumber(short portNumber) {
this.portNumber = portNumber;
}
/**
* @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;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the config
*/
public int getConfig() {
return config;
}
/**
* @param config the config to set
*/
public void setConfig(int config) {
this.config = config;
}
/**
* @return the state
*/
public int getState() {
return state;
}
/**
* @param state the state to set
*/
public void setState(int state) {
this.state = state;
}
/**
* @return the currentFeatures
*/
public int getCurrentFeatures() {
return currentFeatures;
}
/**
* @param currentFeatures the currentFeatures to set
*/
public void setCurrentFeatures(int currentFeatures) {
this.currentFeatures = currentFeatures;
}
/**
* @return the advertisedFeatures
*/
public int getAdvertisedFeatures() {
return advertisedFeatures;
}
/**
* @param advertisedFeatures the advertisedFeatures to set
*/
public void setAdvertisedFeatures(int advertisedFeatures) {
this.advertisedFeatures = advertisedFeatures;
}
/**
* @return the supportedFeatures
*/
public int getSupportedFeatures() {
return supportedFeatures;
}
/**
* @param supportedFeatures the supportedFeatures to set
*/
public void setSupportedFeatures(int supportedFeatures) {
this.supportedFeatures = supportedFeatures;
}
/**
* @return the peerFeatures
*/
public int getPeerFeatures() {
return peerFeatures;
}
/**
* @param peerFeatures the peerFeatures to set
*/
public void setPeerFeatures(int peerFeatures) {
this.peerFeatures = peerFeatures;
}
/**
* Read this message off the wire from the specified ByteBuffer
* @param data
*/
public void readFrom(ChannelBuffer data) {
this.portNumber = data.readShort();
if (this.hardwareAddress == null)
this.hardwareAddress = new byte[OFP_ETH_ALEN];
data.readBytes(this.hardwareAddress);
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"));
this.config = data.readInt();
this.state = data.readInt();
this.currentFeatures = data.readInt();
this.advertisedFeatures = data.readInt();
this.supportedFeatures = data.readInt();
this.peerFeatures = data.readInt();
}
/**
* Write this message's binary format to the specified ByteBuffer
* @param data
*/
public void writeTo(ChannelBuffer data) {
data.writeShort(this.portNumber);
data.writeBytes(hardwareAddress);
try {
byte[] name = this.name.getBytes("ASCII");
if (name.length < 16) {
data.writeBytes(name);
for (int i = name.length; i < 16; ++i) {
data.writeByte((byte) 0);
}
} else {
data.writeBytes(name, 0, 15);
data.writeByte((byte) 0);
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
data.writeInt(this.config);
data.writeInt(this.state);
data.writeInt(this.currentFeatures);
data.writeInt(this.advertisedFeatures);
data.writeInt(this.supportedFeatures);
data.writeInt(this.peerFeatures);
}
@Override
public int hashCode() {
final int prime = 307;
int result = 1;
result = prime * result + advertisedFeatures;
result = prime * result + config;
result = prime * result + currentFeatures;
result = prime * result + Arrays.hashCode(hardwareAddress);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + peerFeatures;
result = prime * result + portNumber;
result = prime * result + state;
result = prime * result + supportedFeatures;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof OFPhysicalPort)) {
return false;
}
OFPhysicalPort other = (OFPhysicalPort) obj;
if (advertisedFeatures != other.advertisedFeatures) {
return false;
}
if (config != other.config) {
return false;
}
if (currentFeatures != other.currentFeatures) {
return false;
}
if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (peerFeatures != other.peerFeatures) {
return false;
}
if (portNumber != other.portNumber) {
return false;
}
if (state != other.state) {
return false;
}
if (supportedFeatures != other.supportedFeatures) {
return false;
}
return true;
}
@Override
public String toString() {
String linkState, linkSpeed;
if ((state & OFPortState.OFPPS_LINK_DOWN.getValue()) != 0) {
linkState = "down";
} else {
linkState = "up";
}
if ((currentFeatures & OFPortFeatures.OFPPF_10GB_FD.getValue()) != 0) {
linkSpeed = "10G";
} else if ((currentFeatures & OFPortFeatures.OFPPF_1GB_FD.getValue()) != 0) {
linkSpeed = "1G";
} else if ((currentFeatures & OFPortFeatures.OFPPF_1GB_HD.getValue()) != 0) {
linkSpeed = "1G(half-duplex)";
} else if ((currentFeatures & OFPortFeatures.OFPPF_100MB_FD.getValue()) != 0) {
linkSpeed = "100M";
} else if ((currentFeatures & OFPortFeatures.OFPPF_100MB_HD.getValue()) != 0) {
linkSpeed = "100M(half-duplex)";
} else if ((currentFeatures & OFPortFeatures.OFPPF_10MB_FD.getValue()) != 0) {
linkSpeed = "10M";
} else if ((currentFeatures & OFPortFeatures.OFPPF_10MB_HD.getValue()) != 0) {
linkSpeed = "10M(half-duplex)";
} else {
linkSpeed = "unknown";
}
return "port " + name + " (" + portNumber + ")" +
", mac " + HexString.toHexString(hardwareAddress) +
", state " + linkState +
", speed " + linkSpeed;
}
}