根据网上相关学习视频和代码仿照的Ryu实现对交换机的端口以及流表项的监视器,代码如下:
#!/usr/bin/env python2
# -*- coding:utf-8 -*-
from operator import attrgetter
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.app import simple_switch_13
from ryu.lib import hub
#导入相关类库
class MyMonitor(simple_switch_13.SimpleSwitch13):
#创建自己的MyMonitor类,同时继承simple_switch_13.SimpleSwitch13类,simple_switch_13.SimpleSwitch13为一个实现自学习交换机的Ryu应用
def __init__(self, *args, **kwargs):
super(MyMonitor, self).__init__(*args, **kwargs)
self.datapaths = {}
self.monitor_thread = hub.spawn(self.monitor)
#使用hub.spawn添加其他线程处理应用
@set_ev_cls(ofp_event.EventOFPStateChange,
[MAIN_DISPATCHER, DEAD_DISPATCHER])
def port_state_change(self, ev):
datapath = ev.datapath
dpid = datapath.id
state = ev.state
if state == MAIN_DISPATCHER:
if datapath not in self.datapaths:
self.datapaths[dpid] = datapath
self.logger.debug('datapath %s register', dpid)
elif state == DEAD_DISPATCHER:
if datapath in self.datapaths:
del self.datapaths[dpid]
self.logger.debug('datapath %s unregister', dpid)
#判断交换机的状态改变并输出
def monitor(self):
while True:
for dpid in self.datapaths.values():
self.stats_request(dpid)
hub.sleep(10)
#monitor函数,一直循环执行stats_request函数进行交换机状态获取并输出,设置输出的时间间隔为10秒
def stats_request(self, datapath):
datapath = datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
msg = ofp_parser.OFPPortStatsRequest(datapath)
datapath.send_msg(msg)
msg = ofp_parser.OFPFlowStatsRequest(datapath)
datapath.send_msg(msg)
#stats_request函数,通过控制器向交换机发送OFPPortStatsRequest和OFPFlowStatsRequest消息,获取交换机端口状态以及流表
@set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def port_stats_reply(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)
#当EventOFPPortStatsReply事件发生时,进行交换机端口状态的输出
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def flow_stats_reply(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)
#当EventOFPPortStatsReply事件发生时,进行流表项优先级为1的流表状态的输出
进行验证,启动Ryu应用,连接到mininet建立的拓扑,对比发现控制器周期显示的流表项和ovs-ofctl命令查看的交换机流表项一致