OpenFlow协议学习

OpenFlow 1.0 协议总结

OpenFlow交换机中包含了1个以上的流表,流表又包含多个流表项。对于接收到的数据包,OpenFlow交换机在流表中选择一个最合适的流表项,并按流表项的内容对数据包进行处理。

流表中包含的流表项由以下3个基本要素组成:Head Field, Counter, Action。Head Field即匹配规则,Counter即匹配次数,Action即匹配后所需要采取的操作。

流表项

Head Field

  • Ingress Port
  • Ethernet source address
  • Ethernet destination address
  • Ethernet type
  • VLAN id
  • VLAN Priority(802.1q PCP)
  • IP source address
  • IP destination address
  • ToS
  • Transport source port/ICMP type
  • Transport destination port/ICMP code

在1.0版本中,STP(802.1d)数据包不执行流表匹配。完成STP处理后,执行“头字段解析之后”,会在此基础上进行数据包与流表的匹配。当数据包与刘表内设置的多条流表项匹配时,优先级最高的流表项即为匹配结果。OpenFlow中可以存在多个流表,但必须从流表0开始匹配。若编号为0的流表中不存在与数据包相匹配的流表项,而在其他流表中存在的话,则前进到下一流表中执行匹配。 数据包与OpenFlow交换机中任何一个流表项都不匹配的情况称之为Table-miss,这种情况下会利用Packet-In消息将数据包转发至控制器,或者丢弃。具体情况会根据设置决定。

Counter

4种计数器 Per Table, Per Port, Per Flow, Per Queue。

Per Table: Active Entries, Packet Lookups, Packet Matches

Per Flow: Received Packets/Bytes, Duration(msec/usec)

Per Queue: Transmit Packets/Bytes, Transmit Overrun Errors

Per Port: Received Packets/Bytes/Drops/Errors, Transmit Packets/Bytes/Drops/Errors, Receive Frame Alignment Errors, Received Overrun Errors, Received CRC Errors, Collisions

Action

Forward, Drop, Enqueue(Optional), Modify-Field(Optional)

Forward

名称 说明 虚拟端口
(port) 转发至指定端口 port
ALL 除接收端口以外的所有端口 0xfffc
CONTROLLER 控制器 0xfffd
LOCAL 发送至本地网络栈 0xfffe
TABLE 执行流表中行动(仅Packet-Out) 0xfff9
IN_PORT 从输入端口发出 0xfff8
NORMAL(optional) 传统L2或L3交换机动作 0xfffa
FLOOD(optional) 按照STP发送 0xfffb

Drop

未在协议中明确说明

Enqueue

在等待队列的末尾添加数据包

Modify-Field

  • 设置VLAN ID
  • 设置VLAN priority
  • 去掉VLAN头
  • 修改源MAC
  • 修改目的MAC
  • 修改源IP
  • 修改目的IP
  • 修改ToS
  • 修改源端口
  • 修改目的端口

控制器和交换机之间的安全通道

安全通道通过控制面网络来建立,不受OpenFlow交换机中的流表项的影响。规范中安全通道应该使用TLS实现,但在OpenFlow 1.1开始添加了TCP明文的方式,默认的TCP端口为6653。

struct openflow_header {
    uint8_t version; // 版本,OpenFlow 1.0-1.3分别对应0x01-0x04
    uint8_t type; // 消息类型,表明OpenFlow消息的类型
    uint16_t length; // Byte数
    uint32_t xid; // 事务ID
}

安全通道的建立过程

  1. 建立TCP/TLS连接
  2. 确定使用的OpenFlow版本,type字段值为OFPT_HELLO,在version中放入各自支持的最大版本号。
  3. 握手,type字段值为OFPT_FEATURES_REQUEST和OFPT_FEATURES_RESPONSE
struct features_response {
    uint64_t datapath_id; // datapath id唯一标识OpenFlow交换机
    uint32_t n_buffer; // 缓存数据包的最大个数
    uint8_t n_tables; // 支持的流表个数
    char pad[24]; 
    uint32_t capabilities; // 支持的容量
    uint32_t actions; // 支持的行动
    struct ofp_phy_port ports[??]; // 物理端口信息
}

struct ofp_phy_port {
    uint16_t port_no; // 物理端口号
    uint8_t hw_addr[OFP_ETH_LENGTH]; // 48位的以太网地址
    uint8_t name[OFP_MAX_PORT_NAME_LEN]; // 128位的端口名称
    uint32_t config; // 端口设置bitmap
    uint32_t state; // 端口状态bitmap
    uint32_t curr; // 当前功能
    uint32_t advertised; // 广播功能
    uint32_t supported;  // 支持功能
    uint32_t peer;  // 连接方广播功能
}
  1. 交换设置(optional)。type为OFPT_SET_CONFIG/OFPT_GET_CONFIG。
struct set_config_message {
    uint16_t flags; // IP碎片处理方法
    uint16_t miss_send_len; // Table-miss数据包个数
}

enum set_config_flag {
    OFPC_FRAG_NORMAL = 0, // 依据流表处理
    OFPC_FRAG_DROP, // 丢弃
    OFPC_FRAG_REASM, // 重组
    OFPC_FRAG_MASK // unknown
}
  1. 其他可能交换的内容 STATS,QUEUE_GET_CONFIG,Vendor, …

Flow-Mod

对于流表进行修改的消息,可以进行添加、删除和变更设置等操作。 种类包括以下几种

  1. OFPFC_ADD
  2. OFPFC_MODIFY
  3. OFPFC_MODIFY_STRICT
  4. OFPFC_DELETE
  5. OFPFC_DELETE_STRICT 后面加上STRICT表示要完全匹配。如果有错误发生,那么将回复错误信息。如果在流表中存在相同项,那么会将原有计数器清零。
struct flow_mod_message {
    struct ofp_match match; // 数据包匹配信息
    uint8_t cookie[64];
    uint8_t action[??]; 
    
}

struct ofp_match {
    uint32_t wildcards; // 无视哪个字段的通配符
    uint16_t in_port; // 输入物理端口
    uint8_t dl_src[OFP_ETH_ALEN]; // 源MAC地址
    uint8_t dl_dst[OFP_ETH_ALEN]; // 目的MAC地址
    uint16_t dl_vlan; // VLAN id
    uint8_t dl_vlan_pcp;  // VLAN 优先级
    uint8_t pad1; 
    uint16_t dl_type; // 以太网帧类型 
    uint8_t nw_tos; // ToS字段
    uint8_t nw_proto; // IP协议号
    uint16_t pad2;
    uint32_t nw_src; // 源IPv4地址
    uint32_t nw_dst; // 目的IPv4地址
    uint16_t tp_src; // 源端口或ICMP类型
    uint16_t tp_dst; // 目的端口或ICMP代码
}

struct flow_mod_action {
    uint16_t command; // 即上面提到的action种类
    uint16_t idle_timeout; // 如果本条规则在idle_timeout时间内没有应用成功,那么将删除该规则
    uint16_t hard_timeout; // 如果本条规则在hard_timeout时间内还未添加成功,那么将取消添加该规则。
    uint16_t priority; // 规则优先级
    uint32_t buffer_id; // 缓存ID
    uint16_t out_port; // 输出端口号
    uint16_t flags;
    uint8_t actions[??]; // TLV结构,一个头部包含修改种类,后面接上具体的数据
}

Packet-In

Packet-In消息用于将到达OpenFlow交换机的数据包发送至OpenFlow交换机。根据交换机是否缓存数据包来设置buffer_id的值:不缓存则设置为-1,将整个数据包发送;缓存则会根据SET_CONFIG消息设置的miss_send_len为最大值的数据包发送,默认值为128。

struct packet_in_message {
    uint32_t buffer_id; // 缓存ID
    uint16_t total_len; // 帧长度
    uint16_t in_port; // 接受帧端口
    uint8_t reason; // 发送原因(不匹配0,流表指定1)
    uint8_t pad;
    uint8_t data[??]; // 具体数据包
}

Packet-Out

Packet-Out即为控制器向交换机发送的消息。

struct packet_out_message {
    uint32_t buffer_id; // 缓存ID
    uint16_t in_port; // 输入端口,用OFPP_NONE表示未指定,用OFPP_CONTROLLER表示是控制器创建的数据包
    uint16_t actions_len;
    uint8_t actions[actions_len]; // 类似于Flow-Mod时的action
    uint8_t data[??]; // 当buffer_id为-1的时候,即不指定交换器缓存时
}

Port-Status

在OpenFlow交换机添加、删除或修改物理端口时,需要发送Port-Status消息来通知OpenFlow控制器。

struct port_status_message {
    uint8_t reason; // OFPPR_ADD(0)、OFPPR_DELETE(1)、OFPPR_MODIFY(2)
    uint8_t pad[56];
    struct ofp_phy_port; 
}

Flow-Removed

当OpenFlow交换机设置的流表项超时时,会向控制器发送Flow-Removed消息。

struct flow_remove_message {
    struct ofp_match match;
    uint8_t cookie[64];
    uint16_t priority;
    uint8_t reason; // OFPRR_IDLE_TIMEOUT(0)、OFPRR_HARD_TIMEOUT(1)、OFPRR_DELETE(2)
    uint8_t pad;
    uint32_t duration_sec; // 有效时间(秒)
    uint32_t duration_nsec; // 纳秒
    uint16_t idle_timeout;
    uint8_t pad2;
    uint64_t packet_count; // 数据包数
    uint64_t byte_count; // 总字节数
}

大部分字段可以直接复制于Flow-Mod的信息。

Error

当在处理过程中出现错误的时候发送,控制器和交换机均可使用,type为OFPT_ERROR_MSG。

struct error_message {
    uint16_t type;
    uint16_t code;
    uint8_t data[??];
}

enum error_type {
    OFPET_HELLO_FAILED,
    OFPET_BAD_REQUEST,
    OFPET_BAD_ACTION,
    OFPET_FLOW_MOD_FAILED,
    OFPET_QUEUE_OP_FAILED
}

具体code参考OpenFlow说明书。

Barrier

用于双方对于事务的完成程度的通信,避免发生有顺序的事务因执行程度未达到而造成错误的情况。例如在发送了三条Flow-Mod信息,xid分别为1、2、3后,可以发送xid为4的Barrier请求,如果可以得到对方xid为4的Barrier响应,则表示前面的消息已经处理完毕。

Echo

用于测试两方的连接情况、通信延迟和通信带宽等。

LLDP

Link Layer Discovery Protocol

IEEE 802.1ab

许多的OpenFlow控制器利用LLDP来检测网络拓扑结构。一般来说,OpenFlow控制器会利用Packet-Out消息向OpenFlow交换机下达发送LLDP帧的命令,接下来利用接收到LLDP帧的OpenFlow交换机向控制器发送的Packet-In消息中得到拓扑消息,构建整个网络拓扑结构。

LLDP的机制

  • 每隔一段时间(标准中建议是30秒)向L2的组播地址发送LLDP帧,这个特性无视链路状态。
  • 发送源地址为发送设备的MAC地址。
  • 单向发送设备的识别号、端口识别号,这样接收方就可以得知发送设备和端口的信息。

LLDP使用三种全局性组播群地址

名称 数值 说明
Nearest Bridge 01-80-C2-00-00-0E 所有的桥和路由设备不转发
Nearest non-TPMR Bridge 01-80-C2-00-00-C3 跨越TPMR桥
Nearest Customer Bridge 01-80-C2-00-00-00 跨越TPMR和S-VLAN桥

一般来说,仅OpenFlow交换机构成的网络拓扑,会使用Nearest Bridge地址,而如果在中间存在有非OpenFlow的普通L2交换机则使用Nearest non-TPMR Bridge地址,借助WAN远程使用OpenFlow交换机则使用Nearest Customer Bridge地址。

-----------------------------------------------------
| 组播地址 | 设备的以太网地址 | 0x88cc(LLDP) | LLDPDU |
-----------------------------------------------------

OpenFlow 1.1 更新

头字段变更为匹配字段

在匹配字段中添加了MPLS标签、MPLS流量类别、元数据

多级流表

OpenFlow交换机可以设置多个流表,还可为一个数据包匹配多个流表项,但是在流表内还是只选择一个流表项

采用流水线处理的方式,新定义了“行动集”的概念,即将所有的行动统一添加到行动集中,但是执行顺序与计入顺序不相同,采用copy TTL inwards->pop->push->copy TTL outwards->decrement TTL->set->qos->group->output的方式,这里面每种类型仅能设置一个。

如果发生了Table-miss的情况,那么将根据OFPT_TABLE_MOD对流表的设置来决定,具体的方法有发送至控制器、前进到下一流表和丢弃。

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注