一:实现流量监控
掌握基于Ryu开发流量监控应用: 主动下发逻辑
(一)流量监控原理
控制器向交换机周期下发获取统计消息,请求交换机信息端口流量统计信息
请求流表项统计信息(提高)
根据交换机统计信息计算计算流量信息
流速公式: speed = (s(t1) - s(t0))/(t1-t0)
剩余带宽公式: free_bw = capability - speed
其中控制器向交换机周期下发获取统计消息,请求交换机消息------是主动下发过程
流速公式:是(t1时刻的流量-t0时刻的流量)/(t1-t0)
剩余带宽公式:链路总带宽-流速--------是这一个这一个,
例如s2-s3(不是一条,例如:h1->s1->s2->s3->h2)的剩余带宽
路径有效带宽是只:这一整条路径中,按照最小的剩余带宽处理
二:代码实现
from operator import attrgetter
from ryu.app import simple_switch_13
from ryu.controller.handler import set_ev_cls
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,DEAD_DISPATCHER
from ryu.lib import hub
class MyMonitor(simple_switch_13.SimpleSwitch13): #simple_switch_13 is same as the last experiment which named self_learn_switch
'''
design a class to achvie managing the quantity of flow
'''
def __init__(self,*args,**kwargs):
super(MyMonitor,self).__init__(*args,**kwargs)
self.datapaths = {}
#use gevent to start monitor
self.monitor_thread = hub.spawn(self._monitor)
@set_ev_cls(ofp_event.EventOFPStateChange,[MAIN_DISPATCHER,DEAD_DISPATCHER])
def _state_change_handler(self,ev):
'''
design a handler to get switch state transition condition
'''
#first get ofprocotol info
datapath = ev.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
#judge datapath`s status to decide how to operate
if datapath.state == MAIN_DISPATCHER: #should save info to dictation
if datapath.id not in self.datapaths:
self.datapaths[datapath.id] = datapath
self.logger.debug("Regist datapath: %16x",datapath.id)
elif datapath.state == DEAD_DISPATCHER: #should remove info from dictation
if datapath.id in self.datapaths:
del self.datapaths[datapath.id]
self.logger.debug("Unregist datapath: %16x",datapath.id)
def _monitor(self):
'''
design a monitor on timing system to request switch infomations about port and flow
'''
while True: #initiatie to request port and flow info all the time
for dp in self.datapaths.values():
self._request_stats(dp)
hub.sleep(5) #pause to sleep to wait reply, and gave time to other gevent to request
def _request_stats(self,datapath):
'''
the function is to send requery to datapath
'''
self.logger.debug("send stats reques to datapath: %16x for port and flow info",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.EventOFPPortStatsReply,MAIN_DISPATCHER)
def _port_stats_reply_handler(self,ev):
'''
monitor to require the port state, then this function is to get infomation for port`s info
print("6666666666port info:")
print(ev.msg)
print(dir(ev.msg))
'''
body = ev.msg.body
self.logger.info('datapath port '
'rx_packets tx_packets'
'rx_bytes tx_bytes'
'rx_errors tx_errors'
)
self.logger.info('--------------- --------'
'-------- --------'
'-------- --------'
'-------- --------'
)
for port_stat in sorted(body,key=attrgetter('port_no')):
self.logger.info('%016x %8x %8d %8d %8d %8d %8d %8d',
ev.msg.datapath.id,port_stat.port_no,port_stat.rx_packets,port_stat.tx_packets,
port_stat.rx_bytes,port_stat.tx_bytes,port_stat.rx_errors,port_stat.tx_errors
)
@set_ev_cls(ofp_event.EventOFPFlowStatsReply,MAIN_DISPATCHER)
def _flow_stats_reply_handler(self,ev):
'''
monitor to require the flow state, then this function is to get infomation for flow`s info
print("777777777flow info:")
print(ev.msg)
print(dir(ev.msg))
'''
body = ev.msg.body
self.logger.info('datapath '
'in_port eth_src'
'out_port eth_dst'
'packet_count byte_count'
)
self.logger.info('--------------- '
'---- -----------------'
'---- -----------------'
'--------- ---------'
)
for flow_stat in sorted([flow for flow in body if flow.priority==1],
key=lambda flow:(flow.match['in_port'],flow.match['eth_src'])):
self.logger.info('%016x %8x %17s %8x %17s %8d %8d',
ev.msg.datapath.id,flow_stat.match['in_port'],flow_stat.match['eth_src'],
flow_stat.instructions[0].actions[0].port,flow_stat.match['eth_dst'],
flow_stat.packet_count,flow_stat.byte_count
)
代码讲解:
1.class MyMonitor(simple_switch_13.SimpleSwitch13):
simple_switch_13.SimpleSwitch13是样例代码,其中实现了和我们上一次实验中,自学习交换机类似的功能
(稍微多了个关于交换机是否上传全部packet还是只上传buffer_id),所以我们直接继承,可以减少写代码时间
2.协程实现伪并发self.monitor_thread = hub.spawn(self._monitor)
def __init__(self,*args,**kwargs):
super(MyMonitor,self).__init__(*args,**kwargs)
self.datapaths = {}
#use gevent to start monitor
self.monitor_thread = hub.spawn(self._monitor)
3.
@set_ev_cls(ofp_event.EventOFPStateChange,[MAIN_DISPATCHER,DEAD_DISPATCHER])
def _state_change_handler(self,ev):
'''
design a handler to get switch state transition condition
'''
#first get ofprocotol info
datapath = ev.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
#judge datapath`s status to decide how to operate
if datapath.state == MAIN_DISPATCHER: #should save info to dictation
if datapath.id not in self.datapaths:
self.datapaths[datapath.id] = datapath
self.logger.debug("Regist datapath: %16x",datapath.id)
elif datapath.state == DEAD_DISPATCHER: #should remove info from dictation
if datapath.id in self.datapaths:
del self.datapaths[datapath.id]
self.logger.debug("Unregist datapath: %16x",datapath.id)
当交换机状态发生变化时,会触发该事件处理函数。该函数首先获取事件中的datapath信息,并判断datapath的状态是MAIN_DISPATCHER还是DEAD_DISPATCHER。
如果datapath的状态是MAIN_DISPATCHER,说明该交换机已经连接到控制器,需要将其信息保存到控制器的datapahts字典中。如果该交换机的id已经存在于datapahts字典中,则不需要再次保存。最后打印调试信息,表示已经成功注册该datapath。
如果datapath的状态是DEAD_DISPATCHER,说明该交换机已经从控制器中断开连接,需要将其信息从datapahts字典中删除。如果该交换机的id已经不存在于datapahts字典中,则不需要再次删除。最后打印调试信息,表示已经成功注销该datapath。
4.在协程中实现周期请求交换机信息
def _monitor(self):
'''
design a monitor on timing system to request switch infomations about port and flow
'''
while True: #initiatie to request port and flow info all the time
for dp in self.datapaths.values():
self._request_stats(dp)
hub.sleep(5) #pause to sleep to wait reply, and gave time to other gevent to request
5.主动下发消息,请求交换机信息OFPFlowStatsRequest
注意:我们这里请求两个(端口和协议信息),所以我们要使用两个函数来分别处理port和flow响应
def _request_stats(self,datapath):
'''
the function is to send requery to datapath
'''
self.logger.debug("send stats reques to datapath: %16x for port and flow info",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)
6.获取端口响应信息ofp_event.EventOFPPortStatsReply
@set_ev_cls(ofp_event.EventOFPPortStatsReply,MAIN_DISPATCHER)
def _port_stats_reply_handler(self,ev):
'''
monitor to require the port state, then this function is to get infomation for port`s info
print("6666666666port info:")
print(ev.msg)
print(dir(ev.msg))
'''
body = ev.msg.body
self.logger.info('datapath port '
'rx_packets tx_packets'
'rx_bytes tx_bytes'
'rx_errors tx_errors'
)
self.logger.info('--------------- --------'
'-------- --------'
'-------- --------'
'-------- --------'
)
for port_stat in sorted(body,key=attrgetter('port_no')):
self.logger.info('%016x %8x %8d %8d %8d %8d %8d %8d',
ev.msg.datapath.id,port_stat.port_no,port_stat.rx_packets,port_stat.tx_packets,
port_stat.rx_bytes,port_stat.tx_bytes,port_stat.rx_errors,port_stat.tx_errors
)
7.获取flow协议响应信息ofp_event.EventOFPFlowStatsReply
@set_ev_cls(ofp_event.EventOFPFlowStatsReply,MAIN_DISPATCHER)
def _flow_stats_reply_handler(self,ev):
'''
monitor to require the flow state, then this function is to get infomation for flow`s info
print("777777777flow info:")
print(ev.msg)
print(dir(ev.msg))
'''
body = ev.msg.body
self.logger.info('datapath '
'in_port eth_src'
'out_port eth_dst'
'packet_count byte_count'
)
self.logger.info('--------------- '
'---- -----------------'
'---- -----------------'
'--------- ---------'
)
for flow_stat in sorted([flow for flow in body if flow.priority==1],
key=lambda flow:(flow.match['in_port'],flow.match['eth_src'])):
self.logger.info('%016x %8x %17s %8x %17s %8d %8d',
ev.msg.datapath.id,flow_stat.match['in_port'],flow_stat.match['eth_src'],
flow_stat.instructions[0].actions[0].port,flow_stat.match['eth_dst'],
flow_stat.packet_count,flow_stat.byte_count
)
三:实验演示
(一)开启Ryu
ryu-manager my_monitor.py
(二)开启Mininet
sudo mn --topo=tree,2,2 --controller=remote --mac
(三)Ryu显示结果
文章来源地址https://www.toymoban.com/news/detail-506394.html文章来源:https://www.toymoban.com/news/detail-506394.html
到了这里,关于SDN实验---Ryu的应用开发(二)流量监控的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!