zoukankan      html  css  js  c++  java
  • RyuBook1.0案例二:Traffic Monitor项目源码分析

    转载:https://www.cnblogs.com/NinWoo/p/9398351.html

    Traffic Monitor源码分析
    从simple_switch_13.SimpleSwitch13控制器继承并开发
    
    class SimpleMonitor13(simple_switch_13.SimpleSwitch13):
    增添datapaths列表,存储交换机id
    
    def __init__(self, *args, **kwargs):
        super(SimpleMonitor13, self).__init__(*args, **kwargs)
        self.datapaths = {}
    引入hub.spawn()函数启动一个新线程,输入为一个新的方法_monitor。
    
    创建一个EventOFPStateChange监听事件,监听MAIN_DISPATCHER,DEAD_DISPATCHER两种情况。
    
    @set_ev_cls(ofp_event.EventOFPStateChange,
                    [MAIN_DISPATCHER, DEAD_DISPATCHER])
    监听如果为MAIN_DISPATCHER,并且datapath.id不在datapath列表中,则证明是新加入的交换机
    
    if ev.state == MAIN_DISPATCHER:
          if datapath.id not in self.datapaths:
               self.logger.debug('register datapath: %016x', datapath.id)
               self.datapaths[datapath.id] = datapath
    如果为DEAD_DISPATCHER,并且datapath.id在datapath列表中,则证明是掉线的交换机
    
     elif ev.state == DEAD_DISPATCHER:
            if datapath.id in self.datapaths:
                self.logger.debug('unregister datapath: %016x', datapath.id)
                del self.datapaths[datapath.id]
    _monitor方法,循环不断向datapath列表中的交换机发送Flow状态请求,和Port状态请求
    
    def _monitor(self):
        while True:
            for dp in self.datapaths.values():
                self._request_stats(dp)
            hub.sleep(10)
    
    def _request_stats(self, datapath):
          self.logger.debug('send stats request: %016x', datapath.id)
          ofproto = datapath.ofproto
          parser = datapath.ofproto_parser
    
          req = parser.OFPFlowStatsRequest(datapath)
          datapath.send_msg(req)
    
          req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
          datapath.send_msg(req)
    刚刚发送了请求,现在监听其回复
    
    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    ...
    
    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    ...
    处理一个事件的标准模板
    首先,我们来看一个标准的控制器处理事件的模板
    
    @set_ev_cls(ofp_event.Event, DISPATCHER(s))
    def your_function(self, ev):
    ...
    简单说,@set_ev_cls(ofp_event.Event, DISPATCHER(s))的含义就是,当接收到DISPATCHER(s)情况的Event事件进行your_function处理。
    
    DISPATCHER(s)可以为单独一个,也可以为由多个DISPATCHER组成的列表,DISPATCHER描述的情况包括:
    
    Defination              Explanation
    HANDSHAKE_DISPATCHER    交换HELLO消息
    CONFIG_DISPATCHER       等待接收SwitchFeatures消息
    MAIN_DISPATCHER         正常状态
    DEAD_DISPATCHER         连接断开
    其中your_function是由你自己定义的函数处理过程,命名可以任意指定;ofp_event.Event是由ofp_event.py提供的一系列事件,在学习了几个Ryu的程序之后,深感,其核心就在于对这些事件的理解。所以,接下来,在分析学习官方案例的同时,也会整合Ryu源码与OpenFlow1.3.3协议的内容,对这些事件进行深入的理解与分析。
    
    ofp_event
    ofp_event类位于ryu/controller/ofp_event.py,主要定义了OpenFlow中的各种事件,配合set_cls_ev可以对指定事件进行处理。
    
    ofp_event.EventOFPSwitchFeatures
    ofp_event.EventOFPPacketIn
    ofp_event.EventOFPStateChange
    在源码中,对EventOFPStateChange这样进行介绍:
    
        An event class for negotiation phase change notification.
    
        An instance of this class is sent to observer after changing
        the negotiation phase.
        An instance has at least the following attributes.
    
        ========= =================================================================
        Attribute Description
        ========= =================================================================
        datapath  ryu.controller.controller.Datapath instance of the switch
        ========= =================================================================
    意思说,该class是处理协商阶段变更通知的事件,在协商更改后发生此消息给观察者。
    
    当我们使用一下的命令,我们就成为了观察者,发生此类消息时,便可以进行接收和处理
    
    @set_ev_cls(ofp_event.EventOFPStateChange,
                    [MAIN_DISPATCHER, DEAD_DISPATCHER])
    详细案例见Traffic Monitor
    
    在协商阶段,MAIN_DISPATCHER意味着有新的交换机接入,DEAD_DISPATCHER意味着有交换机脱离连接。
    
    总结:
    
    发起事件          处理事件
    交换机状态变化    EventOFPStateChange
    ofp_event.EventOFPFlowStatsReply
    在源码中,对EventOFPFlowStatsReply这样介绍:
    
        Individual flow statistics reply message
    
        The switch responds with this message to an individual flow statistics
        request.
    意思说,该事件用于处理个体流量统计回复消息,即统计某一交换机上的流量信息。而流量统计信息存储在body(ev.msg.body)结构体中。具体包括:
    
    table_id
    duration_sec
    duration_nsec
    priority
    idle_timeout
    hard_timeout
    flags
    cookie
    packet_count
    byte_count
    match
    instructions
    使用范例:
    
    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def flow_stats_reply_handler(self, ev):
           flows = []
           for stat in ev.msg.body:
                flows.append('table_id=%s '
                       'duration_sec=%d duration_nsec=%d '
                       'priority=%d '
                       'idle_timeout=%d hard_timeout=%d flags=0x%04x '
                       'cookie=%d packet_count=%d byte_count=%d '
                       'match=%s instructions=%s' %
                       (stat.table_id,
                       stat.duration_sec, stat.duration_nsec,
                       stat.priority,
                       stat.idle_timeout, stat.hard_timeout, stat.flags,
                       stat.cookie, stat.packet_count, stat.byte_count,
                       stat.match, stat.instructions))
            self.logger.debug('FlowStats: %s', flows)
    来源:源码ryu\ofproto\ofproto_v1_3_parser.py
    
    与上一个事件的产生来源不同,该事件并不是由交换机状态改变而产生,而是由控制器主动发出,触发该事件并接收处理的。控制器主动发出的命令为OFPFlowStatsRequest函数。
    
    同样,查看源码中该函数的文档
    
        """
        Individual flow statistics request message
    
        The controller uses this message to query individual flow statistics.
    
        ================ ======================================================
        Attribute        Description
        ================ ======================================================
        flags            Zero or ``OFPMPF_REQ_MORE``
        table_id         ID of table to read
        out_port         Require matching entries to include this as an output
                         port
        out_group        Require matching entries to include this as an output
                         group
        cookie           Require matching entries to contain this cookie value
        cookie_mask      Mask used to restrict the cookie bits that must match
        match            Instance of ``OFPMatch``
        ================ ======================================================
    看见,该函数作用就是发出流量统计请求的。文档同样给出范例程序:
    
        Example::
    
            def send_flow_stats_request(self, datapath):
                ofp = datapath.ofproto
                ofp_parser = datapath.ofproto_parser
    
                cookie = cookie_mask = 0
                match = ofp_parser.OFPMatch(in_port=1)
                req = ofp_parser.OFPFlowStatsRequest(datapath, 0,
                                                     ofp.OFPTT_ALL,
                                                     ofp.OFPP_ANY, ofp.OFPG_ANY,
                                                     cookie, cookie_mask,
                                                     match)
                datapath.send_msg(req)
    查看构造函数:
    
    def __init__(self, datapath, flags=0, table_id=ofproto.OFPTT_ALL,
                     out_port=ofproto.OFPP_ANY,
                     out_group=ofproto.OFPG_ANY,
                     cookie=0, cookie_mask=0, match=None, type_=None):
    实际使用过程中,如果没有特定需要,这里我们可以只指定一个datapath参数,其他为缺省的默认值。
    
    小结:
    
    发起事件                 处理事件
    OFPFlowStatsRequest    EventOFPFlowStatsReply
    ofp_event.EventOFPPortStatsReply
    在源码中对该函数的说明如下:
    
    """
        Port statistics reply message
    
        The switch responds with this message to a port statistics request.
    
        ================ ======================================================
        Attribute        Description
        ================ ======================================================
        body             List of ``OFPPortStats`` instance
        ================ ======================================================
    该函数为端口统计应答消息,文档中给的范例程序如下:
    
    Example::
    
            @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
            def port_stats_reply_handler(self, ev):
                ports = []
                for stat in ev.msg.body:
                    ports.append('port_no=%d '
                                 'rx_packets=%d tx_packets=%d '
                                 'rx_bytes=%d tx_bytes=%d '
                                 'rx_dropped=%d tx_dropped=%d '
                                 'rx_errors=%d tx_errors=%d '
                                 'rx_frame_err=%d rx_over_err=%d rx_crc_err=%d '
                                 'collisions=%d duration_sec=%d duration_nsec=%d' %
                                 (stat.port_no,
                                  stat.rx_packets, stat.tx_packets,
                                  stat.rx_bytes, stat.tx_bytes,
                                  stat.rx_dropped, stat.tx_dropped,
                                  stat.rx_errors, stat.tx_errors,
                                  stat.rx_frame_err, stat.rx_over_err,
                                  stat.rx_crc_err, stat.collisions,
                                  stat.duration_sec, stat.duration_nsec))
                self.logger.debug('PortStats: %s', ports)
    通过案例程序,我们可以看到,从该消息中,我们可以获取到:
    
    rx_packets
    tx_packets
    rx_bytes
    tx_bytes
    rx_dropped
    tx_dropped
    rx_errors
    tx_errors
    rx_frame_err
    tx_overerr
    rx_crc_err
    collisions
    duration_sec
    duration_nsec
    同样该事件同样对应存在一个端口统计请求事件OFPPortStatsRequest,源码中对该函数的说明如下:
    
        """
        Port statistics request message
    
        The controller uses this message to query information about ports
        statistics.
    
        ================ ======================================================
        Attribute        Description
        ================ ======================================================
        flags            Zero or ``OFPMPF_REQ_MORE``
        port_no          Port number to read (OFPP_ANY to all ports)
        ================ ======================================================
    使用范例如下:
    
    Example::
    
            def send_port_stats_request(self, datapath):
                ofp = datapath.ofproto
                ofp_parser = datapath.ofproto_parser
    
                req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_ANY)
                datapath.send_msg(req)
    小结:
    
    发起事件                处理事件
    OFPPortStatsRequest    EventOFPPortStatsReply
  • 相关阅读:
    Atitit 华为基本法 attilax读后感
    Atitit 华为管理者内训书系 以奋斗者为本 华为公司人力资源管理纲要 attilax读后感
    Atitit 项目版本管理gitflow 与 Forking的对比与使用
    Atitit 管理的模式扁平化管理 金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理
    Atitit 乌合之众读后感attilax总结 与读后感结构规范总结
    深入理解 JavaScript 异步系列(4)—— Generator
    深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
    深入理解 JavaScript 异步系列(2)—— jquery的解决方案
    深入理解 JavaScript 异步系列(1)——基础
    使用 github + jekyll 搭建个人博客
  • 原文地址:https://www.cnblogs.com/dream397/p/13157412.html
Copyright © 2011-2022 走看看