Skip to content

Commit

Permalink
publish network awareness.
Browse files Browse the repository at this point in the history
  • Loading branch information
muzixing committed Jun 29, 2016
1 parent 807d9e3 commit 0859b86
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 97 deletions.
29 changes: 18 additions & 11 deletions ryu/app/network_awareness/README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
##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 or delay. Actually, it can based on bandwidth easily if you make a little bit change of code. The detail information of modules shows below.
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.

* NetworkAwareness is a module for collecting network information.
The detail information of modules shows below.

* NetworkMonitor is a module for collecting network traffic information.
* Network Aware is a module for collecting network information.

* NetworkDelayDetector is a module for collecting link delay information. [Coming soon]
* 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.

* ShortestForwarding is a simple application to achieve shortest forwarding based on hop or delay.


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 File

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

Expand All @@ -25,14 +30,16 @@ You have to reinstall Ryu, so that you can run the new code. In the top derector
sudo python setup.py install


###Start
### Start

Go into the directory, and run applications.
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
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.

You will find out the information shown in terninal.
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!

Good Luck!
If you have any question, you can email me. Don't forget to STAR this repository!
62 changes: 44 additions & 18 deletions ryu/app/network_awareness/network_awareness.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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
Expand All @@ -34,12 +35,14 @@

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]
SLEEP_PERIOD = 10
IS_UPDATE = True

def __init__(self, *args, **kwargs):
super(NetworkAwareness, self).__init__(*args, **kwargs)
Expand All @@ -66,7 +69,7 @@ def _discover(self):
if i == 5:
self.get_topology(None)
i = 0
hub.sleep(self.SLEEP_PERIOD)
hub.sleep(setting.DISCOVERY_PERIOD)
i = i + 1

@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
Expand Down Expand Up @@ -113,7 +116,7 @@ def get_links(self):
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'))
# 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:
Expand Down Expand Up @@ -148,16 +151,38 @@ def create_interior_links(self, link_list):
# get ports without link into access_ports
def create_access_ports(self):
for sw in self.switch_port_table:
self.access_ports[sw] = self.switch_port_table[
sw] - self.interior_ports[sw]

def floyd_dict(self, graph, cutoff=None, weight='weight'):
return nx.all_pairs_dijkstra_path(graph, cutoff=cutoff, weight=weight)

def get_shortest_paths(self, cutoff=None, weight='weight'):
self.shortest_paths = self.floyd_dict(self.graph, cutoff=cutoff,
weight=weight)
return self.shortest_paths
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,
Expand All @@ -173,7 +198,8 @@ def get_topology(self, ev):
self.create_interior_links(links)
self.create_access_ports()
self.get_graph(self.link_to_port.keys())
self.get_shortest_paths(weight='weight')
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]:
Expand Down Expand Up @@ -211,7 +237,7 @@ def _packet_in_handler(self, ev):

def show_topology(self):
switch_num = len(self.graph.nodes())
if self.pre_graph != self.graph or self.IS_UPDATE:
if self.pre_graph != self.graph or setting.TOSHOW:
print "---------------------Topo Link---------------------"
print '%10s' % ("switch"),
for i in xrange(1, switch_num + 1):
Expand All @@ -224,7 +250,7 @@ def show_topology(self):
print ""
self.pre_graph = copy.deepcopy(self.graph)

if self.pre_link_to_port != self.link_to_port or self.IS_UPDATE:
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):
Expand All @@ -240,7 +266,7 @@ def show_topology(self):
print ""
self.pre_link_to_port = copy.deepcopy(self.link_to_port)

if self.pre_access_table != self.access_table or self.IS_UPDATE:
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():
Expand Down
152 changes: 152 additions & 0 deletions ryu/app/network_awareness/network_delay_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# 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.

from __future__ import division
from ryu import cfg
from ryu.base import app_manager
from ryu.base.app_manager import lookup_service_brick
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 ryu.topology.switches import Switches
from ryu.topology.switches import LLDPPacket
import networkx as nx
import time
import setting


CONF = cfg.CONF


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

def __init__(self, *args, **kwargs):
super(NetworkDelayDetector, self).__init__(*args, **kwargs)
self.name = 'delaydetector'
self.sw_module = lookup_service_brick('switches')
self.awareness = lookup_service_brick('awareness')

self.datapaths = {}
self.echo_latency = {}
self.measure_thread = hub.spawn(self._detector)

@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 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 _detector(self):
while CONF.weight == 'delay':
self.create_link_delay()
try:
self.awareness.shortest_paths = {}
self.logger.debug("Refresh the shortest_paths")
except:
self.awareness = lookup_service_brick('awareness')

self.show_delay_statis()
self._send_echo_request()
hub.sleep(setting.DELAY_DETECTING_PERIOD)

def _send_echo_request(self):
for datapath in self.datapaths.values():
parser = datapath.ofproto_parser
data = "%.6f" % time.time()
echo_req = parser.OFPEchoRequest(datapath, data=data)
datapath.send_msg(echo_req)

@set_ev_cls(ofp_event.EventOFPEchoReply, MAIN_DISPATCHER)
def echo_reply_handler(self, ev):
try:
latency = time.time() - eval(ev.msg.data)
self.echo_latency[ev.msg.datapath.id] = latency
except:
return

def get_dalay(self, src, dst):
try:
fwd_delay = self.awareness.graph[src][dst]['lldpdelay']
re_delay = self.awareness.graph[dst][src]['lldpdelay']
src_latency = self.echo_latency[src]
dst_latency = self.echo_latency[dst]

delay = (fwd_delay + re_delay - src_latency - dst_latency)/2
return max(delay, 0)
except:
return float('inf')

def _save_lldp_delay(self, src=0, dst=0, lldpdelay=0):
try:
self.awareness.graph[src][dst]['lldpdelay'] = lldpdelay
except:
if self.awareness is None:
self.awareness = lookup_service_brick('awareness')
return

def create_link_delay(self):
try:
for src in self.awareness.graph:
for dst in self.awareness.graph[src]:
if src == dst:
self.awareness.graph[src][dst]['delay'] = 0
continue
delay = self.get_dalay(src, dst)
self.awareness.graph[src][dst]['delay'] = delay
except:
if self.awareness is None:
self.awareness = lookup_service_brick('awareness')
return

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
try:
src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data)
dpid = msg.datapath.id
in_port = msg.match['in_port']
if self.sw_module is None:
self.sw_module = lookup_service_brick('switches')

for port in self.sw_module.ports.keys():
if src_dpid == port.dpid and src_port_no == port.port_no:
port_data = self.sw_module.ports[port]
timestamp = port_data.timestamp
if timestamp:
delay = time.time() - timestamp
self._save_lldp_delay(src=src_dpid, dst=dpid,
lldpdelay=delay)
except LLDPPacket.LLDPUnknownFormat as e:
return

def show_delay_statis(self):
if setting.TOSHOW and self.awareness is not None:
self.logger.info("\nsrc dst delay")
self.logger.info("---------------------------")
for src in self.awareness.graph:
for dst in self.awareness.graph[src]:
delay = self.awareness.graph[src][dst]['delay']
self.logger.info("%s<-->%s : %s" % (src, dst, delay))
Loading

0 comments on commit 0859b86

Please sign in to comment.