Skip to content

Instantly share code, notes, and snippets.

@alextricity25
Created January 29, 2018 16:48
Show Gist options
  • Save alextricity25/bc40dc49eb0e508c72941fbb45aff7b8 to your computer and use it in GitHub Desktop.
Save alextricity25/bc40dc49eb0e508c72941fbb45aff7b8 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import os
import pdb
from ryu.base import app_manager
from ryu.controller import dpset
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.ofproto import ofproto_v1_3
from ryu.lib import hub
from bwstats import BandwidthStats
from topo import Topology
cfgfile = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "config.txt"))
STAT_REQUEST_PERIOD = 5
'''
Useful Topology class functions/properties:
Topology.hosts - a dictionary of Host objects keyed on host name
Topology.switches - a list of switch names
Topology.coreSwitches - dictionary of CoreSwitch objects keyed on
switch name
Topology.edgeSwitches - dictionary of EdgeSwitch objects keyed on
switch name
Topology.vlans - dictionary of vlan members, keyed on the vlan id (an integer)
Topology.ports[sw][inNode] - returns the port number on switch sw connected to
the adjacent node inNode, if inNode is a node name
(ie, switch or host). If inNode is a number, returns
the node or switch name on that port on switch sw.
Topology.getVlanCore(vlanId) - returns the core switch pre-assigned for the
vlan vlanId
Topology.dpidToName(dpid) - returns the switch name associated with the
specified dpid
Useful CoreSwitch class functions/properties:
CoreSwitch.name - the name of the switch (eg, 's101')
CoreSwitch.dpid - the dpid of the switch (eg, 101)
CoreSwitch.vlans - list of pre-assigned vlans for the switch to handle
Useful EdgeSwitch class functions/properties:
EdgeSwitch.name - the name of the switch (eg, 's101')
EdgeSwitch.dpid - the dpid of the switch (eg, 101)
EdgeSwitch.neighbors - list of hosts' names (eg, 'h6') attached to
the switch
Useful Host class functions/properties:
Host.name - the name of the host (eg, 'h6')
Host.eth - the MAC address of the host
Host.switch - the switch to which the host is connected
Host.vlans - a list of vlans with which the host is associated
Use BandwidthStats class functions/properties:
BandwidthStats.addHostBwStat(hostname, txbytes, rxbytes) - log transmitted
and received bytes for the specified host
BandwidthStats.hostBwString() - returns pretty-printed string for bandwidth
usage (transmitted and received bytes) by host
BandwidthStats.tenantBwString() - returns pretty-printed string for
bandwidth usage (transmitted and received) by tenant
Useful OFPortStats class functions/properties:
OFPortStats.port_no - the port number for the statistic
OFPortStats.rx_bytes - the number of received bytes from port_no
OFPortStats.tx_bytes - the number of transmitted bytes from port_no
'''
class BandwidthMonitor(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {
'dpset' : dpset.DPSet,
}
def __init__(self, *args, **kwargs):
super(BandwidthMonitor, self).__init__(*args, **kwargs)
self.datapaths = {}
self.dpset = kwargs['dpset']
self.topo = Topology(cfgfile)
self.bwstats = BandwidthStats(self.topo)
self.monitor_thread = hub.spawn(self.monitor)
@set_ev_cls(ofp_event.EventOFPStateChange, [MAIN_DISPATCHER, DEAD_DISPATCHER])
def stateChangeHandler(self, ev):
datapath = ev.datapath
if datapath.id:
if ev.state == MAIN_DISPATCHER:
if not datapath.id 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:
self.statsReplied = 0
for dp in self.datapaths.values():
self.requestStats(dp)
hub.sleep(STAT_REQUEST_PERIOD)
def requestStats(self, datapath):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def statsReplyHandler(self, ev):
# Here, a datapath (ie, switch) responds to the stats request.
body = ev.msg.body
datapath = ev.msg.datapath
dpid = datapath.id
# name of switch reporting data
name = self.topo.dpidToName(dpid)
totalDropped = 0
for stat in body:
totalDropped += stat.tx_dropped
totalDropped += stat.rx_dropped
self.bwstats.addDroppedPktStat(name, totalDropped)
# ASSIGNMENT 2:
# If the switch reporting the statistic is an edge switch, and the
# port connects to a host, log the statistic to bwstats, using
# self.bwstats.addHostBwStat(hostname, transmitted bytes, received bytes)
# (Hint: you can look up the switch or host connected to a port using
# self.topo.ports[switch name][port number])
# [ ADD YOUR CODE HERE ]
# This is just a template
for stat in body:
print 'ALEX - Name: {}'.format(name)
print 'ALEX - port_no: {}'.format(stat.port_no)
# Filter out virtual ports
if stat.port_no >= 5:
continue
device_of_port = self.topo.ports[name][stat.port_no]
if device_of_port in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
self.bwstats.addHostBwStat(
device_of_port, stat.tx_bytes, stat.rx_bytes)
# # Check to see if it's an edge switch
# if name not in ['s101', 's102', 's103']:
# continue
# total_rx = stat.rx
# total_tx = stat.tx
# self.bwstats.addDroppedPktStat(name, totalDropped)
# periodically print tenant bandwidth usage
self.statsReplied += 1
if self.statsReplied == len(self.datapaths):
self.bwstats.updateTenantStats()
self.logger.info(self.bwstats.tenantBwString())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment