Application development of SDN experiment --- Ryu

supplement:

Installation Notepadqq under (a) the Ubuntu

Background: Why install Notepadqq

Notepad ++ is not only syntax highlighting, syntax also folded, and support for macros and plug-in expansion modules basic functions. 
But unfortunately Notepad ++ can only be used under Windows platform. Work must use Windows, Notepad ++ is one of many programmers favorite text editor,
ability to use the same software to it under Ubuntu?
Notepadqq is such a very close and Notepad ++ editor, with almost the same functionality.

installation:

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

Installation (2):

snap install --classic notepadqq

Added: What is snap package?

Uninstall:

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

(B) mounting the Ubuntu sublime

advantage:

Class Git integration
Incremental differences in function tracks changes to the file being edited.
Move to GTK3, as well as a variety of high DPI fix for Linux.
New themes and Block insertion support.
Support Unicode 11.0
Support for code block (block caret) of
Syntax highlighting increased support for Clojure, D, Go, Lua language

installation:

1. Due to the recent download speed is too slowhttp://pan.baidu.com/s/1kURLcZt Password: acm6

2. Installation: sudo dpkg -i sublime-text_build-3126_amd64.deb

3. Install the package control and Anaconda plug https://www.jianshu.com/p/36df65bc78f9

Uninstall Editor

sudo apt remove --autoremove sublime-text

Zero: How Programming

 

A: Hub / Hub (programming ideas) "key"

(A) clear problem

How to achieve hub software-defined?

(B) design solutions

Hub implemented algorithm (flooding), by the controller, and data plane implemented hub operation know

(C) determining the specific technical solution

Controller selects Ryu, analog data plane through Mininet

(D) the implementation of the deployment

On the controller programming application development hubs, created to prepare for the test network authentication scheme

(E) validation program

Run the program, commissioning procedures, verification procedures

(F) optimization

After successful authentication, the optimizer

II: Hubs principle --- Design Solutions

A data packet from port1 to enter, it will be copied, flooding forwarded to all other ports issue

Three: deployment of the implementation --- Ryu controller API to learn and use (Hub Hub Development)

(A) code for

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);
Note: Comments may bring as many mistakes as you ... write two versions, a non-annotated, for debugging. Write a comment for learning, review

(B) start controller

Manager hub.py---verbose [ryu]  # to enter the directory, the file directory under hub.py   --verbose display debugging information

 

(B) start Mininet connection test

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

Ryu end controller response :( Note: After starting mininet, then turn off Ryu, re-enter the test better)

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 中

  

(三)事件监听----装饰器实现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向控制器下发流表操作 

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

 

Guess you like

Origin www.cnblogs.com/ssyfj/p/11731565.html