流表(Flow Table):计数器(Counters)
OpenFlow流表(Flow Table)
流表记录(Flow Table Entry)应当包含三个部分:
- 头部字段(header fields);
- 计数器(counters);
- 动作(actions)。
头部字段 | 计数器 | 动作 |
---|---|---|
用于匹配包 | 通过统计来更新已匹配的包 | 应用已匹配的包 |
其中,计数器要求统计消息中应当包含如下内容:
每张表的计数器 | 位数 |
---|---|
启用记录数 | 32 |
包查询数 | 64 |
包匹配数 | 64 |
每条流的计数器 | 位数 |
---|---|
接收包数 | 64 |
接收字节数 | 64 |
时长(秒) | 32 |
时长(微秒) | 32 |
每个端口的计数器 | 位数 |
---|---|
接收包数 | 64 |
已传输包数 | 64 |
接收字节数 | 64 |
已传输字节数 | 64 |
接收丢弃数 | 64 |
已传输丢弃数 | 64 |
接收错误数 | 64 |
已传输错误数 | 64 |
接收帧队列错误数 | 64 |
接收溢出错误数 | 64 |
接收CRC错误数 | 64 |
冲突数 | 64 |
每个队列的计数器 | 位数 |
---|---|
已传输包数 | 64 |
已传输字节数 | 64 |
已传输溢出错误数 | 64 |
在下方OpenFlowJ项目的OFStatistics.java源文件中,仅定义接口类,包含四个方法声明:
- getLength():获取消息长度
- readFrom():读取数据,类型为ByteBuffer
- writeTo():向ByteBuffer中写入数据
- computeLength():计算消息长度
package org.openflow.protocol.statistics;
import java.nio.ByteBuffer;
//OpenFlow统计基类(计数器)
public interface OFStatistics {
// 获取消息长度(单位:byte)
public int getLength();
// 从ByteBuffer中读取数据
public void readFrom(ByteBuffer data);
// 将数据写入ByteFuffer
public void writeTo(ByteBuffer data);
// 计算消息长度
public int computeLength();
}
围绕OFStatistics接口实现如下几个分类统计功能,对应协议附件的Read State Messages一节内容:
- Description:描述统计,描述OpenFlow交换机信息,请求体为空,回复体参考ofp_desc_stats
- Table:表统计,请求体为空,回复体是一组结构体,每个结构体参考ofp_table_stats
- Vendor:供应商统计,扩展,请求与回复体都以32位vendor ID开始,与结构体ofp_vendor_header是相同格式
- Aggregate(Request&Reply,请求与回复):聚合统计,聚合流统计,请求体参考ofp_aggregate_stats_request,回复体参考ofp_aggregate_stats_reply,请求体和应答体由供应商定义。
- Flow(Request&Reply,请求与回复):流统计,独立的流统计,请求体参考ofp_flow_stats_request,回复体是一组结构体,每个结构体参考ofp_flow_stats
- Port(Request&Reply,请求与回复):端口统计,物理端口统计,请求体参考ofp_port_stats_request,回复体是一组结构体,每个结构体参考ofp_port_stats
- Queue(Request&Reply,请求与回复):队列统计,一个端口的队列统计,请求体参考物理端口请求定义,回复体是一组结构体,每个结构体参考ofp_queue_stats
目前暂不深入解析这7个统计类,先作为简单介绍,后期将展开进行源码解析。在OpenFlow v1.0官方协议中定义了统计类型,具体如下:
enum ofp_stats_types {
OFPST_DESC,
OFPST_FLOW,
OFPST_AGGREGATE,
OFPST_TABLE,
OFPST_PORT,
OFPST_QUEUE,
OFPST_VENDOR = 0xffff
};
在OFStatisticsType.java文件中定义了统计类型的枚举类,即上述7个功能,其源码如下:
package org.openflow.protocol.statistics;
import java.lang.reflect.Constructor;
import org.openflow.protocol.Instantiable;
import org.openflow.protocol.OFType;
// OFStatisticsType.java
// 枚举统计类型,即计数器的内容分类。
public enum OFStatisticsType {
DESC (0, OFDescriptionStatistics.class, OFDescriptionStatistics.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFDescriptionStatistics();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFDescriptionStatistics();
}
}),
FLOW (1, OFFlowStatisticsRequest.class, OFFlowStatisticsReply.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFFlowStatisticsRequest();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFFlowStatisticsReply();
}
}),
AGGREGATE (2, OFAggregateStatisticsRequest.class, OFAggregateStatisticsReply.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFAggregateStatisticsRequest();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFAggregateStatisticsReply();
}
}),
TABLE (3, OFTableStatistics.class, OFTableStatistics.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFTableStatistics();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFTableStatistics();
}
}),
PORT (4, OFPortStatisticsRequest.class, OFPortStatisticsReply.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFPortStatisticsRequest();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFPortStatisticsReply();
}
}),
QUEUE (5, OFQueueStatisticsRequest.class, OFQueueStatisticsReply.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFQueueStatisticsRequest();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFQueueStatisticsReply();
}
}),
VENDOR (0xffff, OFVendorStatistics.class, OFVendorStatistics.class,
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFVendorStatistics();
}
},
new Instantiable<OFStatistics>() {
@Override
public OFStatistics instantiate() {
return new OFVendorStatistics();
}
});
static OFStatisticsType[] requestMapping;
static OFStatisticsType[] replyMapping;
protected Class<? extends OFStatistics> requestClass;
protected Constructor<? extends OFStatistics> requestConstructor;
protected Instantiable<OFStatistics> requestInstantiable;
protected Class<? extends OFStatistics> replyClass;
protected Constructor<? extends OFStatistics> replyConstructor;
protected Instantiable<OFStatistics> replyInstantiable;
protected short type;
// 初始化OpenFlow统计类型,包含类型值与派生类
OFStatisticsType(int type, Class<? extends OFStatistics> requestClass,
Class<? extends OFStatistics> replyClass,
Instantiable<OFStatistics> requestInstantiable,
Instantiable<OFStatistics> replyInstantiable) {
this.type = (short) type;
this.requestClass = requestClass;
try {
this.requestConstructor = requestClass.getConstructor(new Class[]{});
} catch (Exception e) {
throw new RuntimeException(
"Failure getting constructor for class: " + requestClass, e);
}
this.replyClass = replyClass;
try {
this.replyConstructor = replyClass.getConstructor(new Class[]{});
} catch (Exception e) {
throw new RuntimeException(
"Failure getting constructor for class: " + replyClass, e);
}
this.requestInstantiable = requestInstantiable;
this.replyInstantiable = replyInstantiable;
OFStatisticsType.addMapping(this.type, OFType.STATS_REQUEST, this);
OFStatisticsType.addMapping(this.type, OFType.STATS_REPLY, this);
}
// 添加&移除:从类型值到统计类枚举的映射
static public void addMapping(short i, OFType t, OFStatisticsType st) {
if (i < 0)
i = (short) (16+i);
if (t == OFType.STATS_REQUEST) {
if (requestMapping == null)
requestMapping = new OFStatisticsType[16];
OFStatisticsType.requestMapping[i] = st;
} else if (t == OFType.STATS_REPLY){
if (replyMapping == null)
replyMapping = new OFStatisticsType[16];
OFStatisticsType.replyMapping[i] = st;
} else {
throw new RuntimeException(t.toString() + " is an invalid OFType");
}
}
static public void removeMapping(short i, OFType t) {
if (i < 0)
i = (short) (16+i);
if (t == OFType.STATS_REQUEST) {
requestMapping[i] = null;
} else if (t == OFType.STATS_REPLY){
replyMapping[i] = null;
} else {
throw new RuntimeException(t.toString() + " is an invalid OFType");
}
}
// 通过类型值获取统计类型
static public OFStatisticsType valueOf(short i, OFType t) {
if (i < 0)
i = (short) (16+i);
if (t == OFType.STATS_REQUEST) {
return requestMapping[i];
} else if (t == OFType.STATS_REPLY){
return replyMapping[i];
} else {
throw new RuntimeException(t.toString() + " is an invalid OFType");
}
}
// 获取此统计类型的类型值
public short getTypeValue() {
return this.type;
}
// 获取此统计类型的子类:(只接受STATS_REQUEST与STATS_REPLY)
public Class<? extends OFStatistics> toClass(OFType t) {
if (t == OFType.STATS_REQUEST) {
return requestClass;
} else if (t == OFType.STATS_REPLY){
return replyClass;
} else {
throw new RuntimeException(t.toString() + " is an invalid OFType");
}
}
// 根据提供的请求或回复(STATS_REQUEST或STATS_REPLY),获取此OFStatisticsType实现类的无参构造函数
public Constructor<? extends OFStatistics> getConstructor(OFType t) {
if (t == OFType.STATS_REQUEST) {
return requestConstructor;
} else if (t == OFType.STATS_REPLY) {
return replyConstructor;
} else {
throw new RuntimeException(t.toString() + " is an invalid OFType");
}
}
// 获取&设置:可实例化请求&回复接口
public Instantiable<OFStatistics> getRequestInstantiable() {
return requestInstantiable;
}
public void setRequestInstantiable(
Instantiable<OFStatistics> requestInstantiable) {
this.requestInstantiable = requestInstantiable;
}
public Instantiable<OFStatistics> getReplyInstantiable() {
return replyInstantiable;
}
public void setReplyInstantiable(Instantiable<OFStatistics> replyInstantiable) {
this.replyInstantiable = replyInstantiable;
}
// 根据提供的请求或回复(STATS_REQUEST或STATS_REPLY),获取一个此OFStatisticsType实现类的新实例
public OFStatistics newInstance(OFType t) {
if (t == OFType.STATS_REQUEST) {
return requestInstantiable.instantiate();
} else if (t == OFType.STATS_REPLY) {
return replyInstantiable.instantiate();
} else {
throw new RuntimeException(t.toString() + " is an invalid OFType");
}
}
}
结合上一篇关于流表内容的头部字段类型源码分析,可总结源码实现类型代码时的共性:
- 枚举所有类型名称,及其对应子类
- 初始化(存储基本信息、添加映射操作)
- 映射操作(添加&移除映射)
- 查询操作(根据类型名查询类型、查询此类型名、查询此类型类、获取此类构造器)
- 实例化操作(实例化接口获取&设置、新建此类型实例)