| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 1 | __author__ = 'Administrator'
|
| 2 |
|
| 3 | import urllib2
|
| 4 | import logging
|
| 5 | from mininet.node import OVSSwitch
|
| 6 | import ast
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 7 | import time
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 8 | logging.basicConfig(level=logging.INFO)
|
| 9 |
|
| 10 | """
|
| 11 | class to read openflow stats from the Ryu controller of the DCNEtwork
|
| 12 | """
|
| 13 |
|
| 14 | class DCNetworkMonitor():
|
| 15 | def __init__(self, net):
|
| 16 | self.net = net
|
| 17 | # link to REST_API
|
| 18 | self.ip = '0.0.0.0'
|
| 19 | self.port = '8080'
|
| 20 | self.REST_api = 'http://{0}:{1}'.format(self.ip,self.port)
|
| 21 |
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 22 | self.previous_measurement = 0
|
| 23 | self.previous_monitor_time = 0
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 24 | self.switch_dpid = 0
|
| 25 | self.metric_key = None
|
| 26 | self.mon_port = None
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 27 |
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 28 | # first set some parameters, before measurement can start
|
| 29 | def setup_rate_measurement(self, vnf_name, vnf_interface=None, direction='tx', metric='packets'):
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 30 | # check if port is specified (vnf:port)
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 31 | if vnf_interface is None:
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 32 | # take first interface by default
|
| 33 | connected_sw = self.net.DCNetwork_graph.neighbors(vnf_name)[0]
|
| 34 | link_dict = self.net.DCNetwork_graph[vnf_name][connected_sw]
|
| 35 | vnf_interface = link_dict[0]['src_port_id']
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 36 |
|
| 37 | for connected_sw in self.net.DCNetwork_graph.neighbors(vnf_name):
|
| 38 | link_dict = self.net.DCNetwork_graph[vnf_name][connected_sw]
|
| 39 | for link in link_dict:
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 40 | # logging.info("{0},{1}".format(link_dict[link],vnf_interface))
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 41 | if link_dict[link]['src_port_id'] == vnf_interface:
|
| 42 | # found the right link and connected switch
|
| 43 | # logging.info("{0},{1}".format(link_dict[link]['src_port_id'], vnf_source_interface))
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 44 | self.mon_port = link_dict[link]['dst_port']
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 45 | break
|
| 46 |
|
| 47 | try:
|
| 48 | # default port direction to monitor
|
| 49 | if direction is None:
|
| 50 | direction = 'tx'
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 51 | if metric is None:
|
| 52 | metric = 'packets'
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 53 |
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 54 | vnf_switch = self.net.DCNetwork_graph.neighbors(str(vnf_name))
|
| 55 |
|
| 56 | if len(vnf_switch) > 1:
|
| 57 | logging.info("vnf: {0} has multiple ports".format(vnf_name))
|
| 58 | return
|
| 59 | elif len(vnf_switch) == 0:
|
| 60 | logging.info("vnf: {0} is not connected".format(vnf_name))
|
| 61 | return
|
| 62 | else:
|
| 63 | vnf_switch = vnf_switch[0]
|
| 64 | next_node = self.net.getNodeByName(vnf_switch)
|
| 65 |
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 66 | if not isinstance(next_node, OVSSwitch):
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 67 | logging.info("vnf: {0} is not connected to switch".format(vnf_name))
|
| 68 | return
|
| 69 |
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 70 | self.previous_measurement = 0
|
| 71 | self.previous_monitor_time = 0
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 72 |
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 73 | #self.switch_dpid = x = int(str(next_node.dpid), 16)
|
| 74 | self.switch_dpid = int(str(next_node.dpid), 16)
|
| 75 | self.metric_key = '{0}_{1}'.format(direction, metric)
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 76 |
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 77 | except Exception as ex:
|
| 78 | logging.exception("get_txrate error.")
|
| 79 | return ex.message
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 80 |
|
| 81 |
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 82 | # call this function repeatedly for streaming measurements
|
| 83 | def get_rate(self, vnf_name, vnf_interface=None, direction='tx', metric='packets'):
|
| 84 |
|
| 85 | key = self.metric_key
|
| 86 |
|
| 87 | ret = self.REST_cmd('stats/port', self.switch_dpid)
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 88 | port_stat_dict = ast.literal_eval(ret)
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 89 | for port_stat in port_stat_dict[str(self.switch_dpid)]:
|
| 90 | if port_stat['port_no'] == self.mon_port:
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 91 | port_uptime = port_stat['duration_sec'] + port_stat['duration_nsec'] * 10 ** (-9)
|
| 92 | this_measurement = port_stat[key]
|
| 93 |
|
| 94 | if self.previous_monitor_time <= 0 or self.previous_monitor_time >= port_uptime:
|
| 95 | self.previous_measurement = port_stat[key]
|
| 96 | self.previous_monitor_time = port_uptime
|
| 97 | # do first measurement
|
| 98 | time.sleep(1)
|
| stevenvanrossem | ed711fd | 2016-04-11 16:59:29 +0200 | [diff] [blame] | 99 | byte_rate = self.get_rate(vnf_name, vnf_interface, direction, metric)
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 100 | return byte_rate
|
| 101 | else:
|
| 102 | time_delta = (port_uptime - self.previous_monitor_time)
|
| 103 | byte_rate = (this_measurement - self.previous_measurement) / float(time_delta)
|
| 104 | #logging.info('uptime:{2} delta:{0} rate:{1}'.format(time_delta,byte_rate,port_uptime))
|
| stevenvanrossem | 9315da4 | 2016-04-11 12:10:06 +0200 | [diff] [blame] | 105 |
|
| 106 | self.previous_measurement = this_measurement
|
| 107 | self.previous_monitor_time = port_uptime
|
| 108 | return byte_rate
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 109 |
|
| 110 | return ret
|
| 111 |
|
| stevenvanrossem | c5a536a | 2016-02-16 14:52:39 +0100 | [diff] [blame] | 112 | def REST_cmd(self, prefix, dpid):
|
| 113 | url = self.REST_api + '/' + str(prefix) + '/' + str(dpid)
|
| 114 | req = urllib2.Request(url)
|
| 115 | ret = urllib2.urlopen(req).read()
|
| 116 | return ret |