class SimpleSwitch13(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__(self, *args, **kwargs): super(SimpleSwitch13, self).__init__(*args, **kwargs) self.graph = DirectedGraph() def add_flow(self, datapath, priority, match, actions, buffer_id=None): ofproto = datapath.ofproto parser = datapath.ofproto_parser inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] if buffer_id: mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match=match, instructions=inst) else: mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst) datapath.send_msg(mod) def update_topology(self): self.graph = DirectedGraph() switch_list = get_switch(self) for switch in switch_list: self.graph.add_node(SwitchNode(switch.dp.id, switch)) links_list = get_link(self) for link in links_list: self.graph.add_edge(link.src.dpid, link.dst.dpid) print(self.graph) @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER) def _port_status_handler(self, ev): self.update_topology() @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def _packet_in_handler(self, ev): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) eth = pkt.get_protocol(ethernet.ethernet) # avoid broadcast from LLDP if eth.ethertype == 35020: return
class Graph_test(unittest.TestCase): def setUp(self): self.graph = DirectedGraph() def test_add_node(self): self.graph.add_node('A') self.assertTrue('A' in self.graph.nodes) with self.assertRaises(Already_there): self.graph.add_node('A') def test_add_edge(self): self.graph.add_edge('A', 'B') self.assertEqual(self.graph.nodes['A'], set('B')) self.assertEqual(self.graph.nodes['B'], set()) with self.assertRaises(Cant_follow_yourself): self.graph.add_edge('D', 'D') def test_get_neighbours(self): self.graph.add_edge('A', 'B') self.graph.add_edge('A', 'C') self.graph.add_edge('B', 'C') self.assertEqual(self.graph.nodes['A'], set(['B', 'C'])) self.assertEqual(self.graph.nodes['B'], set(['C'])) self.assertEqual(self.graph.nodes['C'], set()) def test_bfs(self): self.graph.add_edge('A', 'B') self.graph.add_edge('A', 'C') self.graph.add_edge('B', 'C') self.graph.add_edge('C', 'D') self.graph.add_node('E') self.assertEqual(self.graph.bfs('A'), set(['A', 'B', 'C', 'D'])) self.assertEqual(self.graph.bfs('E'), set(['E'])) self.assertEqual(self.graph.bfs('B'), set(['B', 'C', 'D'])) self.assertEqual(self.graph.bfs('C'), set(['D', 'C'])) self.assertEqual(self.graph.bfs('D'), set(['D'])) def test_path_between(self): self.graph.add_edge('A', 'B') self.graph.add_edge('A', 'C') self.graph.add_edge('B', 'C') self.graph.add_edge('C', 'D') self.graph.add_node('E') self.assertFalse(self.graph.path_between('B', 'A')) self.assertTrue(self.graph.path_between('A', 'D')) self.assertTrue(self.graph.path_between('A', 'C'))
class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13): _CONTEXTS = { 'wsgi': WSGIApplication, } def __init__(self, *args, **kwargs): super(SimpleSwitchRest13, self).__init__(*args, **kwargs) self.switches = {} wsgi = kwargs['wsgi'] wsgi.register(SimpleSwitchController, {simple_switch_instance_name: self}) self.graph = DirectedGraph() self.forwarding_tables = [] self.mac_to_port = {} def update_topology(self): self.graph = DirectedGraph() switch_list = get_switch(self) for switch in switch_list: self.graph.add_node(SwitchNode(switch.dp.id, switch)) links_list = get_link(self) for link in links_list: self.graph.add_edge(link.src.dpid, link.dst.dpid) print(self.graph) print(len(links_list)) print("test") def add_flow(self, datapath, priority, match, actions, buffer_id=None): ofproto = datapath.ofproto parser = datapath.ofproto_parser inst = [ parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) ] if buffer_id: mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match=match, instructions=inst) else: mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst) datapath.send_msg(mod) def _handle_arp(self, datapath, port, pkt_ethernet, pkt_arp, target_hw_addr, target_ip_addr): # see http://osrg.github.io/ryu-book/en/html/packet_lib.html if pkt_arp.opcode != arp.ARP_REQUEST: return pkt = packet.Packet() pkt.add_protocol( ethernet.ethernet(ethertype=pkt_ethernet.ethertype, dst=pkt_ethernet.src, src=target_hw_addr)) pkt.add_protocol( arp.arp(opcode=arp.ARP_REPLY, src_mac=target_hw_addr, src_ip=target_ip_addr, dst_mac=pkt_arp.src_mac, dst_ip=pkt_arp.src_ip)) self._send_packet(datapath, port, pkt) def _send_packet(self, datapath, port, pkt): ofproto = datapath.ofproto parser = datapath.ofproto_parser pkt.serialize() self.logger.info("To dpid {0} packet-out {1}".format(datapath.id, pkt)) data = pkt.data actions = [parser.OFPActionOutput(port=port)] out = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=ofproto.OFPP_CONTROLLER, actions=actions, data=data) datapath.send_msg(out) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def _packet_in_handler(self, ev): if ev.msg.msg_len < ev.msg.total_len: self.logger.debug("packet truncated: only %s of %s bytes", ev.msg.msg_len, ev.msg.total_len) msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) eth = pkt.get_protocols(ethernet.ethernet)[0] if eth.ethertype == ether_types.ETH_TYPE_LLDP: # ignore lldp packet return dst = eth.dst src = eth.src dpid = datapath.id pkt_arp = pkt.get_protocol(arp.arp) if pkt_arp: print(pkt_arp) d_ip = pkt_arp.dst_ip s_ip = pkt_arp.src_ip arp_table = None for entry in self.forwarding_tables: switch_id = entry['switch_id'] src_ip = entry['src_ip'] dst_ip = entry['dst_ip'] eth_src = entry["eth_src"] eth_dst = entry["eth_dst"] in_port = entry['in_port'] out_port = entry['out_port'] if dpid == switch_id and dst_ip == d_ip: arp_table = entry break if arp_table: self._handle_arp(datapath=datapath, port=in_port, pkt_ethernet=pkt.get_protocols( ethernet.ethernet)[0], pkt_arp=pkt_arp, target_hw_addr=arp_table["eth_dst"], target_ip_addr=d_ip) for entry in self.forwarding_tables: switch_id = entry['switch_id'] src_ip = entry['src_ip'] dst_ip = entry['dst_ip'] eth_src = entry["eth_src"] eth_dst = entry["eth_dst"] in_port = entry['in_port'] out_port = entry['out_port'] if dpid == switch_id and eth_src == src and eth_dst == dst: match = parser.OFPMatch(in_port=in_port, eth_dst=eth_dst, eth_src=eth_src) actions = [parser.OFPActionOutput(out_port)] self.add_flow(datapath, 1, match, actions) print(match) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): super(SimpleSwitchRest13, self).switch_features_handler(ev) datapath = ev.msg.datapath self.switches[datapath.id] = datapath self.mac_to_port.setdefault(datapath.id, {}) def set_mac_to_port(self, dpid, entry): mac_table = self.mac_to_port.setdefault(dpid, {}) datapath = self.switches.get(dpid) entry_port = entry['port'] entry_mac = entry['mac'] if datapath is not None: parser = datapath.ofproto_parser if entry_port not in mac_table.values(): for mac, port in mac_table.items(): # from known device to new device actions = [parser.OFPActionOutput(entry_port)] match = parser.OFPMatch(in_port=port, eth_dst=entry_mac) self.add_flow(datapath, 1, match, actions) # from new device to known device actions = [parser.OFPActionOutput(port)] match = parser.OFPMatch(in_port=entry_port, eth_dst=mac) self.add_flow(datapath, 1, match, actions) mac_table.update({entry_mac: entry_port}) return mac_table def find_src_dpid(self, src_addr): switch_list = get_all_switch(self) for switch in switch_list: port_list = switch.ports for port in port_list: if src_addr == port.hw_addr: print(port.hw_addr, port.dpid) return (port.hw_addr, port.dpid) # @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER) def _port_status_handler(self, ev): msg = ev.msg reason = msg.reason port_no = msg.desc.port_no ofproto = msg.datapath.ofproto print("links:") links = get_link(self) print(links) print("switches:") switches = get_switch(self) print(switches) print(" [", end='') for switch in switches: print(switch.dp.id, end='') print(",", end='') print("]") def remove_table_flows(self, datapath, table_id, match, instructions): ofproto = datapath.ofproto flow_mod = datapath.ofproto_parser.OFPFlowMod( datapath, 0, 0, table_id, ofproto.OFPFC_DELETE, 0, 0, 1, ofproto.OFPCML_NO_BUFFER, ofproto.OFPP_ANY, ofproto.OFPG_ANY, 0, match, instructions) return flow_mod
class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13): _CONTEXTS = { 'wsgi': WSGIApplication, } def __init__(self, *args, **kwargs): super(SimpleSwitchRest13, self).__init__(*args, **kwargs) self.switches = {} wsgi = kwargs['wsgi'] wsgi.register(SimpleSwitchController, {simple_switch_instance_name: self}) self.graph = DirectedGraph() self.forwarding_tables = [] self.mac_to_port = {} self.ip_to_mac = { "169.254.20.158": "b8:27:eb:17:0d:96", "169.254.173.130": "b8:27:eb:7f:7c:ea", "169.254.240.121": "b8:27:eb:81:61:47" } self.link_to_port = { (1, "169.254.20.158"): 2, (9, "169.254.173.130"): 16, (8, "169.254.240.121"): 2 } def update_topology(self): self.graph = DirectedGraph() switch_list = get_switch(self) for switch in switch_list: self.graph.add_node(SwitchNode(switch.dp.id, switch)) links_list = get_link(self) for link in links_list: self.graph.add_edge(link.src.dpid, link.dst.dpid) print(self.graph) print(len(links_list)) print("test") def add_flow(self, datapath, priority, match, actions, buffer_id=None): ofproto = datapath.ofproto parser = datapath.ofproto_parser inst = [ parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) ] if buffer_id: mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match=match, instructions=inst) else: mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst) datapath.send_msg(mod) def _handle_arp(self, datapath, port, pkt_ethernet, pkt_arp, target_hw_addr, target_ip_addr): # see http://osrg.github.io/ryu-book/en/html/packet_lib.html if pkt_arp.opcode != arp.ARP_REQUEST: return pkt = packet.Packet() pkt.add_protocol( ethernet.ethernet(ethertype=pkt_ethernet.ethertype, dst=pkt_ethernet.src, src=target_hw_addr)) pkt.add_protocol( arp.arp(opcode=arp.ARP_REPLY, src_mac=target_hw_addr, src_ip=target_ip_addr, dst_mac=pkt_arp.src_mac, dst_ip=pkt_arp.src_ip)) self._send_packet(datapath, port, pkt) def _send_packet(self, datapath, port, pkt): ofproto = datapath.ofproto parser = datapath.ofproto_parser pkt.serialize() self.logger.info("To dpid {0} packet-out {1}".format(datapath.id, pkt)) data = pkt.data actions = [parser.OFPActionOutput(port=port)] out = parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=ofproto.OFPP_CONTROLLER, actions=actions, data=data) datapath.send_msg(out) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def _packet_in_handler(self, ev): msg = ev.msg # print("#############################################") datapath = msg.datapath dpid = datapath.id parser = datapath.ofproto_parser ofproto = datapath.ofproto port = msg.match['in_port'] pkt = packet.Packet(data=msg.data) # self.logger.info("packet-in: %s" % (pkt,)) eth = pkt.get_protocols(ethernet.ethernet)[0] pkt_eth = pkt.get_protocol(ethernet.ethernet) if pkt_eth: dst_mac = pkt_eth.dst eth_type = pkt_eth.ethertype if eth.ethertype == ether_types.ETH_TYPE_LLDP: # ignore lldp packet return pkt_arp = pkt.get_protocol(arp.arp) if pkt_arp: print("datapath id: " + str(dpid)) print("port: " + str(port)) print("pkt_eth.dst: " + str(pkt_eth.dst)) print("pkt_eth.src: " + str(pkt_eth.src)) print("pkt_arp: " + str(pkt_arp)) print("pkt_arp:src_ip: " + str(pkt_arp.src_ip)) print("pkt_arp:dst_ip: " + str(pkt_arp.dst_ip)) print("pkt_arp:src_mac: " + str(pkt_arp.src_mac)) print("pkt_arp:dst_mac: " + str(pkt_arp.dst_mac)) # Destination and source ip address d_ip = pkt_arp.dst_ip s_ip = pkt_arp.src_ip # Destination and source mac address (HW address) d_mac = pkt_arp.dst_mac s_mac = pkt_arp.src_mac in_port = msg.match['in_port'] dst_addr = self.ip_to_mac[d_ip] self._handle_arp(datapath=datapath, port=in_port, pkt_ethernet=pkt.get_protocols( ethernet.ethernet)[0], pkt_arp=pkt_arp, target_hw_addr=dst_addr, target_ip_addr=d_ip) else: print("OTHER") print(pkt) for entry in self.forwarding_tables: switch_id = entry['switch_id'] src_ip = entry['src_ip'] dst_ip = entry['dst_ip'] out_port = entry['out_port'] if dpid == switch_id: match = parser.OFPMatch(ipv4_src=src_ip, ipv4_dst=dst_ip, eth_type=ether.ETH_TYPE_IP) actions = [parser.OFPActionOutput(out_port)] self.add_flow(datapath, 1, match, actions) print("MATCH:") print(match) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): super(SimpleSwitchRest13, self).switch_features_handler(ev) datapath = ev.msg.datapath self.switches[datapath.id] = datapath self.mac_to_port.setdefault(datapath.id, {}) def set_mac_to_port(self, dpid, entry): mac_table = self.mac_to_port.setdefault(dpid, {}) datapath = self.switches.get(dpid) entry_port = entry['port'] entry_mac = entry['mac'] if datapath is not None: parser = datapath.ofproto_parser if entry_port not in mac_table.values(): for mac, port in mac_table.items(): # from known device to new device actions = [parser.OFPActionOutput(entry_port)] match = parser.OFPMatch(in_port=port, eth_dst=entry_mac) self.add_flow(datapath, 1, match, actions) # from new device to known device actions = [parser.OFPActionOutput(port)] match = parser.OFPMatch(in_port=entry_port, eth_dst=mac) self.add_flow(datapath, 1, match, actions) mac_table.update({entry_mac: entry_port}) return mac_table def find_src_dpid(self, src_addr): switch_list = get_all_switch(self) for switch in switch_list: port_list = switch.ports for port in port_list: if src_addr == port.hw_addr: print(port.hw_addr, port.dpid) return (port.hw_addr, port.dpid) # @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER) def _port_status_handler(self, ev): msg = ev.msg reason = msg.reason port_no = msg.desc.port_no ofproto = msg.datapath.ofproto print("links:") links = get_link(self) print(links) print("switches:") switches = get_switch(self) print(switches) print(" [", end='') for switch in switches: print(switch.dp.id, end='') print(",", end='') print("]") def remove_table_flows(self, datapath, table_id, match, instructions): ofproto = datapath.ofproto flow_mod = datapath.ofproto_parser.OFPFlowMod( datapath, 0, 0, table_id, ofproto.OFPFC_DELETE, 0, 0, 1, ofproto.OFPCML_NO_BUFFER, ofproto.OFPP_ANY, ofproto.OFPG_ANY, 0, match, instructions) return flow_mod
class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13): _CONTEXTS = { 'wsgi': WSGIApplication, } def __init__(self, *args, **kwargs): super(SimpleSwitchRest13, self).__init__(*args, **kwargs) self.switches = {} wsgi = kwargs['wsgi'] wsgi.register(SimpleSwitchController, {simple_switch_instance_name: self}) self.graph = DirectedGraph() def update_topology(self): self.graph = DirectedGraph() switch_list = get_switch(self) for switch in switch_list: self.graph.add_node(SwitchNode(switch.dp.id, switch)) links_list = get_link(self) for link in links_list: self.graph.add_edge(link.src.dpid, link.dst.dpid) print(self.graph) print(len(links_list)) print("test") @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def _packet_in_handler(self, ev): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) eth = pkt.get_protocol(ethernet.ethernet) # avoid broadcast from LLDP if eth.ethertype == 35020: return print(pkt) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): super(SimpleSwitchRest13, self).switch_features_handler(ev) datapath = ev.msg.datapath self.switches[datapath.id] = datapath self.mac_to_port.setdefault(datapath.id, {}) def set_mac_to_port(self, dpid, entry): mac_table = self.mac_to_port.setdefault(dpid, {}) datapath = self.switches.get(dpid) entry_port = entry['port'] entry_mac = entry['mac'] if datapath is not None: parser = datapath.ofproto_parser if entry_port not in mac_table.values(): for mac, port in mac_table.items(): # from known device to new device actions = [parser.OFPActionOutput(entry_port)] match = parser.OFPMatch(in_port=port, eth_dst=entry_mac) self.add_flow(datapath, 1, match, actions) # from new device to known device actions = [parser.OFPActionOutput(port)] match = parser.OFPMatch(in_port=entry_port, eth_dst=mac) self.add_flow(datapath, 1, match, actions) mac_table.update({entry_mac: entry_port}) return mac_table def find_src_dpid(self, src_addr): switch_list = get_all_switch(self) for switch in switch_list: port_list = switch.ports for port in port_list: if src_addr == port.hw_addr: print(port.hw_addr, port.dpid) return (port.hw_addr, port.dpid) # @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER) def _port_status_handler(self, ev): msg = ev.msg reason = msg.reason port_no = msg.desc.port_no ofproto = msg.datapath.ofproto print("links:") links = get_link(self) print(links) print("switches:") switches = get_switch(self) print(switches) print(" [", end='') for switch in switches: print(switch.dp.id, end='') print(",", end='') print("]") def remove_table_flows(self, datapath, table_id, match, instructions): ofproto = datapath.ofproto flow_mod = datapath.ofproto_parser.OFPFlowMod( datapath, 0, 0, table_id, ofproto.OFPFC_DELETE, 0, 0, 1, ofproto.OFPCML_NO_BUFFER, ofproto.OFPP_ANY, ofproto.OFPG_ANY, 0, match, instructions) return flow_mod