From 1b248603f8ecc971a7d084b1e438030dc6df6446 Mon Sep 17 00:00:00 2001 From: structix Date: Mon, 16 May 2022 12:37:41 +0000 Subject: [PATCH] =?UTF-8?q?Dateien=20hochladen=20nach=20=E2=80=9E=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.2_simpleIPRouting | 195 ++++++++++++++++++++++++++++++ example.py | 280 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 475 insertions(+) create mode 100644 1.2_simpleIPRouting create mode 100644 example.py diff --git a/1.2_simpleIPRouting b/1.2_simpleIPRouting new file mode 100644 index 0000000..fc5061c --- /dev/null +++ b/1.2_simpleIPRouting @@ -0,0 +1,195 @@ +{ + "application": { + "dpctl": "", + "ipBase": "10.0.0.0/8", + "netflow": { + "nflowAddId": "0", + "nflowTarget": "", + "nflowTimeout": "600" + }, + "openFlowVersions": { + "ovsOf10": "0", + "ovsOf11": "0", + "ovsOf12": "0", + "ovsOf13": "1" + }, + "sflow": { + "sflowHeader": "128", + "sflowPolling": "30", + "sflowSampling": "400", + "sflowTarget": "" + }, + "startCLI": "1", + "switchType": "ovs", + "terminalType": "xterm" + }, + "controllers": [ + { + "opts": { + "controllerProtocol": "tcp", + "controllerType": "remote", + "hostname": "c0", + "remoteIP": "127.0.0.1", + "remotePort": 6633 + }, + "x": "734.0", + "y": "274.0" + } + ], + "hosts": [ + { + "number": "5", + "opts": { + "defaultRoute": "10.0.2.254", + "hostname": "h5", + "ip": "10.0.2.1/24", + "nodeNum": 5, + "sched": "host" + }, + "x": "114.0", + "y": "415.0" + }, + { + "number": "6", + "opts": { + "defaultRoute": "10.0.2.254", + "hostname": "h6", + "ip": "10.0.2.2/24", + "nodeNum": 6, + "sched": "host" + }, + "x": "253.0", + "y": "422.0" + }, + { + "number": "7", + "opts": { + "defaultRoute": "10.0.2.254", + "hostname": "h7", + "ip": "10.0.2.3/24", + "nodeNum": 7, + "sched": "host" + }, + "x": "431.0", + "y": "423.0" + }, + { + "number": "8", + "opts": { + "defaultRoute": "10.0.2.254", + "hostname": "h8", + "ip": "10.0.2.4/24", + "nodeNum": 8, + "sched": "host" + }, + "x": "547.0", + "y": "425.0" + }, + { + "number": "1", + "opts": { + "defaultRoute": "10.0.1.254", + "hostname": "h1", + "ip": "10.0.1.1/24", + "nodeNum": 1, + "sched": "host" + }, + "x": "128.0", + "y": "107.0" + }, + { + "number": "3", + "opts": { + "defaultRoute": "10.0.1.254", + "hostname": "h3", + "ip": "10.0.1.3/24", + "nodeNum": 3, + "sched": "host" + }, + "x": "412.0", + "y": "115.0" + }, + { + "number": "2", + "opts": { + "defaultRoute": "10.0.1.254", + "hostname": "h2", + "ip": "10.0.1.2/24", + "nodeNum": 2, + "sched": "host" + }, + "x": "263.0", + "y": "110.0" + }, + { + "number": "4", + "opts": { + "defaultRoute": "10.0.1.254", + "hostname": "h4", + "ip": "10.0.1.4/24", + "nodeNum": 4, + "sched": "host" + }, + "x": "541.0", + "y": "120.0" + } + ], + "links": [ + { + "dest": "s1", + "opts": {}, + "src": "h1" + }, + { + "dest": "s1", + "opts": {}, + "src": "h2" + }, + { + "dest": "s1", + "opts": {}, + "src": "h3" + }, + { + "dest": "s1", + "opts": {}, + "src": "h4" + }, + { + "dest": "s1", + "opts": {}, + "src": "h5" + }, + { + "dest": "s1", + "opts": {}, + "src": "h6" + }, + { + "dest": "s1", + "opts": {}, + "src": "h7" + }, + { + "dest": "s1", + "opts": {}, + "src": "h8" + } + ], + "switches": [ + { + "number": "1", + "opts": { + "controllers": [ + "c0" + ], + "hostname": "s1", + "nodeNum": 1, + "switchType": "default" + }, + "x": "300.0", + "y": "250.0" + } + ], + "version": "2" +} \ No newline at end of file diff --git a/example.py b/example.py new file mode 100644 index 0000000..82406b1 --- /dev/null +++ b/example.py @@ -0,0 +1,280 @@ +from ryu.base import app_manager +from ryu.controller import ofp_event +from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_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 ether_types +from ryu.lib.packet import ipv4 +from ryu.lib.packet import icmp +from ryu.lib.packet.arp import arp +from ryu.lib.packet.packet import Packet + +class L3Switch(app_manager.RyuApp): + OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] + + IP_ADDR = "10.0.0.254" + MAC_ADDR = "52:00:00:00:00:01" + + def __init__(self, *args, **kwargs): + super(L3Switch, self).__init__(*args, **kwargs) + self.mac_to_port = {} + self.ip_to_mac = {} + + @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 + + # install table-miss flow entry + # + # We specify NO BUFFER to max_len of the output action due to + # OVS bug. At this moment, if we specify a lesser number, e.g., + # 128, OVS will send Packet-In with invalid buffer_id and + # truncated packet data. In that case, we cannot output packets + # correctly. The bug has been fixed in OVS v2.1.0. + match = parser.OFPMatch() + actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, + ofproto.OFPCML_NO_BUFFER)] + self.add_flow(datapath, 0, match, actions) + + 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 send_packet(self, datapath, port, pkt, buffer_id=None): + ofproto = datapath.ofproto + parser = datapath.ofproto_parser + + pkt.serialize() + self.logger.info("packet-out %s" % (pkt,)) + data = pkt.data + + actions = [parser.OFPActionOutput(port=port)] + + if buffer_id: + out = parser.OFPPacketOut(datapath=datapath, + buffer_id=buffer_id, + in_port=ofproto.OFPP_CONTROLLER, + actions=actions, + data=data) + else: + out = parser.OFPPacketOut(datapath=datapath, + buffer_id=ofproto.OFP_NO_BUFFER, + in_port=ofproto.OFPP_CONTROLLER, + actions=actions, + data=data) + + datapath.send_msg(out) + + def do_arp(self, datapath, packet, frame, inPort): + dpid = datapath.id + ofproto = datapath.ofproto + parser = datapath.ofproto_parser + + arpPacket = packet.get_protocol(arp) + if arpPacket.opcode == 1 : + # arp request + arp_dstIp = arpPacket.dst_ip + self.logger.info('received ARP Request %s => %s (port%d)'%(frame.src, frame.dst, inPort)) + if arp_dstIp == self.IP_ADDR or arp_dstIp == "10.0.1.254" or arp_dstIp == "10.0.2.254": + # this switch was requested + opcode = 2 + srcMAC = self.MAC_ADDR + srcIP = arp_dstIp + dstMAC = frame.src + dstIP = arpPacket.src_ip + outPort = inPort + # learn mac 2 port mapping + self.mac_to_port[dpid][dstMAC] = inPort + # learn ip 2 mac mapping + self.ip_to_mac[dpid][dstIP] = dstMAC + self.logger.info("send ARP reply %s => %s (port%d)" %(srcMAC, dstMAC, outPort)) + else: + if arpPacket.dst_ip in self.ip_to_mac[dpid]: + # optimization: the switch already knows the mapping and can answer the request + opcode = 2 + srcMAC = self.ip_to_mac[dpid][arpPacket.dst_ip] + srcIP = arpPacket.dst_ip + dstMAC = frame.src + dstIP = arpPacket.src_ip + outPort = self.mac_to_port[dpid][dstMAC] + self.logger.info("optimization: answer ARP request %s => %s (port%d)" %(srcMAC, dstMAC, outPort)) + else: + # forward arp request + opcode = 1 + srcMAC = frame.src + srcIP = arpPacket.src_ip + dstMAC = frame.dst + dstIP = arpPacket.dst_ip + outPort = ofproto.OFPP_FLOOD + # learn mac 2 port mapping + self.mac_to_port[dpid][srcMAC] = inPort + # learn ip 2 mac mapping + self.ip_to_mac[dpid][srcIP] = srcMAC + self.logger.info("froward ARP request %s => %s (port%d)" %(srcMAC, dstMAC, outPort)) + elif arpPacket.opcode == 2 : + self.logger.info(arpPacket) + if arpPacket.dst_mac == self.MAC_ADDR: + # learn mac 2 port mapping + self.mac_to_port[dpid][arpPacket.src_mac] = inPort + # learn ip 2 mac mapping + self.ip_to_mac[dpid][arpPacket.src_ip] = arpPacket.src_mac + return + else: + opcode = 2 + #arp reply + # forward arp reply + srcMAC = frame.src + srcIP = arpPacket.src_ip + dstMAC = frame.dst + dstIP = arpPacket.dst_ip + outPort = self.mac_to_port[dpid][dstMAC] + # learn mac 2 port mapping + self.mac_to_port[dpid][srcMAC] = inPort + # learn ip 2 mac mapping + self.ip_to_mac[dpid][srcIP] = srcMAC + self.logger.debug('forward ARP reply %s => %s (port%d)'%(frame.src ,frame.dst, inPort)) + self.send_arp(datapath, opcode, srcMAC, srcIP, dstMAC, dstIP, outPort) + + def send_arp(self, datapath, opcode, srcMac, srcIp, dstMac, dstIp, outPort): + if opcode == 1: + targetMac = "FF:FF:FF:FF:FF:FF" + targetIp = dstIp + elif opcode == 2: + targetMac = dstMac + targetIp = dstIp + e = ethernet.ethernet(dstMac, srcMac, ether_types.ETH_TYPE_ARP) + a = arp(1, 0x0800, 6, 4, opcode, srcMac, srcIp, targetMac, targetIp) + p = Packet() + p.add_protocol(e) + p.add_protocol(a) + + self.send_packet(datapath, outPort, p) + + def do_icmp(self, datapath, port, pkt_ethernet, pkt_ipv4, pkt_icmp): + self.logger.info(pkt_icmp.type) + self.logger.info(icmp.ICMP_ECHO_REQUEST) + if pkt_icmp.type != icmp.ICMP_ECHO_REQUEST: + return + pkt = packet.Packet() + pkt.add_protocol(ethernet.ethernet(ethertype=pkt_ethernet.ethertype, + dst=pkt_ethernet.src, + src=self.MAC_ADDR)) + pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src, + src=self.IP_ADDR, + proto=pkt_ipv4.proto)) + pkt.add_protocol(icmp.icmp(type_=icmp.ICMP_ECHO_REPLY, + code=icmp.ICMP_ECHO_REPLY_CODE, + csum=0, + data=pkt_icmp.data)) + self.logger.info("do icmp: %s" %(pkt,)) + self.logger.info("port: %s" %(port)) + self.send_packet(datapath, port, pkt) + + def do_l2_switch(self, datapath, dpid, packet, frame, in_port, buffer_id=None): + ofproto = datapath.ofproto + parser = datapath.ofproto_parser + + if frame.dst in self.mac_to_port[dpid]: + out_port = self.mac_to_port[dpid][frame.dst] + else: + out_port = ofproto.OFPP_FLOOD + + actions = [parser.OFPActionOutput(out_port)] + + # install a flow to avoid packet_in next time + if out_port != ofproto.OFPP_FLOOD: + match = parser.OFPMatch(in_port=in_port, eth_dst=frame.dst) + # verify if we have a valid buffer_id, if yes avoid to send both + # flow_mod & packet_out + if buffer_id != ofproto.OFP_NO_BUFFER: + self.add_flow(datapath, 1, match, actions, buffer_id) + return + else: + self.add_flow(datapath, 1, match, actions) + data = None + if buffer_id == ofproto.OFP_NO_BUFFER: + data = packet.data + + out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id, + in_port=in_port, actions=actions, data=data) + datapath.send_msg(out) + + @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) + def _packet_in_handler(self, ev): + # If you hit this you might want to increase + # the "miss_send_length" of your switch + 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 + self.mac_to_port.setdefault(dpid, {}) + self.ip_to_mac.setdefault(dpid, {}) + + + self.logger.info("packet in dpid: %s, src: %s, dest: %s, in_port: %s", dpid, src, dst, in_port) + + #learn mac to port mapping + if src not in self.mac_to_port[dpid]: + self.mac_to_port[dpid][src] = in_port + + if eth.ethertype == ether_types.ETH_TYPE_ARP: + self.do_arp(datapath, pkt, eth, in_port) + return + + if eth.ethertype == ether_types.ETH_TYPE_IP: + ipv4_pkt = pkt.get_protocol(ipv4.ipv4) + + #check if packet is for this switch + if ipv4_pkt.dst == self.IP_ADDR: + icmp_pkt = pkt.get_protocol(icmp.icmp) + if icmp_pkt: + self.do_icmp(datapath, in_port, eth, ipv4_pkt, icmp_pkt) + else: + if ipv4_pkt.dst not in self.ip_to_mac[dpid]: + self.send_arp(datapath, 1, self.MAC_ADDR, ipv4_pkt.src, "FF:FF:FF:FF:FF:FF", ipv4_pkt.dst, ofproto.OFPP_FLOOD) + else: + dstMac = self.ip_to_mac[dpid].get(ipv4_pkt.dst) + pkt.get_protocols(ethernet.ethernet)[0].dst = dstMac + pkt.get_protocols(ethernet.ethernet)[0].src = self.MAC_ADDR + port = self.mac_to_port[dpid][dstMac] + #self.logger.info(port) + self.send_packet(datapath, port, pkt) + pass + + # packet is not for this switch, so do l2 switching + if dst != self.MAC_ADDR: + self.do_l2_switch(datapath, dpid, pkt, eth, in_port, msg.buffer_id) + return + return