由OpenFlowJ源码学习OpenFlow协议V1.0(流表:头部字段)

流表(Flow Table):头部字段(Header Fields)

OpenFlow流表(Flow Table)
流表记录(Flow Table Entry)应当包含三个部分:

  1. 头部字段(header fields);
  2. 计数器(counters);
  3. 动作(actions)。
头部字段计数器动作
用于匹配包通过统计来更新已匹配的包应用已匹配的包

其中,在包的头部字段中,合规的12个元组名称及其属性如下所示:

元组名位数使用场景
进入端口(Ingress Port)-(依赖于实现)所有包
以太网源地址(Ethernet source address)48所有已开启端口的包
以太网目的地址(Ethernet destination address)48所有已开启端口的包
以太网类型(Ethernet type)16所有已开启端口的包
VLAN ID(VLAN id)12所有以太网类型为0x8100的包
VLAN优先级(VLAN priority)3所有以太网类型为0x8100的包
IP源地址(IP source address)32所有IP和ARP包
IP目的地址(IP destination address)32所有IP和ARP包
IP协议(IP protocol)8所有IP、IPoE、ARP包
IP ToS位(IP ToS bits)6所有IP包
传输源端口/ICMP类型(Transport source port / ICMP Type)16所有TCP、UDP和ICMP包
传输目的端口/ICMP码值(Transport destination port / ICMP Code)16所有TCP、UDP和ICMP包

所有的OpenFlow消息头部都具备以下头部结构,合计8字节,即64位:

  1. version:8位,OpenFlow版本号
  2. type:8位,OpenFlow消息类型,包含三种:
    1. Controller-to-Switch(控制器对交换机)
    2. Asynchronous(异步信息)
    3. Symmetric(对称信息)
  3. length:16位,包含头部在内的消息长度
  4. xid:32位,事务ID,使用请求时相同的事务ID作为回复ID,方便配对
// OpenFlow v1.0规定结构
struct ofp_header {
	uint8_t version;
	uint8_t type;
	uint16_t length;
	uint32_t xid;
};
OFP_ASSERT(sizeof(struct ofp_header) == 8);

在下方OpenFlowJ项目的OFMessage.java源文件中可看出,对于通用头部结构的操作可归纳为以下几点:

  1. 四个通用头部字段的获取&设置函数(version、length、type、xid)
  2. 计算长度用于写入数据(computeLength)
  3. 转换为字符串(toString)
  4. 重写hashCode函数
  5. 重写equals函数
package org.openflow.protocol;

import java.nio.ByteBuffer;
import org.openflow.util.U16;
import org.openflow.util.U32;
import org.openflow.util.U8;

// OFMessage.java文件
public class OFMessage {
	// 定义静态初始值
	public static byte OFP_VERSION = 0x01; // OpenFlow版本:1.0
    public static int MINIMUM_LENGTH = 8; // 最短长度(包含头部字段在内):8
    
    // 通用OpenFlow头部字段结构
    protected byte version;
    protected OFType type; 
    protected short length;
    protected int xid;
    
    // 初始化OpenFlow版本
    public OFMessage() {
        this.version = OFP_VERSION;
    }
    
    // 获取&设置:有、无符号的消息长度
    public short getLength() {
        return length;
    }
    public int getLengthU() {
        return U16.f(length);
    }
    public OFMessage setLength(short length) {
        this.length = length;
        return this;
    }
    public OFMessage setLengthU(int length) {
        this.length = U16.t(length);
        return this;
    }
    
    // 获取&设置:消息类型
    public OFType getType() {
        return type;
    }
    public OFMessage setType(OFType type) {
        this.type = type;
        return this;
    }
    
    // 获取&设置:OpenFlow版本号
    public byte getVersion() {
        return version;
    }
    public OFMessage setVersion(byte version) {
        this.version = version;
        return this;
    }
    
    // 获取&设置:事务ID
    public int getXid() {
        return xid;
    }
    public OFMessage setXid(int xid) {
        this.xid = xid;
        return this;
    }
    
    // 读取:字节缓冲区(ByteBuffer)-->数据
    // 写入:数据-->字节缓冲区(ByteBuffer)
    public void readFrom(ByteBuffer data) {
        this.version = data.get();
        this.type = OFType.valueOf(data.get()); // OPType.valueOf()函数:将编号翻译成对应的类型
        this.length = data.getShort();
        this.xid = data.getInt();
    }
    public void writeTo(ByteBuffer data) {
        computeLength();
        data.put(version);
        data.put(type.getTypeValue()); // type.getTypeValue()函数:获取类型值
        data.putShort(length);
        data.putInt(xid);
    }
    
    // 工具:计算长度&转换成字符串
    public void computeLength() {
        this.length = (short) MINIMUM_LENGTH;
    }
    public String toString() {
        return "ofmsg" +
            ":v=" + U8.f(this.getVersion()) +
            ";t=" + this.getType() +
            ";l=" + this.getLengthU() +
            ";x=" + U32.f(this.getXid());
    }
    
    // 重写hashCode函数与equals函数
    @Override
    public int hashCode() {
        final int prime = 97;
        int result = 1;
        result = prime * result + length;
        result = prime * result + ((type == null) ? 0 : type.hashCode());
        result = prime * result + version;
        result = prime * result + xid;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof OFMessage)) {
            return false;
        }
        OFMessage other = (OFMessage) obj;
        if (length != other.length) {
            return false;
        }
        if (type == null) {
            if (other.type != null) {
                return false;
            }
        } else if (!type.equals(other.type)) {
            return false;
        }
        if (version != other.version) {
            return false;
        }
        if (xid != other.xid) {
            return false;
        }
        return true;
    }
}

在解析完头部通用字段操作后,补充一些OpenFlow的类型介绍

类型名消息分类类型值
HELLO对称消息0
ERROR对称消息1
ECHO_REQUEST对称消息2
ECHO_REPLY对称消息3
VENDOR对称消息4
FEATURES_REQUEST控制器/交换机消息5
FEATURES_REPLY控制器/交换机消息6
GET_CONFIG_REQUEST控制器/交换机消息7
GET_CONFIG_REPLY控制器/交换机消息8
SET_CONFIG控制器/交换机消息9
PACKET_IN异步消息10
FLOW_REMOVED异步消息11
PORT_STATUS异步消息12
PACKET_OUT控制器/交换机消息13
FLOW_MOD控制器/交换机消息14
PORT_MOD控制器/交换机消息15
STATS_REQUEST控制器/交换机消息16
STATS_REPLY控制器/交换机消息17
BARRIER_REQUEST控制器/交换机消息18
BARRIER_REPLY控制器/交换机消息19
QUEUE_CONFIG_REQUEST控制器/交换机消息20
QUEUE_CONFIG_REPLY控制器/交换机消息21
UNKNOWN控制器/交换机消息0xff
// OpenFlow v1.0规定类型
enum ofp_type {
	/* 不可变消息 */
	OFPT_HELLO,
	OFPT_ERROR,
	OFPT_ECHO_REQUEST,
	OFPT_ECHO_REPLY,
	OFPT_VENDOR,
	/* 交换机配置消息 */
	OFPT_FEATURES_REQUEST,
	OFPT_FEATURES_REPLY,
	OFPT_GET_CONFIG_REQUEST,
	OFPT_GET_CONFIG_REPLY,
	OFPT_SET_CONFIG,
	/* 异步消息 */
	OFPT_PACKET_IN,
	OFPT_FLOW_REMOVED,
	OFPT_PORT_STATUS,
	/* 控制器命令消息 */
	OFPT_PACKET_OUT,
	OFPT_FLOW_MOD,
	OFPT_PORT_MOD,
	/* 统计消息 */
	OFPT_STATS_REQUEST,
	OFPT_STATS_REPLY,
	/* 栅栏消息 */
	OFPT_BARRIER_REQUEST,
	OFPT_BARRIER_REPLY,
	/* 队列配置消息 */
	OFPT_QUEUE_GET_CONFIG_REQUEST,
	OFPT_QUEUE_GET_CONFIG_REPLY
};

在下方OpenFlowJ项目的OFType.java源文件中对每个类型字段做了类型值定义,可归纳为以下几个功能点:

  1. 枚举OpenFlow类型
  2. 添加&删除一个类型值到OFType枚举的映射
  3. 通过类型值获取OPType枚举类型
  4. 获取与此OFType对应的类型值
  5. 获取与此OFType对应的OFMessage子类
  6. 获取此OFType实现类的无参构造函数
  7. 获取一个通过此OFType表示的OFMessage的新实例
  8. 获取&设置可实例化接口
package org.openflow.protocol;

import java.lang.reflect.Constructor;
import org.openflow.util.U8;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// OFType.java
// OpenFlow v1.0中,type字段占8位
public enum OFType {
    HELLO               (0, OFHello.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFHello();
                            }}),
    ERROR               (1, OFError.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFError();
                            }}),
    ECHO_REQUEST        (2, OFEchoRequest.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFEchoRequest();
                            }}),
    ECHO_REPLY          (3, OFEchoReply.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFEchoReply();
                            }}),
    VENDOR              (4, OFVendor.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFVendor();
                            }}),
    FEATURES_REQUEST    (5, OFFeaturesRequest.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFFeaturesRequest();
                            }}),
    FEATURES_REPLY      (6, OFFeaturesReply.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFFeaturesReply();
                            }}),
    GET_CONFIG_REQUEST  (7, OFGetConfigRequest.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFGetConfigRequest();
                            }}),
    GET_CONFIG_REPLY    (8, OFGetConfigReply.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFGetConfigReply();
                            }}),
    SET_CONFIG          (9, OFSetConfig.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFSetConfig();
                            }}),
    PACKET_IN           (10, OFPacketIn.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFPacketIn();
                            }}),
    FLOW_REMOVED        (11, OFFlowRemoved.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFFlowRemoved();
                            }}),
    PORT_STATUS         (12, OFPortStatus.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFPortStatus();
                            }}),
    PACKET_OUT          (13, OFPacketOut.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFPacketOut();
                            }}),
    FLOW_MOD            (14, OFFlowMod.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFFlowMod();
                            }}),
    PORT_MOD            (15, OFPortMod.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFPortMod();
                            }}),
    STATS_REQUEST       (16, OFStatisticsRequest.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFStatisticsRequest();
                            }}),
    STATS_REPLY         (17, OFStatisticsReply.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFStatisticsReply();
                            }}),
    BARRIER_REQUEST     (18, OFBarrierRequest.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFBarrierRequest();
                            }}),
    BARRIER_REPLY       (19, OFBarrierReply.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFBarrierReply();
                            }}),
    QUEUE_CONFIG_REQUEST    (20, OFMessage.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFQueueConfigRequest();
                            }}),
    QUEUE_CONFIG_REPLY  (21, OFMessage.class, new Instantiable<OFMessage>() {
                            @Override
                            public OFMessage instantiate() {
                                return new OFQueueConfigReply();
                            }}),
    UNKNOWN             (0xff, OFUnknownMessage.class, new Instantiable<OFMessage>() {
                                @Override
                                public OFMessage instantiate() {
                                    return new OFUnknownMessage();
                            }});

    protected static Logger log = LoggerFactory.getLogger(OFType.class);

    static OFType[] mapping;

    protected Class<? extends OFMessage> clazz;
    protected Constructor<? extends OFMessage> constructor;
    protected Instantiable<OFMessage> instantiable;
    protected byte type;

	// 初始化OFType
    OFType(int type, Class<? extends OFMessage> clazz, Instantiable<OFMessage> instantiator) {
        this.type = (byte) type;
        this.clazz = clazz;
        this.instantiable = instantiator;
        try {
            this.constructor = clazz.getConstructor(new Class[]{}); // clazz.getConstructor()函数:获取有参数构造函数
        } catch (Exception e) {
            throw new RuntimeException(
                    "Failure getting constructor for class: " + clazz, e);
        }
        OFType.addMapping(this.type, this);
    }

    // 添加&移除:一个从类型值到OPType的枚举映射
    static public void addMapping(byte i, OFType t) {
        if (mapping == null)
            mapping = new OFType[32];
        if (i >= 0 && i < 32)
            OFType.mapping[i] = t;
    }
    static public void removeMapping(byte i) {
        if (i >= 0 && i < 32)
            OFType.mapping[i] = null;
    }

    // 通过类型值获取OPType枚举类型
    static public OFType valueOf(Byte i) {
        try {
            return OFType.mapping[i];
        } catch (ArrayIndexOutOfBoundsException e) {
            log.warn("Unknown message type requested: {}", U8.f(i));
            return UNKNOWN;
        }
    }

    // 获取与此OFType对应的类型值
    public byte getTypeValue() {
        return this.type;
    }

    // 获取与此OFType对应的OFMessage子类
    public Class<? extends OFMessage> toClass() {
        return clazz;
    }

    // 获取此OFType实现类的无参构造函数
    public Constructor<? extends OFMessage> getConstructor() {
        return constructor;
    }

    // 获取一个通过此OFType表示的OFMessage的新实例
    public OFMessage newInstance() {
        return instantiable.instantiate();
    }

    // 获取&设置:可实例化接口
    public Instantiable<OFMessage> getInstantiable() {
        return instantiable;
    }
    public void setInstantiable(Instantiable<OFMessage> instantiable) {
        this.instantiable = instantiable;
    }
}
  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫零NET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值