实验目的
- 在互联网越来越发达的时代,网络上承载着越来越多的业务,所以维护网络的稳定非常重要。
- 当网络发生异常时,需要快速定位故障点,从而快速修复网络,保障业务的畅通。
- 流量监控可以实时获取网络的流量状况,实现网络流量状态可视化。
- 在故障发生时,通过流量监控应用可以快速定位故障点,缩短故障恢复时长。
此外,流量监控的数据也可以为流量工程提供数据支撑,从而提升网络整体的带宽利用率。
示例应用完成了基于OpenFlow1.3协议的流量统计信息的获取
- 包括基于端口的流量统计信息和基于流表项的统计信息
- 示例仅介绍如何获取统计信息,统计信息的处理和呈现将不做介绍
- 更多信息可以参考完整版流量监控应用
实验程序
```pythoncoding:utf-8
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 SimpleMonitor(simpleswitch13.SimpleSwitch13): def init(self, args, *kwargs): super(SimpleMonitor, self).__init(args,*kwargs) self.datapaths = {}
# 在初始化SimpleMonitor对象时,会启动一个协程 去周期运行_monitor方法。# _monitor方法中调用了_request_stats方法# 该方法向datapath发送了流表统计信息请求OFPFlowStatsRequest和端口统计信息请求OFPPortStatsRequest。# 这两个请求报文发送到datapath之后,交换机需要回复控制器对应的统计信息回复报文。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.datapathif ev.state == MAIN_DISPATCHER:if not datapath.id in self.datapaths:self.logger.debug('register datapath: %016x', datapath.id)self.datapaths[datapath.id] = datapathelif 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.ofprotoparser = datapath.ofproto_parserreq = 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):# _flow_stats_reply_handler 方法和_port_stats_reply_handler# 分别注册了EventOFPFlowStatsReply事件和EventOFPPortStatsReply事件。# 当交换机回复统计信息报文时,会触发对应的处理方法。# 比如交换机通过OFPPortStatsReply报文回复控制器其端口统计信息,在Ryu内部就会产生EventOFPPortStatsReply事件# 该事件会分发到所有注册了该事件的handler,其中就包括_port_stats_reply_handler。# _port_stats_reply_handler方法被调用之后,会将报文信息解析并打印相关信息,从而完成统计报文的解析处理工作。# 同理,流表项统计信息的回复信息的处理也是如此。body = ev.msg.bodyself.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)self.logger.info('datapath ''tcpsrc in-port eth-dst ''outport packets bytes')self.logger.info('---------------- ''------ -- -------- ----------------- ''------')# 在成功解析到流量统计信息之后,可以将其保存到对应的数据结构中。# 然后使用当前数据减去前一周期获取的统计数据,再通过两个统计信息的时间信息,相减得到时间间隔。# 最后将统计信息数值的差除以时间间隔,从而获得统计流量速度信息,完成流量监控程序。# 由于代码较长,且此部分内容不属于本示例展示重点for stat in sorted([flow for flow in body if flow.priority == 2],key=lambda flow: (flow.match['tcp_src'],flow.match['in_port'],flow.match['eth_dst'])):self.logger.info('%016x %8d %8x %17s %8x %8d %8d',ev.msg.datapath.id,stat.match['tcp_src'], 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.bodyself.logger.info('datapath port ''rx-pkts rxbytes rx-error ''tx-pkts txbytes 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)
<a name="teLDV"></a># 运行实验- 写完以上代码之后将其保存为Python 文件, 如`simple_monitor_13_test.py`,然后保存到ryu/app目录下- 由于这个文件是新加的,Ryu编译文件中并没有,所以还需要将Ryu重新编译安装- 重新安装之后,通过ryu-manager命令启动Ryu控制器并加载新写的应用即可- 具体命令如下```shellcd ryupython setup.py installryu-manager ryu/app/simple_monitor_13_test.py
启动Ryu之后,通过Mininet启动任意无环拓扑并连接到控制器。
sudo mn --controller remote
连接成功之后,运行结果如图所示

