Skip to content

Commit

Permalink
puah network awareness module
Browse files Browse the repository at this point in the history
  • Loading branch information
muzixing committed Jul 1, 2016
1 parent 3c7c83a commit 6c2d02e
Show file tree
Hide file tree
Showing 8 changed files with 1,188 additions and 0 deletions.
55 changes: 55 additions & 0 deletions ryu/app/network_awareness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
##Network Awareness

Network Awareness is a set of Ryu applications to collecting the basic network information including the topology, link delay, and link free bandwidth. Also, the Shortest\_forwarding.py application can achieve the shortest path forwarding based on HOP, DELAY and BANDWIDTH. You can set model of computing shortest path when starting Ryu by adding "weight" argument. Moreover, you can set "k-paths" argument to support K-Shortest paths computing. Fortunately, our application supports load balance based on dynamic traffic information.

The detail information of modules shows below.

* Network Aware is a module for collecting network information.

* Network Monitor is a module for collecting network traffic information.

* Network Delay is a module for collecting link delay information.

* Shortest\_forwarding is a simple application to achieve shortest forwarding based on hop or delay.

* Setting is the common setting module.



In this version, we take networkx's data structure to store topology. Meanwhile, we also use networkx's function to calculate shortest path.


### Download File

Download files, and add them to ryu directory, for instance, app/network_awareness

### Make some changes

To register parsing parameter, you NEED to add code into flags.py, which is in the topo directory of ryu project.

CONF.register_cli_opts([
# k_shortest_forwarding
cfg.IntOpt('k-paths', default=1, help='number for k shortest paths'),
cfg.StrOpt('weight', default='hop',
help='weight type of computing shortest path.')])

### Reinstall Ryu

You have to reinstall Ryu, so that you can run the new code. In the top derectory of ryu project.

sudo python setup.py install


### Start

Go into the directory, and run applications. You are suggested to add arguments when starting Ryu. The example shows below.

ryu-manager shortest_forwarding.py --observe-links --k-paths=2 --weight=bw

The last step is to set up a network and connect to Ryu.

If you need to show collected information, you can set the parameter in setting.py. Also, you can define your personal setting, such as topology discovery period, You will find out the information shown in terninal.

Enjoy it! Good Luck!

If you have any question, you can email me. Don't forget to STAR this repository!
1 change: 1 addition & 0 deletions ryu/app/network_awareness/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"For loading module"
277 changes: 277 additions & 0 deletions ryu/app/network_awareness/network_awareness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# Copyright (C) 2016 Li Cheng at Beijing University of Posts
# and Telecommunications. www.muzixing.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# conding=utf-8
import logging
import struct
import copy
import networkx as nx
from operator import attrgetter
from ryu import cfg
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ipv4
from ryu.lib.packet import arp
from ryu.lib import hub

from ryu.topology import event, switches
from ryu.topology.api import get_switch, get_link
import setting


CONF = cfg.CONF


class NetworkAwareness(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

def __init__(self, *args, **kwargs):
super(NetworkAwareness, self).__init__(*args, **kwargs)
self.topology_api_app = self
self.name = "awareness"
self.link_to_port = {} # (src_dpid,dst_dpid)->(src_port,dst_port)
self.access_table = {} # {(sw,port) :[host1_ip]}
self.switch_port_table = {} # dpip->port_num
self.access_ports = {} # dpid->port_num
self.interior_ports = {} # dpid->port_num

self.graph = nx.DiGraph()
self.pre_graph = nx.DiGraph()
self.pre_access_table = {}
self.pre_link_to_port = {}
self.shortest_paths = None

self.discover_thread = hub.spawn(self._discover)

def _discover(self):
i = 0
while True:
self.show_topology()
if i == 5:
self.get_topology(None)
i = 0
hub.sleep(setting.DISCOVERY_PERIOD)
i = i + 1

@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
msg = ev.msg
self.logger.info("switch:%s connected", datapath.id)

# install table-miss flow entry
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)

def add_flow(self, dp, p, match, actions, idle_timeout=0, hard_timeout=0):
ofproto = dp.ofproto
parser = dp.ofproto_parser

inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]

mod = parser.OFPFlowMod(datapath=dp, priority=p,
idle_timeout=idle_timeout,
hard_timeout=hard_timeout,
match=match, instructions=inst)
dp.send_msg(mod)

def get_host_location(self, host_ip):
for key in self.access_table.keys():
if self.access_table[key][0] == host_ip:
return key
self.logger.info("%s location is not found." % host_ip)
return None

def get_switches(self):
return self.switches

def get_links(self):
return self.link_to_port

# get Adjacency matrix from link_to_port
def get_graph(self, link_list):
for src in self.switches:
for dst in self.switches:
# self.graph.add_edge(src, dst, weight=float('inf'))
if src == dst:
self.graph.add_edge(src, dst, weight=0)
elif (src, dst) in link_list:
self.graph.add_edge(src, dst, weight=1)
return self.graph

def create_port_map(self, switch_list):
for sw in switch_list:
dpid = sw.dp.id
self.switch_port_table.setdefault(dpid, set())
self.interior_ports.setdefault(dpid, set())
self.access_ports.setdefault(dpid, set())

for p in sw.ports:
self.switch_port_table[dpid].add(p.port_no)

# get links`srouce port to dst port from link_list,
# link_to_port:(src_dpid,dst_dpid)->(src_port,dst_port)
def create_interior_links(self, link_list):
for link in link_list:
src = link.src
dst = link.dst
self.link_to_port[
(src.dpid, dst.dpid)] = (src.port_no, dst.port_no)

# find the access ports and interiorior ports
if link.src.dpid in self.switches:
self.interior_ports[link.src.dpid].add(link.src.port_no)
if link.dst.dpid in self.switches:
self.interior_ports[link.dst.dpid].add(link.dst.port_no)

# get ports without link into access_ports
def create_access_ports(self):
for sw in self.switch_port_table:
all_port_table = self.switch_port_table[sw]
interior_port = self.interior_ports[sw]
self.access_ports[sw] = all_port_table - interior_port

def k_shortest_paths(self, graph, src, dst, weight='weight', k=1):
generator = nx.shortest_simple_paths(graph, source=src,
target=dst, weight=weight)
shortest_paths = []
try:
for path in generator:
if k <= 0:
break
shortest_paths.append(path)
k -= 1
return shortest_paths
except:
self.logger.debug("No path between %s and %s" % (src, dst))

def all_k_shortest_paths(self, graph, weight='weight', k=1):
_graph = copy.deepcopy(graph)
paths = {}

# find ksp in graph.
for src in _graph.nodes():
paths.setdefault(src, {src: [[src] for i in xrange(k)]})
for dst in _graph.nodes():
if src == dst:
continue
paths[src].setdefault(dst, [])
paths[src][dst] = self.k_shortest_paths(_graph, src, dst,
weight=weight, k=k)
return paths

events = [event.EventSwitchEnter,
event.EventSwitchLeave, event.EventPortAdd,
event.EventPortDelete, event.EventPortModify,
event.EventLinkAdd, event.EventLinkDelete]

@set_ev_cls(events)
def get_topology(self, ev):
switch_list = get_switch(self.topology_api_app, None)
self.create_port_map(switch_list)
self.switches = self.switch_port_table.keys()
links = get_link(self.topology_api_app, None)
self.create_interior_links(links)
self.create_access_ports()
self.get_graph(self.link_to_port.keys())
self.shortest_paths = self.all_k_shortest_paths(
self.graph, weight='weight', k=CONF.k_paths)

def register_access_info(self, dpid, in_port, ip, mac):
if in_port in self.access_ports[dpid]:
if (dpid, in_port) in self.access_table:
if self.access_table[(dpid, in_port)] == (ip, mac):
return
else:
self.access_table[(dpid, in_port)] = (ip, mac)
return
else:
self.access_table.setdefault((dpid, in_port), None)
self.access_table[(dpid, in_port)] = (ip, mac)
return

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath

parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)

eth_type = pkt.get_protocols(ethernet.ethernet)[0].ethertype
arp_pkt = pkt.get_protocol(arp.arp)
ip_pkt = pkt.get_protocol(ipv4.ipv4)

if arp_pkt:
arp_src_ip = arp_pkt.src_ip
arp_dst_ip = arp_pkt.dst_ip
mac = arp_pkt.src_mac

# record the access info
self.register_access_info(datapath.id, in_port, arp_src_ip, mac)

def show_topology(self):
switch_num = len(self.graph.nodes())
if self.pre_graph != self.graph or setting.TOSHOW:
print "---------------------Topo Link---------------------"
print '%10s' % ("switch"),
for i in xrange(1, switch_num + 1):
print '%10d' % i,
print ""
for i in self.graph.nodes():
print '%10d' % i,
for j in self.graph[i].values():
print '%10.0f' % j['weight'],
print ""
self.pre_graph = copy.deepcopy(self.graph)

if self.pre_link_to_port != self.link_to_port or setting.TOSHOW:
print "---------------------Link Port---------------------"
print '%10s' % ("switch"),
for i in xrange(1, switch_num + 1):
print '%10d' % i,
print ""
for i in xrange(1, switch_num + 1):
print '%10d' % i,
for j in xrange(1, switch_num + 1):
if (i, j) in self.link_to_port.keys():
print '%10s' % str(self.link_to_port[(i, j)]),
else:
print '%10s' % "No-link",
print ""
self.pre_link_to_port = copy.deepcopy(self.link_to_port)

if self.pre_access_table != self.access_table or setting.TOSHOW:
print "----------------Access Host-------------------"
print '%10s' % ("switch"), '%12s' % "Host"
if not self.access_table.keys():
print " NO found host"
else:
for tup in self.access_table:
print '%10d: ' % tup[0], self.access_table[tup]
self.pre_access_table = copy.deepcopy(self.access_table)
Loading

0 comments on commit 6c2d02e

Please sign in to comment.