本實作是使用Ryu提供的App來使用 OpenFlow 來取得相關的統計資訊
實驗拓樸
1.Simple_monitor_13.py
在Controller上執行simple_monitor_13
$ryu-manager ryu.app.simple_monitor_13
可以看到switch有正確連接且回傳的統計資訊都是零。
接著在Host1向Host2執行Ping指令
H1
ping 192.168.1.102
執行完成後,可以在Controller上面(如下圖)看到Port12 以及Port14有流量變化,也可以看到上面有Flow Entry的統計資訊
流量監控功能已經被實作在 SimpleMonitor 類別中並繼承自 SimpleSwitch13 ,所以Simple_monitor_13.py 已經沒有轉送相關的處理功能了。
from operator import attrgetter
from ryu.app import simple_switch_13 //繼承SimpleSwitch13
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) //每10秒要求
def _request_stats(self, datapath): //驅動OFPFlowStatsRequest以及OFPPortStatsRequest去要求資料
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) //對交換器的Flow Entry取得資料
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) //對交換器的Por取得資料
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)
2.oftcl_rest.py
在Controller上面執行
ryu-manager ryu.app.ofctl_rest ryu.app.simple_switch_13
※因為oftcl_rest並沒有轉發功能,所以建議和SimpleSwitch一起啟動,以便後續進行。
另外開啟Terminal執行
curl -X GET http://127.0.0.1:8080/stats/switches
curl -X GET http://127.0.0.1:8080/stats/flow/{dpid}
curl -X GET http://127.0.0.1:8080/stats/aggregateflow/{dpid}
curl -X GET http://127.0.0.1:8080/stats/table/{dpid}
下圖為未執行任何網路動作
可以看見 flow aggregateflow table 資料為空
下圖為Host1對Host2執行ping指令後
所得到的資料
獲得Switch列表
curl -X GET http://127.0.0.1:8080/stats/switches
獲得Switch規格
curl -X GET http://127.0.0.1:8080/stats/desc/<dpid>
獲得Switch的Flow狀態
curl -X GET http://127.0.0.1:8080/stats/flow/<dpid>
獲得Switch的Flow統計資料
curl -X GET http://127.0.0.1:8080/stats/aggregateflow/<dpid>
獲得Switch的Table
curl -X GET http://127.0.0.1:8080 GET /stats/table/<dpid>
※oftcl_rest想了解更多指令,請前往傳送點