实验6:开源控制器实践——RYU

2021/10/18 23:16:20

本文主要是介绍实验6:开源控制器实践——RYU,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

实验6:开源控制器实践——RYU

一、实验目的

  1. 能够独立部署RYU控制器;
  2. 能够理解RYU控制器实现软件定义的集线器原理;
  3. 能够理解RYU控制器实现软件定义的交换机原理。

二、实验环境

  1. 下载虚拟机软件Oracle VisualBox或VMware;
  2. 在虚拟机中安装Ubuntu 20.04 Desktop amd64,并完整安装Mininet;

三、实验要求

(一)基本要求

1. 完成Ryu控制器的安装。

2. 搭建下图所示SDN拓扑,协议使用Open Flow 1.0,并连接Ryu控制器。

img

3. 通过Ryu的图形界面查看网络拓扑。

4. 阅读Ryu文档的The First Application一节,运行并使用 tcpdump 验证L2Switch,分析和POX的Hub模块有何不同。

(二)进阶要求

1. 阅读Ryu关于simple_switch.py和simple_switch_1x.py的实现,以simple_switch_13.py为例,完成其代码的注释工作,并回答下列问题:

a) 代码当中的mac_to_port的作用是什么?
b) simple_switch和simple_switch_13在dpid的输出上有何不同?
c) 相比simple_switch,simple_switch_13增加的switch_feature_handler实现了什么功能?
d) simple_switch_13是如何实现流规则下发的?
e) switch_features_handler和_packet_in_handler两个事件在发送流规则的优先级上有何不同?

simple_switch13源代码及注释

from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types

# 继承ryu.base.app_manager.RyuApp
# 基类ryu.base.app_manager.RyuAPP是所有开发APP必备继承的类,
# 可以理解成开发APP的环境,而且有了它都不用注册,非常方便

class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]  # 指定OpenFlow 1.3版本

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch13, self).__init__(*args, **kwargs)
        self.mac_to_port = {} 
    # 定义MAC地址列表,这里的mac_to_port表就是对应的交换机二层通信查询表 

# set_ev_cls指定事件类别得以接受事件消息和交换机状态作为参数
# set_ev_cls第一个参数表示事件发生时应该调用的函数,第二个参数告诉交换机只有在交换机握手完成之后,才可以被调用。
# ofp_event完成了事件的定义,从而我们可以在函数中注册handler,监听事件,并作出回应
# packet_in_handler方法用于处理packet_in事件。
# @set_ev_cls修饰符用于告知RYU,被修饰的函数应该被调用。


    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
    	# ev.msg 是用来存储对应事件的 OpenFlow 消息类别实体
    	# msg.datapath是用来存储OpenFlow交换机ryu.controller.controller.Datapath 类别所对应的实体
        datapath = ev.msg.datapath  
        ofproto = datapath.ofproto  # ofproto表示使用的OpenFlow版本所对应的ryu.ofproto.ofproto_v1_3
        parser = datapath.ofproto_parser  # 和ofproto一样,有对应版本ryu.ofproto.ofproto_v1_3_parser,解析协议才能使用
        
		
   @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
   def _packet_in_handler(self, ev):
       # If you hit this you might want to increase
       # the "miss_send_length" of your switch
       if ev.msg.msg_len < ev.msg.total_len:
           self.logger.debug("packet truncated: only %s of %s bytes",
                             ev.msg.msg_len, ev.msg.total_len)
        # 送往 Controller 的封包可以僅只傳送 header 部分( Ethernet header ),剩下的則存在緩衝區間中以增加效率。 
        #但目前( 2014年1月 )Open vSwitch 存在臭蟲的關係,會將所有的封包都傳送,並不會只傳送 header。
       #这条logger.debug日志是为了提示送往controller的packet_in包是截取header 部分,这里我是这么理解的,有错误请大家告知
       # 为了接收处理未知目的地的数据包,需要执行Packet-In 事件管理
       
       msg = ev.msg  # 每一个事件类ev中都有msg成员,用于携带触发事件的数据包
       datapath = msg.datapath  # 已经格式化的msg其实就是一个packet_in报文,msg.datapath直接可以获得packet_in报文的datapath结构
       # datapath用于描述一个交换网桥,也是和控制器通信的实体单元。
       # datapath.send_msg()函数用于发送数据到指定datapath。
       # 通过datapath.id可获得dpid数据。
       ofproto = datapath.ofproto  # datapath.ofproto对象是一个OpenFlow协议数据结构的对象,成员包含OpenFlow协议的数据结构,如动作类型OFPP_FLOOD
       parser = datapath.ofproto_parser  # datapath.ofp_parser则是一个按照OpenFlow解析的数据结构。

   	# 更新Mac地址表
       in_port = msg.match['in_port']

       pkt = packet.Packet(msg.data)
       eth = pkt.get_protocols(ethernet.ethernet)[0] 
       # pkt.get_protocols 传入的是 协议类 参数
       # 得到协议的ethernet.ethernet类实例的协议列表,看源码知道了lib.packet.packet/ethernet

       if eth.ethertype == ether_types.ETH_TYPE_LLDP:
           # ignore lldp packet
           return
       dst = eth.dst
       src = eth.src

       dpid = datapath.id
       self.mac_to_port.setdefault(dpid, {})
       # 指定交换机dpid,默认mac_to_port表为空

       self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
       # 日志记录信息

       # learn a mac address to avoid FLOOD next time.
       self.mac_to_port[dpid][src] = in_port

   	# 判断转发的数据包的连接端口
   	# 目的 MAC 位址若存在于 MAC 地址表,则判断该连接端口号码为输出。
   	# 反之若不存在于 MAC 地址表则 OUTPUT action 类别的实体并生成 flooding( OFPP_FLOOD )给目的连接端口使用。
       if dst in self.mac_to_port[dpid]:
           out_port = self.mac_to_port[dpid][dst]
        # 有目的地址寻找端口号,否则泛洪
       else:
           out_port = ofproto.OFPP_FLOOD
   	
   		# 准备泛洪的packet_out指令给后面的if判断语句最后的else
       actions = [parser.OFPActionOutput(out_port)]

       # install a flow to avoid packet_in next time
       if out_port != ofproto.OFPP_FLOOD:
           match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)
           # verify if we have a valid buffer_id, if yes avoid to send both
           # flow_mod & packet_out
           if msg.buffer_id != ofproto.OFP_NO_BUFFER:
               self.add_flow(datapath, 1, match, actions, msg.buffer_id)
               return # 不用泛洪退出函数
           else:
               self.add_flow(datapath, 1, match, actions)

   	# 在 MAC 地址表中找寻目的 MAC 地址,若是有找到则发送 Packet-Out 讯息,并且转送数据包。
       data = None
       if msg.buffer_id == ofproto.OFP_NO_BUFFER:
       # 表示要泛洪发送Packet-Out,把本身的二进制数据取出来
           data = msg.data
   	#需要Flooding 的actions和msg。buffer_id已经准备好了
       out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                 in_port=in_port, actions=actions, data=data)
       datapath.send_msg(out)


a) 代码当中的mac_to_port的作用是什么?
答:对应的交换机二层通信查询表 。

b) simple_switch和simple_switch_13在dpid的输出上有何不同?
答:simple_switch_13对dpid填充为16位数字。

c) 相比simple_switch,simple_switch_13增加的switch_feature_handler实现了什么功能?
答:安装无目标的流表条目

d) simple_switch_13是如何实现流规则下发的?
答:接收到包后学习,存在mac地址就进行转发,不存在就洪泛转发。

e) switch_features_handler和packet_in_handler两个事件在发送流规则的优先级上有何不同?
答:switch_features_handler发送的priority=0,packet_in_handler发送的流表的priority设置为1,switch_features_handler优先级更高。

(二)进阶要求

​ 个人感想:前面的基础任务我想还是ok的吧,安装那么多东西,也不差一个ryu。能碰到的问题也相差无几。但安装的时候好像把python升级了?删除了一下旧链接,重新再建立新连接也就搞定了,后面使用 tcpdump 验证L2Switch的过程跟上次的实验步骤都差不多。

这次的进阶,查资料就完事了,勉勉强强看懂一些功能,但大部分的代码就是我虽然看的不是很懂,但我大受震撼。感觉其中暗含的技术真是让人摸不着头,可能以后再学深入一些可能就会再明白些吧。



这篇关于实验6:开源控制器实践——RYU的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程