LEFT | RIGHT |
1 # ~/ryu$ PYTHONPATH= ./bin/ryu-manager ryu/app/cpm_13.py --observe-links | 1 # ~/ryu$ PYTHONPATH= ./bin/ryu-manager ryu/app/cpm_13.py --observe-links |
2 | 2 |
3 from ryu.ofproto import ofproto_v1_3 | 3 from ryu.ofproto import ofproto_v1_3 |
4 from ryu.app import simple_switch_13 | 4 from ryu.app import simple_switch_13 |
5 from ryu.controller.handler import set_ev_cls | 5 from ryu.controller.handler import set_ev_cls |
6 from ryu.topology import event, switches | 6 from ryu.topology import event, switches |
7 from ryu.topology.api import get_switch, get_link | 7 from ryu.topology.api import get_switch, get_link |
8 from ryu.controller import ofp_event | 8 from ryu.controller import ofp_event |
9 from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER | 9 from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER |
10 from ryu.lib.packet import packet | 10 from ryu.lib.packet import packet |
11 from ryu.lib.packet import arp | 11 from ryu.lib.packet import arp |
12 from ryu.lib.packet import ethernet | 12 from ryu.lib.packet import ethernet |
13 from ryu.lib.packet import ether_types | 13 from ryu.lib.packet import ether_types |
14 from ryu.lib.packet import ipv4 | 14 from ryu.lib.packet import ipv4 |
15 from ryu.lib.packet import icmp | 15 from ryu.lib.packet import icmp |
16 from ryu.lib.packet import udp | 16 from ryu.lib.packet import udp |
17 from ryu.lib.packet import tcp | 17 from ryu.lib.packet import tcp |
18 from ryu.lib import hub | 18 from ryu.lib import hub |
19 import time | 19 import time |
20 from my_http_client import MyHTTPClient | 20 from my_http_client import MyHTTPClient |
21 | 21 |
22 | 22 |
23 class CPM13(simple_switch_13.SimpleSwitch13): | 23 class CPM13(simple_switch_13.SimpleSwitch13): |
24 "CPM module for topology discovery and SPF" | 24 "CPM module for topology discovery and SPF" |
25 | 25 |
26 OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] | 26 OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] |
27 | 27 |
28 def __init__(self, *args, **kwargs): | 28 def __init__(self, *args, **kwargs): |
29 super(CPM13, self).__init__(*args, **kwargs) | 29 super(CPM13, self).__init__(*args, **kwargs) |
| 30 self.fib = {} # 2017-11-18 |
30 self.topo_links = {} | 31 self.topo_links = {} |
31 self.switches = {} | 32 self.switches = {} |
32 self.neighbor_ports = {} # Temp 2017-10-02 | 33 self.neighbor_ports = {} # Temp 2017-10-02 |
33 self.port_metric = {} # 2017-10-16 | 34 self.port_metric = {} # 2017-10-16 |
34 self.hosts = {} | 35 self.hosts = {} |
35 self.hosts_temp_ban = {} # 2017-10-17 | |
36 self.sample_interval = 30 # How often to query the DM | 36 self.sample_interval = 30 # How often to query the DM |
37 self.ref_bw = 100000000.0 # 100 Mbps; Reference Bandwidth in Bps | 37 self.ref_bw = 100000000.0 # 100 Mbps; Reference Bandwidth in Bps |
38 self.ref_hc = 30.0 # 30 Hops; Reference Hop Count | 38 self.ref_hc = 30.0 # 30 Hops; Reference Hop Count |
39 # Connect with DM: | 39 # Connect with DM: |
40 self.dm_server = MyHTTPClient('http://192.16.125.183/API_REST/request.ph
p/get?') | 40 self.dm_server = MyHTTPClient('http://192.16.125.183/API_REST/request.ph
p/get?') |
41 self.port_counters_snapshot = {'object_index': 1000, 'switches': []} | 41 self.port_counters_snapshot = {'object_index': 1000, 'switches': []} |
42 self.get_dm_data_thread = hub.spawn(self._get_dm_data) | 42 hub.spawn(self._get_dm_data) |
| 43 |
| 44 # Connect with DM#2; need a second object of MyHTTPClient as |
| 45 # URL for POST requests is different. |
| 46 self.dm_server_2 = MyHTTPClient('http://192.16.125.183/API_REST/request.
php')· |
43 | 47 |
44 def _get_dm_data(self): | 48 def _get_dm_data(self): |
45 while True: | 49 while True: |
46 # Ask for DM data every self.sample_interval seconds: | 50 # Ask for DM data every self.sample_interval seconds: |
47 hub.sleep(self.sample_interval) | 51 hub.sleep(self.sample_interval) |
48 #body = self.dm_server.get_data_from_dm('port_counters', 1) | 52 #body = self.dm_server.get_data_from_dm('port_counters', 1) |
49 params_dict = {'module': 'nfm', 'row': 1, 'table': 'port_counters'} | 53 params_dict = {'module': 'nfm', 'row': 1, 'table': 'port_counters'} |
50 body = self.dm_server.send_GET(params_dict) | 54 body = self.dm_server.send_GET(params_dict) |
51 #print body | 55 #print body |
52 if body is None: # This is True if NO json in HTTP reponse | 56 if body is None: # This is True if NO json in HTTP reponse |
53 print 'No NFM monitoring data received from DM' | 57 print 'No NFM monitoring data received from DM' |
54 continue | 58 continue |
55 # print body | 59 # print body |
56 self._calculate_link_metric(body) | 60 self._calculate_link_metric(body) |
| 61 self._fib_update() |
| 62 |
| 63 def _fib_update(self): |
| 64 for (a, z) in self.fib.keys(): |
| 65 best_path = self._find_best_path(a, z) |
| 66 if self.fib[(a, z)] != best_path: |
| 67 self.fib[(a, z)] = best_path |
| 68 print '[UPDATED BEST PATH] ', a, '>', z, ':', self.fib[(a, z)] |
| 69 |
| 70 def _fib_lookup(self, src_switch, dst_switch): |
| 71 print self.fib |
| 72 print '[FIB LOOKUP]', (src_switch, dst_switch), self.fib[(src_switch, ds
t_switch)] |
| 73 return self.fib[(src_switch, dst_switch)] |
57 | 74 |
58 def _calculate_link_metric(self, data_dict): | 75 def _calculate_link_metric(self, data_dict): |
59 | 76 |
60 for switch in data_dict['switches']: | 77 for switch in data_dict['switches']: |
61 # each element is a dictionary as well | 78 # each element is a dictionary as well |
62 for port_counter in switch['port_counters']: | 79 for port_counter in switch['port_counters']: |
63 # each element is a dictionary as well | 80 # each element is a dictionary as well |
64 | 81 |
65 tx_metric = float(port_counter['tx_bw']) / self.ref_bw | 82 tx_metric = float(port_counter['tx_bw']) / self.ref_bw |
| 83 |
| 84 # Round to 3 decimal points |
| 85 # https://docs.python.org/2.7/library/functions.html#round |
| 86 tx_metric = round(tx_metric, 3) |
66 | 87 |
67 self.port_metric[(switch['switch_dpid'], | 88 self.port_metric[(switch['switch_dpid'], |
68 port_counter['port'])] = tx_metric | 89 port_counter['port'])] = tx_metric |
69 | 90 |
70 #print '[CALC] Port Metric', (switch['switch_dpid'], port_counte
r['port']), 'set to', tx_metric | 91 #print '[CALC] Port Metric', (switch['switch_dpid'], port_counte
r['port']), 'set to', tx_metric |
71 | 92 |
72 def _calculate_hop_count(self, paths): | 93 def _calculate_hop_count(self, paths): |
73 paths_dict = {} | 94 paths_dict = {} |
74 | 95 |
75 for path in paths: | 96 for path in paths: |
(...skipping 13 matching lines...) Expand all Loading... |
89 # v is the current switch dpid | 110 # v is the current switch dpid |
90 # path[k + 1] is the dpid of the next switch in path | 111 # path[k + 1] is the dpid of the next switch in path |
91 (tx_port, _) = self.neighbor_ports[(v, path[k + 1])] | 112 (tx_port, _) = self.neighbor_ports[(v, path[k + 1])] |
92 # Find busiest port in path: | 113 # Find busiest port in path: |
93 if worst_metric < self.port_metric[(v, tx_port)]: | 114 if worst_metric < self.port_metric[(v, tx_port)]: |
94 worst_metric = self.port_metric[(v, tx_port)] | 115 worst_metric = self.port_metric[(v, tx_port)] |
95 paths_dict[path] = worst_metric | 116 paths_dict[path] = worst_metric |
96 | 117 |
97 return paths_dict | 118 return paths_dict |
98 | 119 |
| 120 def _deny_flow(self, datapath, in_port, pkt_in, hard_timeout=1): |
| 121 ofproto = datapath.ofproto |
| 122 parser = datapath.ofproto_parser |
| 123 |
| 124 match_args = self._parse_ip_packet_headers(pkt_in) |
| 125 match_args['in_port'] = in_port |
| 126 |
| 127 # https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument
-lists |
| 128 match = parser.OFPMatch(**match_args) |
| 129 |
| 130 inst = [parser.OFPInstructionActions( |
| 131 ofproto.OFPIT_CLEAR_ACTIONS, [])] |
| 132 mod = parser.OFPFlowMod(datapath=datapath, priority=65535, |
| 133 match=match, instructions=inst, |
| 134 hard_timeout=hard_timeout) |
| 135 datapath.send_msg(mod) |
| 136 |
99 @set_ev_cls(event.EventSwitchEnter) | 137 @set_ev_cls(event.EventSwitchEnter) |
100 def _handle_new_switch(self, ev): | 138 def _handle_new_switch(self, ev): |
101 # Gives the ryu.controller.controller.Datapath object of the switch: | 139 # Gives the ryu.controller.controller.Datapath object of the switch: |
102 # print ev.switch.dp | 140 # print ev.switch.dp |
103 new_switch = ev.switch.dp | 141 new_switch = ev.switch.dp |
104 self.switches[new_switch.id] = ev.switch.dp | 142 self.switches[new_switch.id] = ev.switch.dp |
105 self.topo_links[new_switch.id] = [] | 143 self.topo_links[new_switch.id] = [] |
106 | 144 |
107 @set_ev_cls(event.EventLinkAdd) | 145 @set_ev_cls(event.EventLinkAdd) |
108 def _handle_new_link(self, ev): | 146 def _handle_new_link(self, ev): |
(...skipping 18 matching lines...) Expand all Loading... |
127 # print 'Neighbors', self.topo_links | 165 # print 'Neighbors', self.topo_links |
128 | 166 |
129 # Temp 2017-10-02 | 167 # Temp 2017-10-02 |
130 self.neighbor_ports[(switchA.dpid, switchB.dpid)] = ( | 168 self.neighbor_ports[(switchA.dpid, switchB.dpid)] = ( |
131 switchA.port_no, switchB.port_no) | 169 switchA.port_no, switchB.port_no) |
132 # print 'Ports', self.neighbor_ports | 170 # print 'Ports', self.neighbor_ports |
133 | 171 |
134 # 2017-10-16 | 172 # 2017-10-16 |
135 self.port_metric[(switchA.dpid, switchA.port_no)] = 0 | 173 self.port_metric[(switchA.dpid, switchA.port_no)] = 0 |
136 #print 'Port Metric', (switchA.dpid, switchA.port_no), 'set to', 0 | 174 #print 'Port Metric', (switchA.dpid, switchA.port_no), 'set to', 0 |
| 175 |
| 176 # 2017-11-16 |
| 177 # Inform DM about this link |
| 178 new_topo_link_json_obj = {'src_switch': switchA.dpid, |
| 179 'src_sw_port': switchA.port_no, |
| 180 'dst_switch': switchB.dpid, |
| 181 'dst_sw_port': switchB.port_no, |
| 182 'module': 'topology', |
| 183 'event': 'link_up', |
| 184 'bandwidth': 100000} |
| 185 self.dm_server_2.send_POST(new_topo_link_json_obj) |
| 186 |
137 | 187 |
138 # https://www.python.org/doc/essays/graphs/ | 188 # https://www.python.org/doc/essays/graphs/ |
139 def _find_all_paths(self, neighbors, start, end, path=[]): | 189 def _find_all_paths(self, neighbors, start, end, path=[]): |
140 path = path + [start] | 190 path = path + [start] |
141 if start == end: | 191 if start == end: |
142 return [path] | 192 return [path] |
143 if start not in neighbors.keys(): | 193 if start not in neighbors.keys(): |
144 return [] | 194 return [] |
145 paths = [] | 195 paths = [] |
146 for node in neighbors[start]: | 196 for node in neighbors[start]: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 best_metric = 100000000000 # Just an Arbitrary high value. | 231 best_metric = 100000000000 # Just an Arbitrary high value. |
182 # Lowest metric means best metric! (0 is the best possible) | 232 # Lowest metric means best metric! (0 is the best possible) |
183 best_path = [] | 233 best_path = [] |
184 for path in all_paths: | 234 for path in all_paths: |
185 composite_metric = w1 * hop_count[path] | 235 composite_metric = w1 * hop_count[path] |
186 composite_metric += w2 * nfm_metric[path] | 236 composite_metric += w2 * nfm_metric[path] |
187 if composite_metric < best_metric: | 237 if composite_metric < best_metric: |
188 best_metric = composite_metric | 238 best_metric = composite_metric |
189 best_path = path | 239 best_path = path |
190 | 240 |
191 print 'BEST PATH between', (src_switch, dst_switch), 'is', best_path | 241 #print 'BEST PATH between', (src_switch, dst_switch), 'is', best_path |
192 print 'with Composite metric', best_metric | 242 #print 'with Composite metric', best_metric |
193 | 243 |
194 return list(best_path) | 244 #return list(best_path) |
| 245 return best_path |
195 | 246 |
196 def _add_network_uni_flow(self, path, pkt, buffer_id=None): | 247 def _add_network_uni_flow(self, path, pkt, buffer_id=None): |
197 pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) | 248 pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) |
198 ip_src = pkt_ipv4.src | 249 ip_src = pkt_ipv4.src |
199 | 250 |
200 # input argument "path" is a list of switches; each item is a dpid | 251 # input argument "path" is a tuple of switches; each item is a dpid |
201 # First I need to find the ports of the two switches: | 252 # First I need to find the ports of the two switches: |
| 253 print 'path', path |
202 if len(path) == 1: | 254 if len(path) == 1: |
203 print 'Hosts are on same switch', path[0] | 255 print 'Hosts are on same switch', path[0] |
204 return | 256 return |
205 | 257 |
206 # Install flows from A >> Z in the reverse order, i.e. | 258 # Install flows from A >> Z in the reverse order, i.e. |
207 # from End to Start. | 259 # from End to Start. |
208 path.reverse() | 260 path = path[::-1] # New tuple with reversed order of items |
| 261 |
209 ip_dst = pkt_ipv4.dst | 262 ip_dst = pkt_ipv4.dst |
210 hostZ = self.hosts[ip_dst] # dst host | 263 hostZ = self.hosts[ip_dst] # dst host |
211 out_port = hostZ['port'] | 264 out_port = hostZ['port'] |
212 | 265 |
213 for k, v in enumerate(path[:-1]): | 266 for k, v in enumerate(path[:-1]): |
214 (in_port, new_out_port) = self.neighbor_ports[( | 267 (in_port, new_out_port) = self.neighbor_ports[( |
215 v, path[k + 1])] | 268 v, path[k + 1])] |
216 | 269 |
217 switch = self.switches[v] | 270 switch = self.switches[v] |
218 | 271 |
219 self._add_switch_uni_flow( | 272 self._add_switch_uni_flow( |
220 switch, in_port, out_port, pkt) | 273 switch, in_port, out_port, pkt) |
221 | 274 |
222 out_port = new_out_port | 275 out_port = new_out_port |
223 | 276 |
224 ip_src = pkt_ipv4.src | 277 ip_src = pkt_ipv4.src |
225 hostA = self.hosts[ip_src] # src host | 278 hostA = self.hosts[ip_src] # src host |
226 in_port = hostA['port'] | 279 in_port = hostA['port'] |
| 280 |
227 self._add_switch_uni_flow(self.switches[path[-1]], | 281 self._add_switch_uni_flow(self.switches[path[-1]], |
228 in_port, out_port, pkt, buffer_id) | 282 in_port, out_port, pkt, buffer_id) |
229 | 283 |
230 def _add_switch_uni_flow(self, datapath, in_port, out_port, pkt, buffer_id=N
one): | 284 def _add_switch_uni_flow(self, datapath, in_port, out_port, pkt, buffer_id=N
one): |
231 parser = datapath.ofproto_parser | 285 parser = datapath.ofproto_parser |
232 | 286 |
| 287 match_args = self._parse_ip_packet_headers(pkt) |
| 288 |
| 289 match_args['in_port'] = in_port |
| 290 |
| 291 if match_args['ip_proto'] == 1: |
| 292 # ICMP |
| 293 priority = 200 |
| 294 |
| 295 elif match_args['ip_proto'] == 6: |
| 296 # TCP |
| 297 # Add src and dst port |
| 298 priority = 400 |
| 299 |
| 300 elif match_args['ip_proto'] == 17: |
| 301 # UDP |
| 302 # Add src and dst port |
| 303 priority = 300 |
| 304 |
| 305 else: |
| 306 priority = 100 # Priority for everything else |
| 307 |
| 308 # https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument
-lists |
| 309 match = parser.OFPMatch(**match_args) |
| 310 self.logger.info('%8d %8d %17s %17s %17s %17s %8d %8d %8d', |
| 311 datapath.id, |
| 312 in_port, |
| 313 match_args['eth_src'], match_args['ipv4_src'], |
| 314 match_args['eth_dst'], match_args['ipv4_dst'], |
| 315 out_port, |
| 316 match_args['ip_proto'], priority) |
| 317 |
| 318 actions = [parser.OFPActionOutput(out_port)] |
| 319 |
| 320 if buffer_id is not None: |
| 321 time.sleep(1) # Delay for FlowMod to ingress switch |
| 322 # This is to ensure that the client packet won't be forwarded |
| 323 # to next (transit) switch before it has already processed |
| 324 # the FlowMod sent to it. |
| 325 # See while loop in function _add_network_uni_flow() |
| 326 |
| 327 self.add_flow(datapath, priority, match, actions, buffer_id) |
| 328 |
| 329 def _parse_ip_packet_headers(self, pkt): |
233 # The following headers are available to all IPv4 packets | 330 # The following headers are available to all IPv4 packets |
234 pkt_ethernet = pkt.get_protocol(ethernet.ethernet) | 331 pkt_ethernet = pkt.get_protocol(ethernet.ethernet) |
235 pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) | 332 pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) |
236 eth_type = pkt_ethernet.ethertype | 333 eth_type = pkt_ethernet.ethertype |
237 eth_src = pkt_ethernet.src | 334 eth_src = pkt_ethernet.src |
238 ip_src = pkt_ipv4.src | 335 ip_src = pkt_ipv4.src |
239 eth_dst = pkt_ethernet.dst | 336 eth_dst = pkt_ethernet.dst |
240 ip_dst = pkt_ipv4.dst | 337 ip_dst = pkt_ipv4.dst |
241 ip_proto = pkt_ipv4.proto # 1 for ICMP | 338 ip_proto = pkt_ipv4.proto # 1 for ICMP, 6 for TCP, 17 for UDP |
242 # | 339 |
243 | 340 match_args = { |
244 priority = 100 | 341 'eth_type': eth_type, |
245 match = parser.OFPMatch( | 342 'eth_src': eth_src, |
246 in_port=in_port, | 343 'ipv4_src': ip_src, |
247 eth_type=eth_type, | 344 'eth_dst': eth_dst, |
248 eth_src=eth_src, | 345 'ipv4_dst': ip_dst, |
249 ipv4_src=ip_src, | 346 'ip_proto': ip_proto |
250 eth_dst=eth_dst, | 347 } |
251 ipv4_dst=ip_dst, | 348 |
252 ip_proto=ip_proto | 349 if ip_proto == 1: |
253 ) | 350 # ICMP |
254 self.logger.info('%8d %8d %17s %17s %17s %17s %8d %8d %8d', | 351 # No other match argument needed |
255 datapath.id, | 352 pass |
256 in_port, eth_src, ip_src, | 353 |
257 eth_dst, ip_dst, out_port, | 354 elif ip_proto == 6: |
258 ip_proto, priority) | 355 # TCP |
259 | 356 # Add src and dst port |
260 actions = [parser.OFPActionOutput(out_port)] | 357 pkt_tcp = pkt.get_protocol(tcp.tcp) |
261 self.add_flow(datapath, priority, match, actions, buffer_id) | 358 match_args['tcp_src'] = pkt_tcp.src_port |
| 359 match_args['tcp_dst'] = pkt_tcp.dst_port |
| 360 |
| 361 elif ip_proto == 17: |
| 362 # UDP |
| 363 # Add src and dst port |
| 364 pkt_udp = pkt.get_protocol(udp.udp) |
| 365 match_args['udp_src'] = pkt_udp.src_port |
| 366 match_args['udp_dst'] = pkt_udp.dst_port |
| 367 |
| 368 else: |
| 369 # Everything else |
| 370 pass |
| 371 |
| 372 return match_args |
262 | 373 |
263 # Taken from Ryu book page 88: | 374 # Taken from Ryu book page 88: |
264 def _send_packet(self, datapath, port, pkt): | 375 def _send_packet(self, datapath, port, pkt): |
265 ofproto = datapath.ofproto | 376 ofproto = datapath.ofproto |
266 parser = datapath.ofproto_parser | 377 parser = datapath.ofproto_parser |
267 pkt.serialize() | 378 pkt.serialize() |
268 self.logger.debug("packet-out %s" % (pkt,)) | 379 self.logger.debug("packet-out %s" % (pkt,)) |
269 data = pkt.data | 380 data = pkt.data |
270 actions = [parser.OFPActionOutput(port=port)] | 381 actions = [parser.OFPActionOutput(port=port)] |
271 out = parser.OFPPacketOut(datapath=datapath, | 382 out = parser.OFPPacketOut(datapath=datapath, |
(...skipping 19 matching lines...) Expand all Loading... |
291 pkt_out.add_protocol(ethernet.ethernet( | 402 pkt_out.add_protocol(ethernet.ethernet( |
292 ethertype=pkt_in_ether.ethertype, | 403 ethertype=pkt_in_ether.ethertype, |
293 dst=pkt_in_ether.src, src=src_mac)) | 404 dst=pkt_in_ether.src, src=src_mac)) |
294 pkt_out.add_protocol(arp.arp(opcode=arp.ARP_REPLY, | 405 pkt_out.add_protocol(arp.arp(opcode=arp.ARP_REPLY, |
295 src_mac=src_mac, | 406 src_mac=src_mac, |
296 src_ip=pkt_in_arp.dst_ip, | 407 src_ip=pkt_in_arp.dst_ip, |
297 dst_mac=pkt_in_arp.src_mac, | 408 dst_mac=pkt_in_arp.src_mac, |
298 dst_ip=pkt_in_arp.src_ip)) | 409 dst_ip=pkt_in_arp.src_ip)) |
299 self._send_packet(datapath, in_port, pkt_out) | 410 self._send_packet(datapath, in_port, pkt_out) |
300 | 411 |
301 def _handle_new_host(self, datapath, switch_port, host_mac): | 412 def _handle_new_host(self, datapath, switch_port, host_mac, host_ip): |
| 413 # Update fib 2017-11-18 |
| 414 switches_with_hosts = [] |
| 415 for ip, params in self.hosts.items(): |
| 416 if params['switch'] not in switches_with_hosts: |
| 417 switches_with_hosts.append(params['switch']) |
| 418 for switch in switches_with_hosts: |
| 419 if switch == datapath.id: |
| 420 # Same switch, no need to add to FIB |
| 421 continue |
| 422 if (switch, datapath.id) not in self.fib: |
| 423 self.fib[(switch, datapath.id)] = self._find_best_path(switch, d
atapath.id) |
| 424 print self.fib |
| 425 if (datapath.id, switch) not in self.fib: |
| 426 self.fib[(datapath.id, switch)] = self._find_best_path(datapath.
id, switch) |
| 427 print self.fib |
| 428 |
| 429 # Add new host to host dict |
| 430 self.hosts[host_ip] = {'mac': host_mac, |
| 431 'switch': datapath.id, |
| 432 'port': switch_port} |
| 433 |
| 434 print "[DISCOVERED NEW HOST]", host_ip, self.hosts[host_ip] |
| 435 |
| 436 # Add flow on this switch, point to NEW HOST: |
302 parser = datapath.ofproto_parser | 437 parser = datapath.ofproto_parser |
303 match = parser.OFPMatch(eth_dst=host_mac) | 438 match = parser.OFPMatch(eth_dst=host_mac) |
304 actions = [parser.OFPActionOutput(switch_port)] | 439 actions = [parser.OFPActionOutput(switch_port)] |
305 self.add_flow(datapath, 50, match, actions) | 440 self.add_flow(datapath, 50, match, actions) |
306 | 441 |
307 @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) | 442 @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) |
308 def _packet_in_handler(self, ev): | 443 def _packet_in_handler(self, ev): |
309 # If you hit this you might want to increase | 444 # If you hit this you might want to increase |
310 # the "miss_send_length" of your switch | 445 # the "miss_send_length" of your switch |
311 if ev.msg.msg_len < ev.msg.total_len: | 446 if ev.msg.msg_len < ev.msg.total_len: |
312 self.logger.debug("packet truncated: only %s of %s bytes", | 447 self.logger.debug("packet truncated: only %s of %s bytes", |
313 ev.msg.msg_len, ev.msg.total_len) | 448 ev.msg.msg_len, ev.msg.total_len) |
314 | 449 |
315 msg = ev.msg | 450 msg = ev.msg |
316 datapath = msg.datapath | 451 datapath = msg.datapath |
317 in_port = msg.match['in_port'] | 452 in_port = msg.match['in_port'] |
318 | 453 |
319 pkt = packet.Packet(msg.data) | 454 pkt = packet.Packet(msg.data) |
320 eth = pkt.get_protocols(ethernet.ethernet)[0] | 455 eth = pkt.get_protocols(ethernet.ethernet)[0] |
321 | 456 |
322 if eth.ethertype == ether_types.ETH_TYPE_LLDP: | 457 if eth.ethertype == ether_types.ETH_TYPE_LLDP: |
323 # ignore lldp packet | 458 # ignore lldp packet |
324 return | 459 return |
325 | 460 |
326 print 'PACKET IN >>', datapath.id, in_port | 461 #print 'PACKET IN >>', datapath.id, in_port |
327 self.logger.debug("packet-in %s" % (pkt,)) | 462 self.logger.debug("packet-in %s" % (pkt,)) |
328 | 463 |
329 dpid = datapath.id | 464 dpid = datapath.id |
330 | 465 |
331 # self.hosts = {'10.0.0.1': {'mac': '00:00:00:00:00:01', 'switch': 11, '
port': 1}, | 466 # self.hosts = {'10.0.0.1': {'mac': '00:00:00:00:00:01', 'switch': 11, '
port': 1}, |
332 # '10.0.0.2': {'mac': '00:00:00:00:00:02', 'switch': 13, 'p
ort': 2}} | 467 # '10.0.0.2': {'mac': '00:00:00:00:00:02', 'switch': 13, 'p
ort': 2}} |
333 | 468 |
334 # Handle ARP Request packets: | 469 # Handle ARP Request packets: |
335 pkt_arp = pkt.get_protocol(arp.arp) | 470 pkt_arp = pkt.get_protocol(arp.arp) |
336 if pkt_arp: | 471 if pkt_arp: |
337 # Inspired by Ryu book page 88 | 472 # Inspired by Ryu book page 88 |
338 if pkt_arp: | 473 if pkt_arp: |
339 if pkt_arp.opcode != arp.ARP_REQUEST: | 474 if pkt_arp.opcode != arp.ARP_REQUEST: |
340 print 'Expected an ARP Request but this is not it.' | 475 print 'Expected an ARP Request but this is not it.' |
341 return | 476 return |
342 | 477 |
343 # Learn new source host: | 478 # Learn new source host: |
344 if pkt_arp.src_ip not in self.hosts: | 479 if pkt_arp.src_ip not in self.hosts: |
345 self.hosts[pkt_arp.src_ip] = { | 480 self._handle_new_host(datapath, in_port, eth.src, pkt_arp.sr
c_ip) |
346 'mac': eth.src, 'switch': dpid, 'port': in_port} | |
347 print "DISCOVERED NEW HOST", pkt_arp.src_ip, self.hosts[pkt_
arp.src_ip] | |
348 # Add flow on this switch, point to NEW HOST: | |
349 self._handle_new_host(datapath, in_port, eth.src) | |
350 return | 481 return |
351 | 482 |
352 # Reply to ARP request: | 483 # Reply to ARP request: |
353 if pkt_arp.dst_ip in self.hosts: | 484 if pkt_arp.dst_ip in self.hosts: |
354 self._handle_arp_request(datapath, in_port, pkt) | 485 self._handle_arp_request(datapath, in_port, pkt) |
355 return | 486 return |
356 | 487 |
357 # Handle IPv4 packets: | 488 # Handle IPv4 packets: |
358 pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) | 489 pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) |
359 if not pkt_ipv4: | 490 if not pkt_ipv4: |
360 print 'NOT an IPv4 Packet:' | 491 print 'NOT an IPv4 Packet:' |
361 self.logger.info("TABLE MISS: switch %s, packet-in %s", dpid, (pkt,)
) | 492 self.logger.info("TABLE MISS: switch %s, packet-in %s", dpid, (pkt,)
) |
362 return | 493 return |
363 else: | 494 else: |
| 495 # Block all similar future packets for 1 second: |
| 496 # self._deny_flow(datapath, in_port, pkt) |
| 497 |
364 dst_switch = self.hosts[pkt_ipv4.dst]['switch'] | 498 dst_switch = self.hosts[pkt_ipv4.dst]['switch'] |
365 # Find best path between (src_switch, dst_switch) | 499 # Find best path between (src_switch, dst_switch) |
366 best_path = self._find_best_path(dpid, dst_switch) | 500 # best_path = self._find_best_path(dpid, dst_switch) |
| 501 print datapath.id, in_port, pkt_ipv4.src, pkt_ipv4.dst |
| 502 best_path = self._fib_lookup(dpid, dst_switch) |
367 | 503 |
368 # Installing flows from A >> Z | 504 # Installing flows from A >> Z |
369 self._add_network_uni_flow(best_path, pkt, msg.buffer_id) | 505 self._add_network_uni_flow(best_path, pkt, msg.buffer_id) |
LEFT | RIGHT |