SDN实验---Ryu的应用开发

补充:

(一)Ubuntu下安装Notepadqq

背景:为什么安装Notepadqq

Notepad++ 不仅有语法高亮度显示,也有语法折叠功能,并且支持宏以及扩充基本功能的外挂模组。
但是可惜的是Notepad++只能在Windows平台下使用。 工作中必须使用Windows时,Notepad++是众多程序员最喜爱的文本编辑器,
在Ubuntu下是否能够使用到相同的软件呢?
Notepadqq就是这样一款与Notepad++非常接近的编辑器,拥有几乎相同的功能。

安装:

sudo add-apt-repository ppa:notepadqq-team/notepadqq
sudo apt-get update
sudo apt-get install notepadqq

安装(2):

snap install --classic notepadqq

补充:什么是snap软件包?

卸载:

sudo apt-get remove notepadqq
sudo add-apt-repository --remove ppa:notepadqq-team/notepadqq

(二)Ubuntu下安装 sublime

优点:

一流的Git集成
增量差异功能可跟踪正在编辑的文件的更改。
移动到GTK3,以及针对Linux的各种高DPI修复。
新的主题功能和块插入支持。
支持Unicode 11.0
对代码块(block caret)的支持
语法高亮增加对 Clojure, D, Go, Lua 语言的支持

安装:

1.由于最近下载速度太慢: http://pan.baidu.com/s/1kURLcZt 密码: acm6

2.进行安装:sudo dpkg -i sublime-text_build-3126_amd64.deb

3.安装package control以及Anaconda插件https://www.jianshu.com/p/36df65bc78f9

卸载编辑器

sudo apt remove --autoremove sublime-text

零:如何编程

一:Hub/集线器 (编程思路)《重点》

(一)明确问题

如何实现软件定义的集线器?

(二)设计解决方案

通过控制器来实现集线器算法(泛洪),然后知道数据平面实现集线器操作

(三)确定具体的技术方案

控制器选用Ryu,数据平面通过Mininet模拟

(四)部署实施

在控制器上编程开发集线器应用,创建实验网络为验证方案做准备

(五)验证方案

运行程序,调试程序,验证程序

(六)优化

验证成功后,优化程序

二:集线器原理---设计解决方案

一个数据包从port1进入,会被复制,泛洪转发到其他所有端口发出

三:部署实施---Ryu控制器API学习和使用(Hub集线器开发)

(一)代码实现

from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls


class Hub(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self,*args,**kwargs):
        super(Hub,self).__init__(*args,**kwargs)

    
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
    def switch_features_handler(self,ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        match = ofp_parser.OFPMatch()
        actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]

        self.add_flow(datapath,0,match,actions,"default flow entry")

    def add_flow(self,datapath,priority,match,actions,remind_content):
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]

        mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
                                    match=match,instructions=inst);
        print("install to datapath,"+remind_content)
        datapath.send_msg(mod);


    @set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
    def packet_in_handler(self,ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        in_port = msg.match['in_port']

        print("get packet in, install flow entry,and lookback parket to datapath")
        
        match = ofp_parser.OFPMatch();
        actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]

        self.add_flow(datapath,1,match,actions,"hub flow entry")

        out = ofp_parser.OFPPacketOut(datapath=datapath,buffer_id=msg.buffer_id,
                                            in_port=in_port,actions=actions)    

        datapath.send_msg(out);
注意:注释可能为你带来不少错误...尽可能写两个版本,一个不带注释,用于调试。一个写注释,用于学习,回顾

(二)启动控制器

ryu-manager hub.py --verbose  #进入目录,在hub.py文件目录下  --verbose显示调试信息

 

(二)启动Mininet进行连接测试

sudo mn --topo=linear,4 --controller=remote

Ryu控制器端响应:(注意:启动mininet后,再先关闭Ryu,重新进入,测试效果更好)

openvswitch交换机与Ryu控制器连接,控制器下发默认流表,提示信息install to datapath,default flow entry

(三)使用pingall命令,使得主机向交换机发送数据包---从而实现交换机上传数据包到控制器,实现流表获取

获取提示信息get packet in, install flow entry,and lookback parket to datapath

四: Hub代码讲解(注释版)

from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls


class Hub(app_manager.RyuApp):
    '''明确控制器所用OpenFlow版本'''
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self,*args,**kwargs):
        super(Hub,self).__init__(*args,**kwargs)

    
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
    def switch_features_handler(self,ev):
        '''
        在Ryu控制器上,我们需要写一个函数去处理openvswitch的连接
        CONFIG_DISPATCHER : Version negotiated and sent features-request message
        '''
        #对事件进行解析
        datapath = ev.msg.datapath    #从连接中获取数据平面的datapath数据结构
        ofproto = datapath.ofproto    #获取OpenFlow协议信息
        ofp_parser = datapath.ofproto_parser    #获取协议解析
        #解析完成

   '''在连接建立成功以后,需要控制器下发一个默认流表
           来指挥所有匹配不到交换机的数据,把他上传到控制器上
        '''

        #install the table-miss flow entry

        match = ofp_parser.OFPMatch()        #匹配域
        
        #OFPActionOutput将数据包发送出去,
        #第一个参数OFPP_CONTROLLER是接收端口,
        #第二个是数据包在交换机上缓存buffer_id,由于我们将数据包全部传送到控制器,所以不在交换机上缓存
        actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]

        self.add_flow(datapath,0,match,actions,"default flow entry")    #默认缺省流表项,设置优先级最低即可
'''
    数据平面    是由若干网元(Network Element)组成,每个网元包含一个或多个SDN数据路径(SDN Datapath)。
    SDN Datapath是逻辑上的网络设备,负责转发和处理数据无控制能力,
    一个SDN DataPath包含控制数据平面接口(Control Data Plane Interface,CDPI)、代理、转发引擎(Forwarding Engine)表和处理功能(Processing Function) 
    SDN数据面(转发面)的关键技术:对数据面进行抽象建模。
    '''
    def add_flow(self,datapath,priority,match,actions,remind_content):
        '''构建流表项 : add a flow entry, install it into datapath
        datapath:表示给哪一个逻辑设备下发流表
        priority:表示优先级
        match,actions:匹配域和动作
        '''

        #datapath属性        
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        #在OpenFlow1.3版本中定义了instruct指令集(交换机内部的一些操作)
        #construct a flow msg and send it
        inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]

        mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
                                    match=match,instructions=inst);
        print("install to datapath,"+remind_content)
        #发送出去
        datapath.send_msg(mod);

        
'''接收数据
        Ryu控制器通过装饰器去注册监听某些事件,去处理这些事件。
        从而实现从数据平面的消息上传到控制器,再从控制器平面到应用平面,应用程序去处理事件,再逐跳返回到openvswitch
    '''

    '''要处理这个事件,需要先去注册监听他
    EventOFPPacketIn: 是我们要监听的事件
    MAIN_DISPATCHER : 是什么状态下,去监听该事件---Switch-features message received and sent set-config message
    '''
    @set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
    def packet_in_handler(self,ev):
        '''Hub集线器类,所实现的功能:
        1.接收从OpenVSwitch发送过来的数据包
        2.将数据包泛洪到Hub中的其他端口中
        '''    

        #解析数据结构
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        in_port = msg.match['in_port']        #获取源端口

        print("get packet in, install flow entry,and lookback parket to datapath")
        
        match = ofp_parser.OFPMatch();        #因为我们是将所有转发,所以不用管匹配,填空表示全部匹配
        actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]

        #调用add_flow,将流表项发送    ,指导后续数据包转发    install flwo entry to avoid packet in next time
        self.add_flow(datapath,1,match,actions,"hub flow entry")    #等级稍微比默认流表项高级

        #注意:我们将流表项下发了,但是数据包我们这次接收的,并没有处理
        #就是再将控制器上的数据包,重新发送给datapath,让他按照流表项处理
        #buffer_id是这个数据包,存放在控制器中的缓冲区位置,是在事件中的buffer_id获取
        out = ofp_parser.OFPPacketOut(datapath=datapath,buffer_id=msg.buffer_id,
                                            in_port=in_port,actions=actions)    

        datapath.send_msg(out);

通信流程:《重点》

1.当开始一个Hub集线器时,会先与控制器进行连接,我们需要在Ryu中设置函数去处理连接,设置并下发默认流表---------函数switch_features_handler实现

2.当主机之间通信时,主机上传信息到OpenVSwitch交换机,而交换机无法匹配到流表项时,我们设置将数据全部上传给Ryu控制器,我们在控制器端实现Hub集线器的泛洪功能,即设置流表项(match-actions为所有匹配数据包的动作为ofproto.OFPP_FLOOD,并且将该流变下发给原来datapath,同时我们要将之前交换机发送过来的数据包重新发送给交换机(让其按照新的流表项进行处理)--------函数packet_in_handler实现

3.我们将公共函数add_flow,构建流表项并且下发流表提出

五:实现整体程序运行了解《重点》

(一)程序入口在哪?------app_manager.RyuApp

    """
    The base class for Ryu applications.

    RyuApp subclasses are instantiated after ryu-manager loaded
    all requested Ryu application modules.
    __init__ should call RyuApp.__init__ with the same arguments.
    It's illegal to send any events in __init__.

    The instance attribute 'name' is the name of the class used for
    message routing among Ryu applications.  (Cf. send_event)
    It's set to __class__.__name__ by RyuApp.__init__.
    It's discouraged for subclasses to override this.
    """

1.app_manager.RyuApp是所有Ryu Applications的基类,我们要实现一个控制器应用,必须继承该基类

2.我们自定义的子类(继承于RyuAPP的子类),将在ryu-manager命令加载中被实例化(它是在ryu管理器加载所有请求的ryu应用程序模块后实例化的)

即我们执行ryu-manager hub.py --verbose命令开启Ryu控制器时,并且处理了所有请求的ryu应用程序模块,之后Hub子类就被实例化了 

3.子类中的__init__方法需要调用父类的__init__方法,并且保持参数一致

    def __init__(self,*args,**kwargs):
        super(Hub,self).__init__(*args,**kwargs)

(二)设置OpenFlow协议---OFP_VERSIONS

    OFP_VERSIONS = None
    """
    A list of supported OpenFlow versions for this RyuApp.
    The default is all versions supported by the framework.

    Examples::

        OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION,
                        ofproto_v1_2.OFP_VERSION]

    If multiple Ryu applications are loaded in the system,
    the intersection of their OFP_VERSIONS is used.
    """

我们设置的协议类型是1.3版本OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION],其中协议在 from ryu.ofproto import ofproto_v1_3 中

  

扫描二维码关注公众号,回复: 7631612 查看本文章

(三)事件监听----装饰器实现set_ev_cls

1.from ryu.controller.handler import set_ev_cls

# should be named something like 'observe_event'
def set_ev_cls(ev_cls, dispatchers=None):
    """
    A decorator for Ryu application to declare an event handler.

    Decorated method will become an event handler.
    ev_cls is an event class whose instances this RyuApp wants to receive.
    dispatchers argument specifies one of the following negotiation phases
    (or a list of them) for which events should be generated for this handler.
    Note that, in case an event changes the phase, the phase before the change
    is used to check the interest.

    .. tabularcolumns:: |l|L|

    =========================================== ===============================
    Negotiation phase                           Description
    =========================================== ===============================
    ryu.controller.handler.HANDSHAKE_DISPATCHER Sending and waiting for hello
                                                message
    ryu.controller.handler.CONFIG_DISPATCHER    Version negotiated and sent
                                                features-request message
    ryu.controller.handler.MAIN_DISPATCHER      Switch-features message
                                                received and sent set-config
                                                message
    ryu.controller.handler.DEAD_DISPATCHER      Disconnect from the peer.  Or
                                                disconnecting due to some
                                                unrecoverable errors.
    =========================================== ===============================
    """
    def _set_ev_cls_dec(handler):
        if 'callers' not in dir(handler):
            handler.callers = {}
        for e in _listify(ev_cls):
            handler.callers[e] = _Caller(_listify(dispatchers), e.__module__)
        return handler
    return _set_ev_cls_dec

2.被set_ev_cls装饰的函数将成为一个事件处理器,参数ev_cls是一个事件类,他的实例是RyuAPP想要接收的(子类),dispatchers参数是事件的协商阶段

@set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)  

(1)self便是子类的实例化对象

(2)协商阶段

    =========================================== ===============================
    Negotiation phase                           Description
    =========================================== ===============================
    ryu.controller.handler.HANDSHAKE_DISPATCHER Sending and waiting for hello  
                                                message
    ryu.controller.handler.CONFIG_DISPATCHER    Version negotiated and sent
                                                features-request message
    ryu.controller.handler.MAIN_DISPATCHER      Switch-features message
                                                received and sent set-config
                                                message
    ryu.controller.handler.DEAD_DISPATCHER      Disconnect from the peer.  Or
                                                disconnecting due to some
                                                unrecoverable errors.
    =========================================== ===============================

发送并等待Hello消息

双方通过握手消息Hello建立安全连接

版本协商并发送功能请求消息

双方建立TLS隧道后,方法发送hello消息进行版本协商
如果协议版本协商成功,则连接建立。否则发送Error消息描述协商失败原因,并终止连接

交换机特征消息接收和发送设置配置消息

协商完成后,控制器和交换机之间发送Features消息,获取交换机参数
参数包括支持的buffer数目、流表数、Actions等
控制器发送SET_CONFIG消息向交换机发送配置参数
通过GET_CONFIG消息得到交换机修改后的配置信息
控制器与OpenFlow交换机之间,发送PACKET_OUT和PACKET_IN消息。通过PACKET_OUT中内置的LLDP包进行网络拓扑的探测
控制器通过FLOW_MOD向控制器下发流表操作 

断开与对等方的连接。或者由于一些不可恢复的错误而断开连接

猜你喜欢

转载自www.cnblogs.com/ssyfj/p/11731565.html
ryu
今日推荐