forked from wildan2711/multipath
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wmultipathy.py
255 lines (202 loc) · 7.72 KB
/
wmultipathy.py
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
from pyretic.lib.corelib import*
from pyretic.lib.std import *
from multiprocessing import Lock
from pyretic.lib.query import *
from collections import defaultdict
from requests import get
from subprocess import check_output
from thread import start_new_thread
import time
import os
import shlex
import json
import re
from datetime import datetime
byte = defaultdict(lambda: 0)
clock = defaultdict(lambda: 0)
thr = defaultdict(lambda: defaultdict(lambda: 0))
# switches
switches = []
switch_info = defaultdict(dict)
# myhost[srcmac]->(switch, port)
myhost = {}
topology_map = defaultdict(dict)
min_route = defaultdict(dict)
# adjacency map [sw1][sw2]->port from sw1 to sw2
adjacency = defaultdict(dict)
collector = '127.0.0.1'
# get interface name of ip address (collector)
def getIfInfo(ip):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((ip, 0))
ip = s.getsockname()[0]
ifconfig = check_output(['ifconfig'])
ifs = re.findall(r'^(\S+).*?inet addr:(\S+).*?', ifconfig, re.S | re.M)
for entry in ifs:
if entry[1] == ip:
return entry
def measure_link(thread):
# every second, we measure the incoming bytes for each port of the switch
while True:
for switch in switches:
for ifindex in switch_info[switch]['ifindex']:
url = 'http://' + collector + ':8008/metric/' + \
collector + '/' + ifindex + '.ifoutoctets/json'
r = get(url)
response = json.loads(r.content)
# print response
try:
thr[switch][ifindex] = response[0]['metricValue']
except KeyError:
pass
# print switch,thr[switch]
time.sleep(1)
def path_cost(route):
cost = 0
for s, p in route:
for i in thr[s]:
cost += thr[s][i]
return cost
def measure_path(thread):
while True:
for src in topology_map.keys():
for dst in topology_map[src].keys():
try:
min_route[src][dst] = min(
topology_map[src][dst], key=path_cost)
except KeyError:
pass
time.sleep(0.1)
def get_paths(src, dst, final_port):
# Depth-first search, find all paths from src to dst
try:
if topology_map[src][dst]:
return topology_map[src][dst]
except KeyError:
paths = []
stack = [(src, [src])]
while stack:
(node, path) = stack.pop()
for next in set(adjacency[node].keys()) - set(path):
if next is dst:
paths.append(path + [next])
else:
stack.append((next, path + [next]))
# Add the ports that connects the switches for all paths
paths_p = []
for path in paths:
r = []
for s1, s2 in zip(path[:-1], path[1:]):
out_port = adjacency[s1][s2]
r.append((s1, out_port))
r.append((dst, final_port))
paths_p.append(r)
topology_map[src][dst] = paths_p
print "Jalur yg tersedia : ", topology_map[src][dst]
return topology_map[src][dst]
def get_least_cost_route(src, dst, final_port):
if src is dst:
return [(dst, final_port)]
# generate all paths from src to dst
# get_paths(src, dst)
r = topology_map[src][dst]
route_costs = [{'route': [], 'cost':0} for k in range(len(r))]
for i in range(len(r)):
route_costs[i]['route'] = r[i]
for s, p in r[i]:
# get the total cost of every interface for switch
for ifindex in thr[s]:
route_costs[i]['cost'] += thr[s][ifindex]
# print route_costs
min_route = min(route_costs, key=lambda x: x['cost'])
if min_route['cost'] == 0:
min_route = min(route_costs, key=lambda x: len(x['route']))
return min_route['route'] + [(dst, final_port)]
class multipath_forwarding(DynamicPolicy):
def __init__(self, routes):
super(multipath_forwarding, self).__init__()
self.routes = routes
self.forward = flood()
self.index = 0
self.set_initial_state()
def set_initial_state(self):
self.query = packets(2, ['srcmac', 'dstmac', 'srcip', 'dstip'])
self.query.register_callback(self.forwarder)
self.update_policy()
def set_network(self, network):
self.set_initial_state()
def update_policy(self):
self.policy = self.forward + self.query
def forwarder(self, pkt):
path = self.routes[self.index % len(self.routes)]
print path
r1 = parallel([(match(switch=a, srcip=pkt['srcip'], dstip=pkt['dstip']) >> fwd(b))
for a, b in path])
# print r1
self.forward = if_(
match(dstip=pkt['dstip'], srcip=pkt['srcip']), r1, self.forward)
self.update_policy()
class find_route(DynamicPolicy):
def __init__(self):
super(find_route, self).__init__()
self.router = flood()
self.set_initial_state()
def set_initial_state(self):
self.query = query = packets(1, ['srcmac', 'dstmac', 'srcip', 'dstip'])
self.query.register_callback(self.myroute)
self.update_policy()
def update_policy(self):
self.policy = self.router + self.query
def myroute(self, pkt):
# print pkt['srcmac'], pkt['dstmac'], pkt['srcip'], pkt['dstip']
if (pkt['srcmac'] not in myhost.keys()) or (pkt['dstmac'] not in myhost.keys()):
return
paths = get_paths(myhost[pkt['srcmac']][0], myhost[
pkt['dstmac']][0], myhost[pkt['dstmac']][1])
self.router = self.router + multipath_forwarding(paths)
self.update_policy()
def find_host():
q = packets(1, ['srcmac'])
q.register_callback(mymac_learner)
return q
def mymac_learner(pkt):
# print pkt['srcmac'], pkt['dstmac'], pkt['switch'], pkt['inport']
if pkt['srcmac'] not in myhost.keys():
myhost[pkt['srcmac']] = (pkt['switch'], pkt['inport'])
class find_switch(DynamicPolicy):
def __init__(self):
self.last_topology = None
self.lock = Lock()
super(find_switch, self).__init__()
def init_sflow(self, ifname, collector, sampling, polling):
cmd = shlex.split('ip link show')
out = check_output(cmd)
info = re.findall('(\d+): ((s[0-9]+)-eth[0-9]+)', out)
sflow = 'ovs-vsctl -- --id=@sflow create sflow agent=%s target=\\"%s\\" sampling=%s polling=%s --' % (
ifname, collector, sampling, polling)
for ifindex, ifname, switch in info:
switch_info[int(switch[1:])]['ifindex'].append(ifindex)
switch_info[int(switch[1:])]['ifname'].append(ifname)
sflow += ' -- set bridge %s sflow=@sflow' % switch
print sflow
os.system(sflow)
# print switch_info
start_new_thread(measure_link, ("thread_measure_link",))
# start_new_thread(measure_path,("thread_measure_path",))
def set_network(self, network):
with self.lock:
for dpid in network.switch_list():
if dpid not in switches:
switches.append(dpid)
switch_info[dpid]['ifindex'] = []
switch_info[dpid]['ifname'] = []
for (s1, s2, data) in network.topology.edges(data=True):
adjacency[s1][s2] = data[s1]
adjacency[s2][s1] = data[s2]
self.last_topology = network.topology
if switches:
print switches
(ifname, agent) = getIfInfo(collector)
self.init_sflow(ifname, collector, 10, 10)
def main():
return (find_switch() + find_host() + find_route())