-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRyu controller port statistics monitoring.py
More file actions
164 lines (119 loc) · 6.94 KB
/
Ryu controller port statistics monitoring.py
File metadata and controls
164 lines (119 loc) · 6.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import os # for file paths and svaing csv files
import pandas as pd
import json
import csv
import datetime
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)
# *********** Flow Statistics Data ***************
""" path = './my_ryu_apps/monitor_data'
str_datapath_id = str( ev.msg.datapath.id )
output_file_name = os.path.join( path,'flow_stats_dpid_' + str_datapath_id + '.csv' ) # we will write a independent file for each datapath
# note : body in ev.msg.body is a list of namedTuples. so to get to the named tuple use the list index frst
for element in body:
print ("element in flow stats", element )
flow_stats_dict = {}
flow_stats_dict['datapath'] = ev.msg.datapath.id
#print ("element as dict", element._asdict())
flow_stats_dict_temporary = {}
flow_stats_dict_temporary = element._asdict() # _asdict() method is a builtin method to convert namedtuples to dictionaries.
flow_stats_dict = {**flow_stats_dict, **flow_stats_dict_temporary} # merge the temporory dictionry with stats dict, to add datapath first
#port_stats_dict['port_no'] = hex( port_stats_dict['port_no'] ) # if we want prot numbers in hexidecimal
self.write_csv(flow_stats_dict, output_file_name) """
# *************************************************
@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)
#port_stats_keys =['datapath' ,'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']
# *********** Port statistics Data ************
path = './my_ryu_apps/monitor_data'
str_datapath_id = str( ev.msg.datapath.id )
output_file_name = os.path.join( path,'port_stats_dpid_' + str_datapath_id + '.csv' ) # we will write a independent file for each datapath
# note : body in ev.msg.body is a list of namedTuples. so to get to the named tuple use the list index frst
for element in body:
port_stats_dict = {}
#add time stamp
port_stats_dict['time'] = datetime.datetime.now()
port_stats_dict['datapath'] = ev.msg.datapath.id
#print ("element as dict", element._asdict())
port_stats_dict_temporary = {}
port_stats_dict_temporary = element._asdict() # _asdict() method is a builtin method to convert namedtuples to dictionaaries.
port_stats_dict = {**port_stats_dict, **port_stats_dict_temporary} # merge the temporory dictionry with stats dict, to add datapath first
#port_stats_dict['port_no'] = hex( port_stats_dict['port_no'] ) # if we want prot numbers in hexidecimal
self.write_csv(port_stats_dict, output_file_name)
@staticmethod
def write_csv(data_dict,output_file_name):
if os.path.isfile(output_file_name) == False : # if file does not exists
with open(output_file_name, 'w') as outfile:
writer = csv.writer(outfile) # open file for wiriting ( wriing the headers (column names))
writer.writerow(list(data_dict.keys())) # add headers
# open for appending rows , if we want to wirte the updated statistcs of each switch,
# we can use 'w', instead of 'a'.
with open(output_file_name, 'a') as outfile:
writer = csv.DictWriter(outfile, fieldnames = data_dict.keys())
writer.writerow(data_dict)