1. 代码解析

ryu/app/simple_monitor_13.py:

from operator import attrgetter
from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub

class SimpleMonitor13(simple_switch_13.SimpleSwitch13):

    def __init__(self, *args, **kwargs):
        super(SimpleMonitor13, self).__init__(*args, **kwargs)
        self.datapaths = {}
        self.monitor_thread = hub.spawn(self._monitor)

    @set_ev_cls(ofp_event.EventOFPStateChange, [MAIN_DISPATCHER, DEAD_DISPATCHER])
    def _state_change_handler(self, ev):
        datapath = ev.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
        elif ev.state == DEAD_DISPATCHER:
            if datapath.id in self.datapaths:
                self.logger.debug('unregister datapath: %016x', datapath.id)
                del self.datapaths[datapath.id]

    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)
    def _flow_stats_reply_handler(self, ev):
        body = ev.msg.body

        self.logger.info('datapath         '
                         'in-port  eth-dst           '
                         'out-port packets  bytes')
        self.logger.info('---------------- '
                         '-------- ----------------- '
                         '-------- -------- --------')
        for stat in sorted([flow for flow in body if flow.priority == 1],
                           key=lambda flow: (flow.match['in_port'],
                                             flow.match['eth_dst'])):
            self.logger.info('%016x %8x %17s %8x %8d %8d',
                             ev.msg.datapath.id,
                             stat.match['in_port'], stat.match['eth_dst'],
                             stat.instructions[0].actions[0].port,
                             stat.packet_count, stat.byte_count)

    @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
    def _port_stats_reply_handler(self, ev):
        body = ev.msg.body

        self.logger.info('datapath         port     '
                         'rx-pkts  rx-bytes rx-error '
                         'tx-pkts  tx-bytes tx-error')
        self.logger.info('---------------- -------- '
                         '-------- -------- -------- '
                         '-------- -------- --------')
        for stat in sorted(body, key=attrgetter('port_no')):
            self.logger.info('%016x %8x %8d %8d %8d %8d %8d %8d',
                             ev.msg.datapath.id, stat.port_no,
                             stat.rx_packets, stat.rx_bytes, stat.rx_errors,
                             stat.tx_packets, stat.tx_bytes, stat.tx_errors)
  • 使用 ryu.lib.hub.spawn() 创建eventlet绿色线程;
  • 当datapath状态发生变化时,Ryu会生成 EventOFPStateChange 事件;
  • ryu.ofproto.ofproto_v1_3_parser.OFPFlowStatsRequest 用于请求交换机提供与流项相关的统计信息;含有如下属性:
================ ======================================================
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
================ ======================================================

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):
    # ...

 

  • ryu.ofproto.ofproto_v1_3_parser.OFPPortStatsRequest 用于请求交换机提供与端口相关的统计信息;含有如下属性:
================ ======================================================
Attribute        Description
================ ======================================================
flags            Zero or OFPMPF_REQ_MORE
port_no          Port number to read (OFPP_ANY to all ports)
================ ======================================================

def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
                 type_=None):
    # ...

 

  • ryu.ofproto.ofproto_v1_3_parser.OFPFlowStatsReplyOFPFlowStatsRequest 的响应;含有如下属性:
================ ======================================================
Attribute        Description
================ ======================================================
body             List of OFPFlowStats instance
================ ======================================================

  ryu.ofproto.ofproto_v1_3_parser.OFPFlowStats 拥有如下属性:

self.table_id = table_id
self.duration_sec = duration_sec
self.duration_nsec = duration_nsec
self.priority = priority
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.flags = flags
self.cookie = cookie
self.packet_count = packet_count
self.byte_count = byte_count
self.match = match
self.instructions = instructions
self.length = length

 

  • ryu.ofproto.ofproto_v1_3_parser.OFPPortStatsReplyOFPPortStatsRequest 的响应;含有如下属性:
================ ======================================================
Attribute        Description
================ ======================================================
body             List of OFPPortStats instance
================ ======================================================

  ryu.ofproto.ofproto_v1_3_parser.OFPPortStats 含有如下属性:

class OFPPortStats(ofproto_parser.namedtuple('OFPPortStats', (
        'port_no', 'rx_packets', 'tx_packets', 'rx_bytes', 'tx_bytes',
        'rx_dropped', 'tx_dropped', 'rx_errors', 'tx_errors',
        'rx_frame_err', 'rx_over_err', 'rx_crc_err', 'collisions',
        'duration_sec', 'duration_nsec'))):
    # ...

 

2. 运行

# --topo sigle,3: 单个交换机,3个主机
# --mac: 自动设置主机的MAC地址
# --switch ovsk: 使用 ovs
# --controller remote: 使用外部OpenFlow控制器
# -x: 启动xterm
$ sudo mn --topo single,3 --mac --switch ovsk --controller remote -x

此时会启动5个xterm:h1~h3, switch, controller.

设置OpenFlow版本:switch: s1

# ovs-vsctl set Bridge s1 protocols=OpenFlow13

启动控制器:controller: c0

# ryu-manager --verbose ryu/app/simple_monitor_13.py

ping:

mininet> h1 ping -c1 h2

查看 controller: c0

 

参考资料

https://osrg.github.io/ryu-book/en/Ryubook.pdf

版权声明:本文为gzming原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/gzming/p/14337299.html