队列
一个OpenFlow交换机可通过简单的队列结构提供有限的QoS(质量服务)支持,从而看出队列在OpenFlow交换机中的重要作用,所以在之前介绍了流表中的三部分内容之外,本节还将以队列角度来看OpenFlow 1.0协议在“四大常见结构”中的最后一个结构:队列结构(其余三个结构即为前三篇文章介绍的头部字段、计数器与动作)。
队列包含四个部分,分别为:
- 队列ID(32位)
- 长度(16位)
- 填充(2*8位,为对齐64位)
- 属性列表(列表)
协议中将结构定义如下:
struct ofp_packet_queue {
uint32_t queue_id;
uint16_t len;
uint8_t pad[2];
struct ofp_queue_prop_header properties[0];
};
OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8);
在OpenFlowJ的OFPacketQueue实现中,和第一节当中的头部字段中介绍的OpenFlow Message基类相类似(见前文:由OpenFlowJ源码学习OpenFlow协议V1.0(流表:头部字段)):
- 三个字段的获取&设置函数(queueId、length、properties)
- 工具:计算消息长度(computeLength)、转换为字符串(toString)
- 重写:重写hashCode函数、重写equals函数、深克隆(动作消息一节中用的浅克隆)
package org.openflow.protocol.queue;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.openflow.protocol.factory.OFQueuePropertyFactory;
import org.openflow.protocol.factory.OFQueuePropertyFactoryAware;
import org.openflow.util.U16;
// OFPacketQueue.java
public class OFPacketQueue implements Cloneable, OFQueuePropertyFactoryAware {
public static int MINIMUM_LENGTH = 8;
protected OFQueuePropertyFactory queuePropertyFactory;
protected int queueId;
protected short length;
protected List<OFQueueProperty> properties;
// 获取&设置队列ID
public int getQueueId() {
return queueId;
}
public OFPacketQueue setQueueId(int queueId) {
this.queueId = queueId;
return this;
}
// 获取&设置长度值
public short getLength() {
return length;
}
public int getLengthU() {
return U16.f(this.length);
}
public void setLength(short length) {
this.length = length;
}
// 获取&设置属性值
public List<OFQueueProperty> getProperties() {
return properties;
}
public OFPacketQueue setProperties(List<OFQueueProperty> properties) {
this.properties = properties;
return this;
}
// 读取:字节缓冲区(ByteBuffer)-->数据
// 写入:数据-->字节缓冲区(ByteBuffer)
public void readFrom(ByteBuffer data) {
this.queueId = data.getInt();
this.length = data.getShort();
data.getShort(); // pad
if (this.queuePropertyFactory == null)
throw new RuntimeException("OFQueuePropertyFactory not set");
this.properties = queuePropertyFactory.parseQueueProperties(data, U16.f(this.length) - MINIMUM_LENGTH);
}
public void writeTo(ByteBuffer data) {
data.putInt(this.queueId);
data.putShort(this.length);
data.putShort((short) 0); // pad
if (this.properties != null) {
for (OFQueueProperty queueProperty : this.properties) {
queueProperty.writeTo(data);
}
}
}
// 重写hashCode函数与equals函数
@Override
public int hashCode() {
final int prime = 6367;
int result = 1;
result = prime * result + length;
result = prime * result
+ ((properties == null) ? 0 : properties.hashCode());
result = prime * result + queueId;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof OFPacketQueue))
return false;
OFPacketQueue other = (OFPacketQueue) obj;
if (length != other.length)
return false;
if (properties == null) {
if (other.properties != null)
return false;
} else if (!properties.equals(other.properties))
return false;
if (queueId != other.queueId)
return false;
return true;
}
// 深克隆
@Override
public OFPacketQueue clone() {
try {
OFPacketQueue clone = (OFPacketQueue) super.clone();
if (this.properties != null) {
List<OFQueueProperty> queueProps = new ArrayList<OFQueueProperty>();
for (OFQueueProperty prop : this.properties) {
queueProps.add(prop.clone());
}
clone.setProperties(queueProps);
}
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// 设置队列属性工厂
@Override
public void setQueuePropertyFactory(
OFQueuePropertyFactory queuePropertyFactory) {
this.queuePropertyFactory = queuePropertyFactory;
}
// 转为字符串,由当前队列属性获取概述
@Override
public String toString() {
return "OFPacketQueue [queueId=" + queueId + ", properties="
+ properties + "]";
}
// 计算消息队列消息长度
public int computeLength() {
int l = MINIMUM_LENGTH;
if (this.properties != null) {
for (OFQueueProperty prop : this.properties) {
l += prop.getLengthU();
}
}
this.length = U16.t(l);
return l;
}
}
目前暂不讲工厂类的细节,等后面会整理各个工厂类的实现关系。
队列属性列表单元结构由三部分组成:
- 是否没有被定义的队列属性(默认没有队列属性,即为0)
- OpenFlow最低速率
- 待添加类型区域
在OpenFlow 1.0协议的结构定义如下:
enum ofp_queue_properties {
OFPQT_NONE = 0,
OFPQT_MIN_RATE,
... /* 其他待添加类型 */
};
所以在除了实现前两项的属性之外,还应当动态添加类型映射,在OpenFlowJ中的OFQueuePropertyType.java文件中。关于描述队列属性类型的具体代码实现方式如下:
package org.openflow.protocol.queue;
import java.lang.reflect.Constructor;
import org.openflow.protocol.Instantiable;
// OFQueuePropertyType.java
// 列出OpenFlow队列类型并映射到有线协议值与派生类
public class OFQueuePropertyType {
public static OFQueuePropertyType NONE = new OFQueuePropertyType(0, "NONE",
OFQueueProperty.class, new Instantiable<OFQueueProperty>() {
@Override
public OFQueueProperty instantiate() {
return new OFQueueProperty();
}
});
public static OFQueuePropertyType MIN_RATE = new OFQueuePropertyType(1, "MIN_RATE",
OFQueuePropertyMinRate.class, new Instantiable<OFQueueProperty>() {
@Override
public OFQueueProperty instantiate() {
return new OFQueuePropertyMinRate();
}
});
protected static OFQueuePropertyType[] mapping;
protected Class<? extends OFQueueProperty> clazz;
protected Constructor<? extends OFQueueProperty> constructor;
protected Instantiable<OFQueueProperty> instantiable;
protected int minLen;
protected String name;
protected short type;
// 初始化:类型值、类型名、派生类与可实例化类
public OFQueuePropertyType(int type, String name, Class<? extends OFQueueProperty> clazz, Instantiable<OFQueueProperty> instantiable) {
this.type = (short) type;
this.name = name;
this.clazz = clazz;
this.instantiable = instantiable;
try {
this.constructor = clazz.getConstructor(new Class[]{});
} catch (Exception e) {
throw new RuntimeException(
"Failure getting constructor for class: " + clazz, e);
}
OFQueuePropertyType.addMapping(this.type, this);
}
// 添加一个从类型值到OPType的枚举映射
static public void addMapping(short i, OFQueuePropertyType t) {
if (mapping == null)
mapping = new OFQueuePropertyType[16];
OFQueuePropertyType.mapping[i] = t;
}
// 通过类型值获取相关联的类型
static public OFQueuePropertyType valueOf(short i) {
return OFQueuePropertyType.mapping[i];
}
// 返回此类型的类型值
public short getTypeValue() {
return this.type;
}
// 获取此类型的子类
public Class<? extends OFQueueProperty> toClass() {
return clazz;
}
// 获取此类型的无参构造函数
public Constructor<? extends OFQueueProperty> getConstructor() {
return constructor;
}
// 获取当前类型的一个新建实例
public OFQueueProperty newInstance() {
return instantiable.instantiate();
}
// 获取&设置:可实例化接口
public Instantiable<OFQueueProperty> getInstantiable() {
return instantiable;
}
public void setInstantiable(Instantiable<OFQueueProperty> instantiable) {
this.instantiable = instantiable;
}
// 获取类型名
public String getName() {
return this.name;
}
@Override
public String toString() {
return this.name;
}
}
从上述代码中可看出,与之前三部分的枚举类差异不大,同时在前三节的类型枚举类代码中均涉及添加映射功能。