RYU,Chapter 1. 交换机(Switching Hub)
Created at 2018-06-04 Updated at 2018-06-06 Category Study
为什么使用RYU?
其实理由很简单:
- 我喜欢用python
- RYU 用着不卡(辣鸡虚拟机真跑不动ODL)
然后就尝试的去看了以下RYU的源码,发现真的很简洁,很有意思!瞬间就爱上了。
前期准备
RYU的安装
在拥有一系列组件的前提下:pip install ryu
接下来会面临一些问题就是,找不到RYU的目录在何方?
输入ryu-manager ***
在报错的后面就有ryu的目录地址
这个方案来自考拉小无
,RYU领路人
RYU各个文件的内容:
这些目录的主要内容在SDNLAB网站上有记录来自李呈,你也可以在RYU的官方文档上学习到。
而这次博客的内容主要是记录我在学习RYUBOOK上的一些感想。如果你想获得RYUBOOK这本书,请点击
交换机(Switching Hub)
关于交换机交换数据包的原理:
- 学习源主机的入端口,MAC地址
- 查找MAC表,若不存在目的主机的MAC地址,则按照生成树协议执行转发所有端口;若存在,则按照端口执行转发
这一块相信学过传统网络知识的同学都基本清楚。
关于OpenFlow交换机的最简单的功能:
- 修改收到的数据包及传送到对应端口
- Packet-in
- Packet-out
借这些功能,RYU控制器大致通过以下内容实现最简单的交换机转发功能:
- 利用Packin-in学习端口号及MAC地址
- 控制器解析Packet-in,得到源主机的接入端口及MAC地址,记录在表
- 利用Packin-out下发流表到交换机实现转发功能
- 控制器解析Packet-in,得到目的主机的MAC地址,查询MAC表,若找到对应项,则使用Packet-out传送到先前对应的端口。否则,利用packet-out来达到flooding功能。
注:这边flooding采用的是OFFP-FLOOD(沿最小生成树发送数据包)
此时,在ovs交换机就有来自控制器所学习好了的流表项目,能够告诉交换机接下去的动作。例如优先级最低的流表是FLOOD动作,优先级高一丢丢的是正常的OUTPUT动作
RYU的源码实现:
先贴上整个源码
from ryu.base import app_manager |
作为控制器的应用程序,需要继承app_manager.RyuApp这个类。该类位于ryu.base.app。在前提部分的链接可以详细了解
- 首先OFP_VERSIONS指定了OpenFlow的协议版本号
- init构造函数似乎没有什么作用
- mac_to_port是MAC表,目前等于一个空dict
|
set_ev_cls是一个事件的装饰器。位于ryu.controller.handler。
在RYU中,事件管理(Event handler),用来处理OpenFlow信息对应发生的事件。如该控制器接收到SwitchFeatures(由ofp_event.EventOFPSwitchFeatures指明)即Features reply时,就会执行下列函数的内容。执行的状态前提是CONFIG_DISPATCHER(接收SwitchFeatures讯息)。
状态有四种,位于ryu.controller.handler中:
- HANDSHAKE_DISPATCHER 交换HELLO信息
- CONFIG_DISPATCHER 接收SwitchFeatures讯息
- MAIN_DISPATCHER 一般状态,指交换机连接成功了
- DEAD_DISPATCHER 连接中断
满足上述条件后,执行switch_features_handler函数。
其中:
- ev.msg 为触发讯息的数据报文
- msg.datapath 则为该报文下的交换机实体
- datapath.ofproto 是一个OpenFlow协议数据结构的对象,成员包含OpenFlow协议的数据结构,如虚拟端口OFPP_FLOOD,OFPP_CONTROLLER。
- datapath.ofp_parser 是一个按照OpenFlow解析的数据结构,即动作
- parser.OFPMatch() 为匹配项,此时为空,完全匹配
- actions 为一个列表,存放动作,动作来自datapath.ofp_parser中解析的数据结构,此例中为OFPActionOutput,其带有两个参数,ofproto.OFPP_CONTROLLER表示发送报文到控制器,ofproto.OFPCML_NO_BUFFER表示表示不应该应用缓冲,并且整个数据包将被发送到控制器。
这个函数完成的内容就是将所有的数据包传给控制器,其中的数据包为优先级为0的流表项匹配到的数据包。
def add_flow(self, datapath, priority, match, actions): |
- OFPInstructionActions 该指令用于写入/应用/清除动作。后文的第一个参数为应用
- OFPFlowMod 控制器发送此消息来修改流表。 参数instructions在源码中解释为list of
OFPInstruction*
instance,*为通配符,此例中为OFPInstructionActions- 其有诸多参数,多为OpenFlow协议的数据结构,具体不再解释,源码解释见下图:
- 此例中,command为默认参数,OFPFC_ADD
- 其有诸多参数,多为OpenFlow协议的数据结构,具体不再解释,源码解释见下图:
- send_msg 排队一个OpenFlow消息发送到相应的交换机。 如果msg.xid为None,则在排队之前会自动在消息上调用set_xid。
|
根据上面的信息,我们可以很容易的得到, _packet_in_handler这个函数,在满足状态为MAIN_DISPATCHER,接收到的报文为EventOFPPacketIn(即Packet-in报文)的时候被调用,其中:
- datapath.id 只用于MAIN_DISPATCHER。交换机标识符
- setdefault 如果键不存在于字典中,将会添加键并将值设为默认值
- pkt = packet.Packet(msg.data) 获取报文数据
- get_protocol 返回首次找到的与指定协议匹配的协议
- ethernet.ethernet 以太网头编码器/解码器类。Ethernet header encoder/decoder class.
- dst,src为获取到的MAC
- msg.match[‘in_port’] 返回匹配到的‘in_port’
- mac_to_port[dpid][src] = in_port 记录MAC
|
相信经过了上面的阅读,这部分的大部分内容都是能够看懂了。其中:
- 如果dst在mac_to_port[dpid],就可以知道转发的out_port端口,否则out_port = ofproto.OFPP_FLOOD
- OFPMatch 流匹配结构Flow Match Structure, 具体可以阅读RYU源码,位于ryu.ofproto.ofproto_v1_3_parser.py
- add_flow(datapath, 1, match, actions) 这条语句下发较高优先级(大于刚才的0)的流表,这样新的数据包过来后会先匹配该流表,实现已知端口的转发功能
- parser.OFPPacketOut Packet-out报文
RYU程序的执行:
完成了一个ryu程序代码是不是很开心,接下来就去实现它吧!
在Linux终端下运行sudo mn --topo single,3 --mac --switch ovsk --controller remote -x
,其中:
- single ,3 为创建一个三个主机连接一台交换机的拓扑
- switch 采用ovs交换机
- 控制器当然是远端(remote)的RYU
- -x 开启各个主机、交换机、控制器的终端
如图所示:
根据书本的要求,设置OpenFLow协议为1.3
在s1交换机终端执行:
ovs-vsctl set Bridge s1 protocols=OpenFlow13
我们先查看s1的流表,发现其为空:
此时我们所有的前期准备已经都完成了,接下来就是执行控制器应用程序了。我们先到我们写好的控制器程序目录,这里我用一个first.py程序
输入ryu-manager first.py
显示界面如下:
控制器应用程序开启后,与交换机建立了连接,Features请求与响应。根据所写的程序,我们会有一个流表添加到OVS交换机上,如图:
这个流表作用就是把未知目的地数据包packet-in到控制器。让控制器进行处理。
接下来我们在mininet中执行pingall
操作,同时监控h1端口的数据包,为了方便,我们仅仅使用tupdump。
在h1终端输入tcpdump -en -i h1-eth0
开启监控端口功能。在此我们只观察 h1 与 h2。
我们可以看到图中的中部, h1 arp h2, h2 request h1 。紧接着,h1 ping h2,h2 request h1 。实现了通讯。右边的是控制器的日志输出,我在程序中加了个计数的功能,每次收到一个packet-in 技术及就加1。
接着,我们查看s1 的流表。
h1、h2、h3 共有三个端口有六个流表,分别指定了各自的数据包如何发送。很高兴程序没有出现BUG!
至此,本章节内容结束。
总结:
学习RYU有一周了,但是其实看的内容并不多,每天都是有一件一件一件事情被解决,但是就是轮不到RYU。很亢奋用一个下午半个晚上的时间重新阅读第一章的内容。并写下了这篇博客。虽然有些概念随着时间还是会一点一点忘记了,希望通过这篇博客能够尽快找到解决的地方。今天也算是完成了一件很重要的事情了!
希望在考试月再接再厉!不仅仅为了自己。
还有这个模板下的代码风格各种BUG,找个时间解决它
……三分钟解决了,把自带的代码高亮置flase。 根目录的_config,yml 中highlight:
enable: false