一:ofproto函数库
ofproto函数库是用来产生及解析OpenFlow信息的函式库。
1:相关模块
每个OpenFlow(版本X.Y)都有相对应的常数模组(ofproto_vX_Y)和解析模组(ofproto_vX_Y_parser)每个OpenFlow版本的实作基本上是独立的。
OpenFlow 版本 | 常数模组 | 解析模组 |
1.0.x | ryu.ofproto.ofproto_v1_0 | ryu.ofproto.ofproto_v1_0_parser |
1.2.x | ryu.ofproto.ofproto_v1_2 | ryu.ofproto.ofproto_v1_2_parser |
1.3.x | ryu.ofproto.ofproto_v1_3 | ryu.ofproto.ofproto_v1_3_parser |
1.4.x | ryu.ofproto.ofproto_v1_4 | ryu.ofproto.ofproto_v1_4_parser |
常数模块是用来做为通信协定中的常数设定使用,下面列出几个例子。
常数 | 说明 |
OFP_VERSION | 通信协定版本编号 |
OFPP_xxxx | 连接端口号 |
OFPCML_NO_BUFFER | 无缓冲区间,直接对全体发送信息 |
OFP_NO_BUFFER | 无效的缓冲编号 |
解析模块提供各个OpenFlow信息的对应类别,下面列出几个例子。为了更好的说明类别的实体,接下来的描述将用“信息物件”取代“信息类别”。
类别(class) | 说明 |
OFPHello | OFPT_HELLO 信息 |
OFPPacketOut | OFPT_PACKET_OUT 信息 |
OFPFlowMod | OFPT_FLOW_MOD 信息 |
解析模块对应了OpenFlow信息的Payload结构中所需的定义,例如下面的例子。为了更好的说明类别的实体,今后将用结构物件(structure object)取代结构类别(structure class)。
类别(class) | 结构 |
OFPMatch | ofp_match |
OFPInstructionGotoTable | ofp_instruction_goto_table |
OFPActionOutput | ofp_action_output |
2:基本使用方法
1.ProtocolDesc类别
这是为了OpenFlow协定所必需存在的类别。使用信息类别的__init__作为datapath的参数,指定该类别的物件。
2.网络位址(Network Address)
Ryu ofproto函式库的API使用最基本的文字表现网络位址,请看下面的例子。备注:但是OpenFlow 1.0和这样的标示方法不同。(2014年2月更新)
位址(Address)种类 | Python表示 |
MAC 位址 | `00:03:47:8c:a1:b3' |
IPv4 位址 | `192.0.2.1' |
IPv6 位址 | `2001:db8::2' |
3.信息物件(Message Object)的产生
每个信息类别(message class),结构类别(structure class)都需要适当的参数以用来产生。参数的名称跟OpenFlow协定所定义的字段名称基本上是一致的。在有冲突的情况下会在最后加入「_」,例如:「type_」就是。
from ryu. ofproto import ofproto_protocol
from ryu. ofproto import ofproto_v1_3
dp = ofproto_protocol.ProtocolDesc(version = ofproto_v1_3.OFP_VERSION)
ofp = dp.ofproto
ofpp = dp.ofproto_parser
actions = [parser.OFPActionOutput(port=ofp.OFPP_CONTROLLER,max_len=ofp,OFPCML_NO_BUFFER)]
inst = [parser.OFPInstructionActions(type_=ofp.OFPIT_APPLY_ACTIONS,actions = actions)]
fm = ofpp.OFPFlowMod (datapath=dp,priority=0,match=ofpp.OFPMatch (in_port =1, eth_src ='00:50:56:c0:00:08'),instructions =inst)
备注:常数模块、解析模块最好是在import的时候就直接标明。如此一来在OpenFlow版本变更的时候,可以将修正的程度将到最低。另外尽量使用ProtocolDesc物件的ofproto和ofproto_parser属性。
4.信息物件(Message Object)的解析
信息物件(message object)的内容是可以查询的。例如OFPPacketIn物件中pid的match field用查询pin.match即可得到相关的信息。OFPMatch物件中TLV的各部分可以使用下列的名称取得相关的数据。
print pin.match ['in_port ']
5.JSON
信息物件(message object)转换成为json.dump的功能是存在的,反之亦然。备注:但是目前OpenFlow 1.0相关的实作并不完全。(2014年2月更新)
import jsonprint
json.dumps(msg.to_jsondict())
6.信息的解析
该功能是为了把信息的原始数据转换成信息物件。对于从交换器收到的信息,框架(Framwork)会自动地进行处理,Ryu应用程序(Application)是不需要特别处理的。具体来说如下:
1.ryu.ofproto.ofproto_parser.header用来处理版本相依的解析
2.上面处理过的结果可以用ryu.ofproto.ofproto_parser.msg功能来解析剩余的部分
7.信息的产生
将信息物件转换并产生对应的信息Byte。同样的,来自交换器的信息将由框架自动处理,Ryu应用程序无需额外的动作。具体来说如下:
1.呼叫信息物件的串行化方法
2.从信息物件中将buf的属性读取出来有些字段,例如“len”即使不指定,在串行化的同时也会自动被计算出来。
二:封包函数库
OpenFlow中Packet-In和Packet-Out信息是用来产生封包,可以在当中的字段放入Byte数据并转换为原始封包的方法。Ryu提供了相当容易使用的封包产生函式库给应用程序使用。
1.基本使用方法
1.协定标头类别(Protocol Header Class)
Ryu封包函式库提供许多协定对应的类别,用来解析或包装封包。下面列出Ryu目前所支持的协定。若需要了解每个协定的细节请参照Welcome to RYU the Network Operating System(NOS) — Ryu 4.34 documentation
后续补充
arp
bgp
bpdu
dhcp
ethernet
icmp
icmpv6
每一个协定类别的__init__参数基本上跟RFC所提到的名称是一致的。同样的每一个协定实体命名也相同。但是当__init__名称与Python内定的关键字发生冲突时,会在名称的尾端加上底线「_」。有些__init__的参数由于有内定的预设值,因此可以忽略。下面的例子中,原本需要被加入的参数version = 4或其他值就可以被忽略。
2.网络位址(Network Address)
位址(Address)种类 | Python表示 |
MAC 位址 | `00:03:47:8c:a1:b3' |
IPv4 位址 | `192.0.2.1' |
IPv6 位址 | `2001:db8::2' |
3.封包的解析(Parse)
封包的Byte String可以产生相对应的Python物件。具体的事例如下:
1. ryu.lib.packet.packet.Packet类别的物件产生(指定要解析的byte string给data作为参数)
2.使用先前产生的物件中get_protocol方法,取得协定中相关属性的物件。
4.封包的产生(串行化,Serialize)
把Python物件转换成为相对封包的byte string。具体说明如下:
1.产生ryu.lib.packet.packet.Packet类别的物件
2.产生相对应的协定物件(ethernet,ipv4,…)
3.在1.所产生的物件中,使用add_protocol方法将2.所产生的物件依序加入
4.呼叫1.所产生物件中的serialize方法将物件转换成byte string Checksum和payload的长度不需要特别设定,在串行化的同时会被自动计算出来。详细的各类别细节请参考相关资讯。
2.应用程序示例
接下来的例子是使用上述的方法,达成一个可以针对ping做出回应的应用程序。接受Packet-In所收到的ARP REQUEST和ICMP ECHO REQUEST后藉由Packet-Out发送响应。IP位址等__init__的参数都是使用固定代码(hard-code)的方式。
备注:OpenFlow 1.2版本之后,因为match而带来的Packet-In信息中,将会带有已经被解析过的资讯。但是这些信息的多寡以及详细程度要看每一台交换器的实际处理决定。例如Open vSwitch仅放入最低需求的信息,在大多数的情况下Controller需要针对数据再进行处理。反之LINC则尽可能放入信息。