RyuBook1.0案例一:Switching Hub项目源码分析
开发目标
实现一个带MAC地址学习功能的二层交换机
Openflow交换机与Openflow控制器安全通道建立步骤
- switch and controller建立未加密TCP连接或者加密的TLS连接
- 确定连接通道的Openflow版本
- 握手
- 其他操作
建立连接通道后,二者发生Hello包,进行协商Openflow版本号
完成交换Hello消息之后建立安全通道,执行握手。Controller发生Features请求,并处理Features响应
接收到Features响应,控制器可以向交换机发送SET_CONFIG
或者GET_CONFIG
请求消息,进行设置交换机默认配置或者查询交换机配置。
之后,可以进行OpenFlow的其他操作
Flow-Mod消息
Flow-Mod(Modify Flow Entry Message)由控制器向交换机下发的设置流表项的信息
其中 ofp_match结构体为数据包匹配部分。
程序分析
设置想要向交换机协商的OpenFlow版本号
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
下发Table-miss流表项
设置完成该项参数配置,控制器自动执行第一步操作,即交换Hello包,协商版本号。协商完成之后,自动执行交换Features包,进行握手。
握手完成后,使用set_ev_cls函数处理Features响应包
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
第二项参数详情如下:
Defination | Explanation |
---|---|
HANDSHAKE_DISPATCHER | 交换HELLO消息 |
CONFIG_DISPATCHER | 等待接收SwitchFeatures消息 |
MAIN_DISPATCHER | 正常状态 |
DEAD_DISPATCHER | 连接断开 |
定义处理函数,并解析返回包的字段
def switch_features_handler(self, ev): datapath = ev.msg.data ofproto = datapath.ofproto parser = datapath.ofproto_parser
安装table-miss entry
match = parser.OFPMatch()
table-miss:
OpenFlow1.3版本为处理table miss事件专门引入的条目。并规定每一个flow table必须要支持table-miss flow entry去处理table miss情况。table-miss flow entry具备最低的优先级(0);必须至少能够支持使用CONTROLLER保留端口发送包,使用Clear-Actions指令丢包;table-miss flow entry和其他flow entry具有相同的特性:默认不存在,控制器可以随时添加或丢弃该条目,也可以到期;如果使用CONTROLLER保留端口发生数据包,Packet-In发送原因必须标明table-miss。
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
OFPActionOutput() :使用一个packet_out 消息去指定你想从交换机的哪个端口发送出数据包。在该应用中,按照标准指定通过CONTROLLER保留端口发生,所以选择了OFPP_CONTROLLER端口。第二个参数OFPCML_NO_BUFFER,指明:消息中必须包含完整的包,而不会被缓冲。
指定完成actions,使用类的add_flow向控制器添加流表项
self.add_flow(self, datapath, 0, match, actions)
接下来分析add_flow的具体实现过程:
构建OpenFlow流表消息
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst)
OpenFlow目前主流版本为Openflow1.0,1.1,1.3。相比1.0版本,1.3版本流表项结构变化很大,在这里我们用到的Instruction可以说是1.0版本中Actions的拓展。Instruction主要负责将流表转发到其他Table,流水线,或者进行其他转发操作。
- OFPIT_APPLY_ACTIONS: 立即应用actions操作到交换机
函数OFPFlowMod()负责构建Flow-Mod消息
使用send()函数发送flow-mod消息
datapath.send(mod)
以上步骤完成下发配置table-miss流表项
MAC地址学习功能实现
MAC地址学习功能,主要要处理接收到的Packet-In数据包,所以重写set_cls_ev函数
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
- ofp_event.EventOFPPacketIn: 指处理PacketIn消息
- MAIN_DISPATCHER: ???
解析数据包
def _package_in_handler(self, ev): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser
获取datapath.id
dpid = datapath.id
datapath是交换机的唯一标识,即dpid
添加dpid: {}到mac地址、port字典中
self.mac_to_port.setdefault(dpid, {})
从datapath中解析dst,src
pkt = packet.Packet(msg.data) eth_pkt = pkt.get_protocol(ethernet.ethernet) dst = eth_pkt.dst src = eth_pkt.src
从datapath中匹配出in_port
in_port = msg.match['in_port']
存储in_port和mac
self.mac_to_port[dpid][src] = in_port
检查,如果已经存储过port和mac,如果存在,则配置out_port为指定端口;如果不存在,则使用OFPP_FLOOD端口,向全部端口进行泛洪。
if dst in self.mac_to_port[dpid]: out_port = self.mac_to_port[dpid][dst] else: out_port = ofproto.OFPP_FLOOD
构建Actions
actions = [parser.OFPActionOutput(out_port)]
如果out_port非Flood端口,则下发流表到交换机
if out_port != ofproto.OFPP_FLOOD: match = parser.OFPMatch(in_port=in_port, eth_dst=dst) self.add_flow(datapath, 1, match, actions)
构建Packet_Out消息,并发送到交换机
out = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=in_port, actions=actions, data=msg.data) datapath.send_msg(out)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
单例模式实现
1. 单线程可用 public class Singleton { private static Singleton singleton; private Singleton() { } public static Singleton getInstance() { if (null == singleton) { singleton = new Singleton(); } return singleton; } } 2. 使用final常量 public class Singleton { private static final Singleton singleton = new Singleton(); private Singleton() { } public static Singleton getInstance() { return singleton; } } 3. 加锁构造 public class Singleton { private static Singleton singleton; private static final Lock LOCK = ne...
- 下一篇
Web Worker 使用教程
一、概述 JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。 Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。 Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。 Web Worker 有以下几个使用注意点。 (1)同源限制 分配给 Worker 线程运行的脚本文件,必须与主线程...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2全家桶,快速入门学习开发网站教程
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2配置默认Tomcat设置,开启更多高级功能